Skip to content

Servidor de comandos

monkeyserna edited this page May 27, 2014 · 18 revisions

Comandos

El servidor de comandos realiza una gran parte de las funcionalidades de la Raspberry Pi. Sus tareas son:

  • Crear un servidor de WebSocket para recibir comandos y scripts desde Android.
  • Establecer una comunicación serie por USB con Arduino para enviar los distintos comandos disponibles.
  • Realizar lecturas del sonar.
  • Controlar el servo.
  • Ejecutar scripts creados en el modo de programación.
  • Indicar la ejecución de un script (proveniente del modo de programación) mediante un LED.

En el apartado Comunicaciones se detallan entre otros aspectos el funcionamiento de los WebSocket en el servidor de comandos y en la aplicación Android, y la comunicación USB tanto por parte de la Raspberry Pi como de Arduino Due.

Este capítulo pretende describir los demás comportamientos que este servidor realiza. Concretamente, se explica qué es lo que sucede cuando se recibe un mensaje, que puede ser de tres tipos:

  • Script realizado en el modo de programación gráfica.
  • Un comando que será reenviado a Arduino
  • Un comando que será ejecutado en Raspberry Pi

Ejecución de scripts Code

La programación gráfica basa en bloques traduce el script realizado por el usuario al lenguaje en el que está escrito el servidor de comandos, para que éste lo ejecute. Por tanto, cuando el usuario decide ejecutar un script realizado mediante bloques, se traduce a Python y se envía al servidor de comandos. El servidor al recibir un script invoca a la función executeScript con el mensaje recibido, que contiene la traducción a Python que será ejecutada.

def executeScript(receivedCommand):
	print "SCRIPT RECEIVED:\n",receivedCommand
	initScript()
	print "STARTING BLOCKLY SCRIPT..."
	exec(receivedCommand)
	print "...BLOCKLY SCRIPT DONE"
	destructScript()

La función muestra una serie de comandos de control y realiza 3 acciones. En primer lugar, llama a la función que inicia los elementos conectados a los pines GPIO de la Raspberry Pi (el sónar y el servo) para activar su posible uso por parte del código recibido. El código recibido se ejecuta mediante el comando exec. Una vez finalizada la ejecución se desactivan los pines GPIO, con el objetivo principal de disminuir el consumo eléctrico del robot.

La función initScript activa los pines GPIO de la Raspberry PI y configura las entradas y salidas empleadas por el sonar y el led de control y enciende el led que indica que un script realizado mediante el bloque de programación gráfica está siendo ejecutado. Además, realiza una primera lectura del sonar, ya que en ocasiones la primera lectura devuelve valores anómalos.

def initScript():
	print "INIT GPIO..."
	GPIO.setwarnings(False)
	GPIO.setmode(GPIO.BCM)	
	GPIO.setup(LEDPIN,GPIO.OUT)	
	GPIO.setup(TRIGPIN,GPIO.OUT)
	GPIO.setup(ECHOPIN,GPIO.IN)
	GPIO.output(LEDPIN, GPIO.HIGH)
	GPIO.output(TRIGPIN, GPIO.LOW)
	readSonar() #FIRST READ IS UNSTABLE
	time.sleep(0.1)
	print "...SONAR GPIO"

Por tanto, esta función activa los pines de la Raspberry Pi y configura el pin al que está conectado el led como salida y lo enciende. Con respecto a las conexiones con el sonar, establece el pin ECHOPIN como entrada y TRIGPIN como salida. A continuación se realiza una primera lectura del sonar, cuya primera lectura es poco fiable.

Cuando el script finaliza su ejecución, se procede a apagar el led indicador, y a desactivar los pines GPIO.

def destructScript():	
	GPIO.output(LEDPIN, GPIO.LOW)
	GPIO.cleanup()	

Funciones auxiliares

Para proporcionalidad funcionalidad a los bloques propios se emplean una serie de funciones auxiliares que hacen posible la ejecución de acciones como la lectura del sonar, la posición del servo o las transmisiones con Arduino.

En el siguiente ejemplo se muestra la traducción a Python de un bloque gráfico:

Como se puede observar, para la traducción se emplean tanto funciones nativas de Python (como la función time.sleep) como propias (sendToArduino y readSonar).

Las traducciones a Python de los bloques gráficos tienen disponibles 5 funciones auxiliares.

Función Descripción
readSonar Devuelva la lectura del sonar en centímetros.
moveServo Establece la posición del servo.
sendToArduino Envía un comando a Arduino.
receiveFromArduino Envía un comando a Arduino y recibe un valor de vuelta. Esta función devuelve el valor recibido.
map Realiza un mapeado de un valor X desde [in_min,in_max] hasta [out_min,out_max].

La funciones descritas en la table anterior tienen un enlace a la descripción de su implementación, que proporciona un mayor nivel de detalle acerca de su funcionamiento e implementación.

Ejecución de comandos

Además de scripts realizados en el bloque de programación gráfica, el servidor de comandos se encarga de recibir y controlar otros dos tipos de mensajes: Comandos Raspberry Pi y Comandos Arduino.

Comandos Raspberry Pi

Si el mensaje recibido es de 2 bytes se trata de un comando que debe ejecutar la Raspberry Pi. Este tipo de mensaje únicamente ocurre cuando el usuario desplaza la barra de control del servo en el modo de control Drive. Por tanto, únicamente existe un comando de este tipo, que se encarga de establecer la posición del servo.

	def handleMessage(self):
		#...
		elif len(msg) == 2:
			p1 = struct.unpack('B', msg[1])[0] * 10
			moveServo(p1)
		#...

Por tanto, lo que el servidor realiza cuando recibe este tipo de comando es convertir el valor al rango que especifica el servo y emplear la función moveServo, que también es empleada por los scripts realizados en el modo de programación gráfica.

Comandos Arduino

La comunicación con Arduino puede ocurrir en dos casos:

  • El modo Drive envía un mensaje WebSocket de 3 bytes.
  • La ejecución de un script escrito en el modo Code utiliza la función sendToArduio o receiveFromArduino.

Los comandos que Arduino recibe tienen siempre una longitud de 3 bytes. Estos comandos son transmitidos como mensajes de 3 bytes de longitud, donde el primer byte se corresponde con el valor del comando en el rango [0,16]. Los otros 2 bytes están reservados a posibles parámetros.

Los comandos implementados en Arduino son 17 y están numerados del 0 al 16, donde:

  • Los 11 primeros están relacionados con el movimiento de los motores (comandos 0 al 10).
  • El comando 11 está destinado al zumbador
  • El comando 12 al encendido y apagado de los leds
  • Los 4 últimos (13 al 16) realizan distintas lecturas de los sensores infrarrojos CNY70.

A continuación se detalla la función Arduino asociada a cada comando, así como una breve explicación de su funcionalidad. Para obtener más información acerca de un comando en concreto, las funciones que a continuación se describen tienen un enlace a la descripción de su implementación.

CMD Función Descripción
0 stopMotors() Detiene el movimiento de los motores.
1 moveBalanced(speed,balance) Mueve los motores hacia adelante. El primer parámetro que recibe indica la velocidad, y el segundo el balance (0 se corresponde con un giro brusco a la izquierda, 123 avanza hacia adelante y 255 gira bruscamente a la derecha).
2 setLeftSpeed(speed) Establece la velocidad del motor izquierdo.
3 setRightSpeed(speed) Establece la velocidad del motor derecho.
4 moveForwards(speed) Establece la velocidad de ambos motores.<
5 turnLeft(speed) Establece la velocidad del motor izquierdo y detiene el derecho.
6 turnRight(speed) Establece la velocidad del motor derecho y detiene el izquierdo.
7 moveBackBalanced(speed,balance) Mueve los motores hacia atrás con velocidad y balance.
8 moveBackBoth(speed) Establece la velocidad de movimiento hacia atrás de ambos motores.
9 moveBackLeft(speed) Establece la velocidad de movimiento hacia atrás del motor izquierdo.
10 moveBackRight(speed) Establece la velocidad de movimiento hacia atrás del motor derecho.
11 beep(state) Establece el estado (encendido = 1, apagado = 0) del zumbador.
12 led(numLed, state) Enciende (state = 1) o apaga (state = 0) el led numLed (entre 0 y 13).
13 sendFrontAndMiddle() Lee todos los sensores infrarrojos y los envía los valores por USB.
14 sendFront() Lee los sensores frontales en binario (negro = 1, blanco = 0) y envía los valores por USB.
15 sendMiddle() Lee los sensores centrales en binario (negro = 1, blanco = 0) y envía los valores por USB.
16 sendAnalogFront() Lee los sensores frontales en analógico y envía los valores por USB.
Clone this wiki locally