La guía definitiva para

Construcción de
Robots con J ava










Scott Preston

SOBRE EL AUTOR
Scott Preston trabaja como arquitecto J ava en Columbus, Ohio, donde reside
con su esposa, Emily, y el perro, Castle. Scott tiene más de 20 años de
programador software y experiencia eléctrica, incluyendo posiciones con la
Marina de los EE.UU., el Banco Uno, CompuServe, UUNET, Inc. y
Covansys, además de dirigir su propia compania de robótica, Preston Research
LLC. Scott también da conferencias sobre robótica en COSI (Centro de
Ciencia e Industria) y manufacturas pequeños robotscon J ava llamados
CubeBots ®. Scott es un miembro de la Comunidad J ava Comunidad de
procesos y un ex alumno de la Universidad Estatal de Ohio.


Sobre el Revisor Técnico

SIMON RITTER es un evangelista de la tecnología Java de Sun Microsystems.
Simon ha estado en el negocio de TI desde 1984 y cuenta con una
licenciatura en ciencias en física de la Universidad de Brunel enel Reino
Unido. Originalmente trabajando en el área de desarrollo de UNIX de AT & T
UNIX System Labs y Novell, Simon se trasladó a Sun en 1996. En ese
momento, comenzó a trabajar con la tecnología Java y desde entonces ha
dividido su tiempo entre el desarrollo de la tecnología Java y consultoría. Él
ahora se especializa en tecnologías emergentes, como la computación grid,
RFID, robótica y redes de sensores inteligentes. Simón y sus rendimiento con
motor Java robots LEGO han comparecido ante audiencias de todo el mundo.

Agradecimientos

Me gustaría dar las gracias especialmente a mi querida esposa, Emily, por aguantarme a mí
mientras escribía este libro y por todas las horas que pasé en el PC y abajo con los robots
cuando podría haber estado pasando con ella. En segundo lugar, me gustaría dar las gracias
a Steve Anglin, Ritter Simon, Marchant Sofía, McGee Michael, y Stence Katie por
ayudarme a escribir este libro, y para los lectores y otros en Apress que ha sido un placer
trabajar con ella. En tercer lugar, me gustaría dar las gracias a Ken Gracey de Parallax, Inc.,
y J im Frye de Lynxmotion, Inc., por el suministro hacia mi con varias partes, componentes
y asesoramiento durante la escritura de este libro. En cuarto lugar, me gustaría dar las
gracias a mi madre para transmitir su sentido común y comprarme un Atari 400 en 1980, y
mi padre por la transmisión de su ingenio y de ingeniería para ayudar a construir el original
Feynman en 2002. En quinto lugar, me gustaría dar las gracias a mi familia política, y
Frikkie Roets Karen, por su hospitalidad última Navidad (y siempre), y para el uso de su
cargo para contactar Apress de escribir este libro. En sexto lugar, me gustaría agradecer a
mi profesor de secundaria la ciencia, J an Greissinger, por inspirarme a amar la ciencia tanto
como lo hacemos hoy, y también Guy Kawasaki por sus libros y los e-mails, que me
inspiró a escribir este libro. Por último, no podría terminar sin mencionar a mis amigos
Harry y Crissy, Ron y Sofía, Marcos y María, Bard y Ann, Mark y Tracy, y J ohn y Kristi.
Me quiere pasar más tiempo con usted este verano, e incluso salir a visitar a los que están
un poco más que un coche. Planee que en 2006.


Introducción

Notas sobre el estilo
Admito que era un programador de robots antes de empezar la construcción. Así que mi perspectiva
puede ser un poco sesgada en la dirección de un programador. Sin embargo, yo tampoco quería que
este libro sea, desde una perspectiva puramente de ingeniería de software. Quería mantener el texto
equilibrado entre la robótica y la programación y no demasiado lindo con cualquier disciplina,
aunque de vez en cuando, me temo que podría haberme consentido.
¿Quién debe leer este libro?
Si desea off-the-shelf componentes del robot, software libre y herramientas de desarrollo, este es el
libro para usted. Puede descargar todo el software es GPL (General Public License) o Apache
License, y usted puede comprar los componentes de su proveedor robot favorito y / o tienda de
hobby. En las secciones siguientes se describen la experiencia que debe tener que sacar el máximo
provecho del libro.
Su Programación / J ava Experiencia
Yo podría decir que usted debe tener un buen conocimiento de técnicas orientadas a objetos y J ava
antes de empezar con este libro, pero si eres como la mayoría de los expertos en robótica, es
probable que aprender sobre la marcha, y siguiendo los diversos ejemplos I 'hemos incluido en estas
páginas. Por supuesto, si usted no tiene experiencia en J ava, sin duda, va a experimentar una curva
de aprendizaje antes de que las cosas comienzan a hacer clic. Si usted comienza a perderse debido
al vocabulario o la complejidad de los ejemplos, sólo comprar uno de los libros a partir de J ava
desde Apress. Son excelentes. Si las cosas siguen sin tener sentido, envíame un e-mail o visitar mi
sitio web y publicar una pregunta.
Su experiencia en la construcción del robot
Para aquellos recoger este libro, esperemos que sea un robot constructor intermedio ya, estar
familiarizado con los conceptos de microcontroladores, controladores de servos, controles
electrónicos de velocidad y sensores, y bien han construido un robot desde cero o desde un kit. Se lo
recomiendo a pocos robots de Lynxmotion, Inc., o si usted quiere construir uno desde cero, echar un
vistazo a algunos de los libros escritos por Apress David Cook.




¿Cómo está estructurado este manual?

He estructurado este libro como si estuviera sentado a construir un robot J ava. Empiezo por la
revisión de los conceptos básicos de la comunicación, y luego discutir cómo conseguir que el robot
se mueva, oír, ver y navegar, antes de explorar cómo optimizar el código y crear accesos directos.
He dividido cada capítulo en subtemas que el progreso de fácil a difícil. Cada sub-tema incluye lo
siguiente:
• Una introducción al tema
• Una discusión detallada del ejemplo de código
• Un código de ejemplo que demuestra el tema
• Una sección o capítulo resumen, si es necesario
Lo que necesita
Aunque se puede usar este libro con bastante eficacia sin que cada elemento con nombre en el
cuadro siguiente, los elementos obligatorios y opcionales que se muestran le ayudará a facilitar los
ejemplos en este libro. También ofrezco una lista de lo que necesita en la introducción de cada
capítulo.
Tabla 1 Ejemplos necesarios para los ejemplos del Libro
REQUISITO OPCIONAL
Java 1.4 SDK DLink DBT-120 u otro adaptador Bluetooth
Java API (comm, avanzado de imagenes, etc) EB500 Bluetooth Transceiver from Parallax
Parallax Javelin or Basic Stamp Pan and Tilt Camera Kit from Lynxmotion
Mini SSC Controladores Servo Lynxmotion SSC-32 Servo controller
Parallax Junta de Educación (BOE) u otro
board
Lynxmotion Extreme Hexapod 2
Cámara Web
Tarjeta de Audio y micrófono
Pequeño robot movil
Miselaneos (sonar, infrarrojo, etc)

Plataforma y versión de Notes
He desarrollado este libro y sus ejemplos con el Sun Java Standard Edition 1.4.2 SDK, utilizando el
Eclipse IDE 3.02 se ejecuta en Microsoft Windows XP. Sin embargo, si usted no tiene un sistema
operativo de Microsoft, usted puede fácilmente trasladar los ejemplos de este libro para Linux,
Macintosh, o cualquier sistema operativo ejecutando una J VM.
Puede descargar la última versión del SDK de http://java.sun.com/j2se/1.4. / download.html y la
última versión de Eclipse en www.eclipse.org / downloads / index.php. Mientras que usted puede
utilizar J 2SE 5.0 o Eclipse 3.1, ambos no estaban listos en el momento de escribir este libro, por lo
que los programas no se han probado con esas versiones.
Ruta del Libro
Los capítulos de este libro se desarrollan unos sobre otros, con el objetivo principal es la
navegación de robots, que abordamos en el capítulo 7. Sin embargo, usted realmente puede ampliar
la capacidad de su robot mediante el uso del habla como se analiza en el capítulo 5, o mediante el
uso de algunos de los puntos tratados en el Capítulo 9. Me baso en los temas de todos los capítulos
anteriores en el capítulo 9, al mismo tiempo que la introducción de algunos programas divertidos y
de gran alcance. Vea la figura 1.

Figura 1 Mapa del Libro





Actualizaciones y Software
Constantemente estaremos actualizando mi sitio en www.scottsbots.com / definitiveguide. Por favor
pase a visitar, descargar el código fuente nueva y ejemplos, y obtener enlaces a recursos de Internet.
También he incluido una sección especial para los robots de compra o partes necesarias para este
libro.

CAPÍTULO 1
EL PRINCIPIO


"Todo debe hacerse lo más simple posible, pero no más sencillo".
-Albert Einstein

1. INTRODUCCIÓN
Antes de empezar a programar su robot con J ava, debe tener en cuenta algunas cosas que
harán la experiencia con su robot J ava mucho más agradable. Estos incluyen los siguientes:

• Un equipo configurado para uso personal y distintos programas informáticos *
• Un enlace serie
• Un microcontrolador
• Un robot

Nota: Asegúrese de que su PC tenga la conexión a Internet más rápida, que con frecuencia se
refieren a los enlaces de Internet para descarga o de referencia.

Para empezar, voy a caminar a través de una configuración similar a la mía. Perdóname los que no
son usuarios de Windows, todas las capturas de pantalla corresponden a Windows XP. Cuando se
presente la ocasión, voy a hablar de una forma alternativa de conseguir lo mismo con un sistema
operativo basado en UNIX.

Configuración de la Computadora Personal

Para facilitar el uso de su computadora personal para este libro, usted debe hacer lo siguiente.
Descargue e instale J ava Standard Edition 1.4.2 de:
• http://java.sun.com/j2se/1.4.2/download.html
Descargue e instale Eclipse 3.02 de:
• http://download.eclipse.org/eclipse/downloads/index.php



Si usted tiene cualquier otro J ava Runtimes instalado en su computador, asegurese de establecer
este parche en las Preferencias de Eclipse, como se muestra en la Figura 1-1.

Ilustración1-¡Error! No hay texto con el estilo especificado en el documento.-1 Configuración del JRE THE ECLIPSE

Descargar el último código fuente de este libro en:
• www.scottsbots.com/definitiveguide
Usted puede agregar los archivos J AR de su proyecto. De esta manera usted debería ser capaz de
llamar a las clases de su propio proyecto con sus propios programas.





Configuración de Conexión Serie
Si usted no tiene un puerto serie (algunos equipos nuevos sólo vienen con conectores USB),
le recomiendo obtener un adaptador serie - USB de nueve pines, como se muestra a
continuación en la Ilustración1-2.


Ilustración 1-2Adaptador Serie - USB (GUC232A)


Configuración del Microcontrolador
Usted debe tener un microcontrolador que se pueda programar en PBASIC. He utilizado el BASIC
Stamp 2 para todos los ejemplos de este libro, ya que hace bien el trabajo. Fue mi primera
microcontrolador, y que cuesta menos.
El BASIC Stamp 2 (que se muestra en la Ilustración 1-3) funciona a 20 MHz y puede ejecutar
aproximadamente 4.000 instrucciones por segundo. Tiene 16 pines I / O, más dos pines dedicados a
comunicación serie, una para transmitir y otra para recibir.




Ilustración 1-¡Error! No hay texto con el estilo especificado en el documento.-3 El Parallax BASIC Stamp 2
Usted puede comprar uno en www.parallax.com por $ 49.
Configuración del Programador de Microcontroladores
Todos los ejemplos de este libro están en PBASIC, porque es el idioma más popular para el
microcontrolador en este momento. También puede encontrar muchos ejemplos y código de
ejemplo en Internet y en el sitio de Parallax. Al final del libro, he incluido una referencia rápida
para PBASIC, así como una versión J avelin Stamp de los ejemplos.
Puede descargar la última versión del programador en www.parallax.com.La Figura 1-4
muestra una imagen de un programa de muestra cargada en el editor del BASIC Stamp Windows.

Ilustración 1-¡Error! No hay texto con el estilo especificado en el documento.-4 El Editor de Windows de BASIC Stamp
Configuración del Robot
Si usted no tiene un robot y le gustaría uno en un kit, varios especímenes finos se pueden encontrar
en www.lynxmotion.com, www.parallax.com o www.prestonresearch.com. Para la mayoría de los
ejemplos de este libro, se utilizó una unidad diferencial robot o CubeBot (como se muestra en la
Figura 1-5).

Ilustración 1-¡Error! No hay texto con el estilo especificado en el documento.-5 El CubeBot
Resumen
Esperemos que tengas todo lo que necesitas para empezar. Ahora voy a empezar por explicar el
proceso de pensamiento detrás de programación de robótica (en otras palabras, obtener su robot
para hacer algunas cosas).
Entonces voy a hablar de algunos conceptos en J ava que se deben tener en cuenta antes de
embarcarse en un proyecto de robótica. Por último, te voy a mostrar un ejemplo de cómo comenzar
a modelar su software de una manera que es a la vez fácil de usar y eficaz.
1.1 Organizando su Comportamiento
Que hace tu robot? Esta es la primera pregunta que se hacen las personas cuando tienen un robot.
Mi respuesta hace cinco años sería algo así como: "Se mueve alrededor de una habitación y evita
los muebles." Entonces la gente diría "Oh ...", y yo después les hablará sobre la tecnología o el
software, algo que nunca atrajo su atención.
Por lo tanto, yo quería algo más para que haga mi robot, además de estas cosas básicas. Yo quería
hacer algo que fuera genial, algo así como una tarea de usuario simple, algo que pudiera decirle a la
gente y no conseguir miradas en blanco a cambio. Por lo tanto, tomé la tarea de conseguir una
bebida de la nevera.
Pensé que el paso a la nevera no sería tan difícil, pero cuando empecé a compilar una lista de tareas
y, a continuación subtareas, y luego los pasos detallados, me di cuenta de que era mejor empezar
por organizar mis pensamientos en torno a lo que quería del programa (ver Figura 1-6). ¡Cómo los
organizo (mis pensamientos), esto requiere una pequeña explicación, así que aquí está la definición
de esos términos:
• Eventos: Estas son las cosas que hacen que un robot haga algo. Escuchar una palabra, ver
algo, o conseguir una solicitud de la red, o una tarea programada, o algo por el estilo.
• Tareas: Estas son las cosas que desencadenan los acontecimientos. Así que si el robot
recibe una solicitud para moverse a algún lugar, la tarea de nivel superior sería moverse. La
tarea de moverse tendría entonces que llamar a una subtarea u otra tarea de ayudar.
• Las subtareas: Estas son las cosas que ayudan a la tarea. Por lo tanto, si la tarea consiste en
pasar de una posición A a una Posición B, un robot debe saber qué dirección está mirando o
consecuencia volverse hacia esa dirección. Las subtareas pueden llamar a otras subtareas o
enviar o recibir paquetes de datos a partir de los subsistemas del robot.
• Los paquetes de datos: Son el último nivel de granularidad en nuestra organización de
tareas. Un paquete de datos envía la información a un controlador de comando que controla
el motor del robot, o sensores, cuyo único propósito es obtener y recibir datos de los
subsistemas del robot o periféricos.

Ilustración 1-¡Error! No hay texto con el estilo especificado en el documento.-6 Un modelo de comportamiento de los
eventos, tareas, subtareas, mientras que los paquetes de datos.


Person 1 =Persona 1
Event: Speak =Evento: Hablar
Task: Move =Tarea: Moverse
SubTask: Change Heading Subtarea =Cambio de Rumbo
SubTask: Rotate Left =Subtarea =Giro hacia la Izquierda
Data Packet: Byte[ ] =Paquete de Datos: Byte[ ]
En la Tabla 1-1, que se muestra a continuación, he enumerado algunos ejemplos de cada uno.
Tabla 1-¡Error! No hay texto con el estilo especificado en el documento.-1 Ejemplo de eventos, tareas, subtareas y
paquetes de datos
EVENTO TAREA SUBTAREA PAQUETE DE
DATOS
Comando Verbal Diagnostico Cambio de rumbo RGB Secuencia de
imágenes
Visión (movimiento) Movimiento Calcular la posición
inicial
Byte[] Salida Serial
Visión (detección de
puntos de referencia)
Siga Objeto Calcular ruta más
corta
Byte[] Entrada Serial
Comando de Control
Remoto
Determinar la
ubicación del objeto
Crear el vector de
movimiento
Sin
Batería Baja Calcular la
transformada de
Hough
Sintaxis de voz en los
altavoces
Evento Programado Dormir

Podría haber aún más tareas o subtareas. La cantidad a añadir dependerá del ruido en su entorno.
Una vez que usted es capaz de llegar a la tarea y subtarea que define lo que usted quiere hacer con
su robot, ya está listo para empezar a manejar algunos de los problemas técnicos relacionados con la
robótica, como el movimiento y la percepción.
Movimiento
¿Cómo hacer que tu robot se mueva dependerá de las respuestas a las siguientes preguntas:
•¿Cuánto dinero tienes para gastar?
•¿Qué tan rápido quieres que tu robot se mueva?
•¿Qué superficie tendrá su robot para seguir adelante?
•¿Cuál será el peso de tu robot?
•¿Cuánto tiempo durará la fuente de alimentación al final?
Digamos que usted tiene un presupuesto de $ 200, usted no desea que su robot se mueva
especialmente rápida, se moverá en concreto o alguna otra superficie lisa, pesará cerca de 150 libras
y la necesidad de seguir con vida cerca de dos horas antes de volver a cargarla. Si este es el caso,
sus opciones son limitadas. Si cambiamos el terreno a desierto o el presupuesto aumenta a $ 2.000,
la lista de posibles soluciones técnicas cambiará drásticamente. Sin embargo, sólo tener un sistema
de accionamiento no va a permitir que usted pueda lograr el objetivo principal de conseguir un
robot para ir a la nevera. Para ello, el robot tendrá que percibir.
Percepción
Para ilustrar lo que el mundo de la percepción del robot es, voy a pedirte que hagas algunos
experimentos.
Usted realmente tendrá que hacer estos experimentos para entender completamente el problema.
Para empezar, vaya a la sala de estar y cierre los ojos. Mantén las manos delante de ti y trata de
llegar a la cocina para que te encuentres frente al refrigerador. Sí cuando te golpees contra algo, eso
está bien, es su sensor bache. Por lo tanto, has una copia de seguridad, sigue la pared, o hay lo que
hay que hacer para navegar hasta que esté delante de la nevera y en un lugar donde se puede
levantar el brazo y abrir la puerta.
Ahora usted se engaña en este ejemplo porque se sabe a qué dirección se enfrentaba cuando
comenzó. Así que ir de nuevo a la sala de estar, gira alrededor de una decena de veces (no caen
hacia abajo) y luego repetir este experimento.
Uy, se estaban engañando de nuevo ya que tenía un mapa de la habitación de la memoria y que
sabía dónde estaban empezando. Así que ahora tengo a alguien que girar, o que le lleve a una nueva
habitación, y luego repetir el experimento.
Empieza a comprender la dificultad? Tal vez usted podría ser capaz de hacerlo mejor si tuviera una
brújula o alguien que le diga la dirección a la que se enfrenta. Usted puede hacerlo mejor si lleva la
cuenta de la cantidad de pasos que tomó y que sabía hasta qué punto era cada paso.
El objetivo de este experimento es que después de varios intentos de llegar a la nevera con los
sensores que se pueden adquirir para el robot, vas a entender lo difícil que es la percepción del
robot.
Navegación
Desde el último experimento usted sabe lo difícil que es con un cerebro humano moverse en un
entorno simple, incluso cuando se tiene un mapa, una serie de sensores y una buena memoria.
Sin embargo, si alguna vez ha llegado tarde a una cita o se ha perdido en el camino hacia una nueva
dirección, ya sabe que a veces incluso la vista y el cerebro de una no es suficiente, porque hay
tantos obstáculos imprevistos o la información con la que usted tiene que trabajar no es "perfecto".
Actualmente uno de los santos griales de la robótica y la inteligencia artificial es la navegación
consistente y precisa. Uno pensaría que esto sería más fácil con un GPS y complejos sistemas de
navegación militar, sin embargo, sigue siendo un objetivo difícil de alcanzar y el gobierno de
EE.UU. está dispuesto a pagar dos millones de dólares para el primer grupo que viene con un
vehículo que puede navegar a través del desierto 175 millas en un plazo de 12 horas. Puede
encontrar más información de este desafío en www.darpa.mil/grandchallenge/.
1.2 Conceptos J ava
J ava es un lenguaje de programación orientado a objetos desarrollado por Sun Microsystems en
1991. En esta sección, voy a describir algunos conceptos importantes que verá en este libro que no
sea evidente para un principiante (véase la Tabla 1-2).
Tabla 1-¡Error! No hay texto con el estilo especificado en el documento.-2 Conceptos Importantes de Java
CONCEPTO DESCRIPCIÓN
Eventos Usualmente se realiza para las interfaces
gráficas de usuario, los eventos son formas de
enviar una clase de notificación de un cambio
de estado. Por ejemplo, cuando recibe datos en
un puerto serial, se lanzará un evento,
informando a la clase que hay datos en un búfer
que debe ser leído.
Interfaces Voy a mantener el uso de interfaces simples.
Van a definir las pautas de comportamiento de
las clases similares.
Super Clases Voy a crear superclases para todas las clases
que tienen un "tipo de" relación. Por ejemplo,
un sello Parallax, un Edwards Scott, y un servo
controlador MiniSSC-II son los tipos de
controladores que se comunican con un puerto
serie. Me gustaría crear un super clase para
manejar los tipos comunes de funcionalidad.
Delegado de Clase Un delegado es una clase que comparte algunas
funciones comunes, pero no comparte "un tipo
de" relación. Por ejemplo, un controlador no es
un tipo de sensor, pero puede haber una
funcionalidad común que quiero añadir a los
dos. Entonces sería crear una clase de delegado
para controlar la funcionalidad de manera
similar para ambas clases.
Clase Proxy Esta es una clase que tiene la funcionalidad de
muchas clases o componentes que se combinan
para actuar como una sola clase. Me gustaría
utilizar dos tipos de clases de proxy: un servidor
proxy físico que representa un dispositivo
robótico como un sensor y un proxy abstracta
que representa una conducta como la
navegación.
Servidor Un programa de J ava que no va a interactuar
con un usuario de línea de comandos de la
interfaz.
Cliente Un programa Java que va a interactuar con una
interfaz de usuario o la línea de comandos y un
servidor.
Hilos Si quieres hacer más de una cosa a la vez, debe
utilizar varios subprocesos.
Hilo de Seguridad de Acceso Concurrente Digamos que usted tiene múltiples hilos que
intentan acceder a un único puerto serie de un
PC. Usted necesita encontrar una manera de
limitar el acceso de un modo seguro para
subprocesos para que no creen condiciones de
interbloqueo.

Haciendo una Pausa en Nuestro Programa
Yo estaba en una conferencia cuando escuché una charla sobre las máquinas de estado y pensé que
sería una buena manera de introducir temporización y sincronización. Una máquina de estados es
un modelo compuesto por tres cosas: estados, transiciones y acciones. Para ilustrar un ejemplo de
una máquina de estados, voy a utilizar un bolígrafo retráctil. Es una máquina de estados muy
simple. La pluma es bien extendida y esta lista para escribir, o es retirada por lo que puede poner en
el bolsillo. Para cambiar su estado, se hace clic en su parte superior, o se la retuerce si es una pluma
de lujo.
Vamos a definir algunos términos tales como: un estado es un poco de información sobre el
modelo. Una transición es un indicador de un cambio en el estado causado por alguna acción. La
máquina de estado simple que se muestra en la Ilustración 1-7 , aquí muestra cómo se extrae
típicamente. Comenzando en el círculo superior (llamado el estado inicial) de la punta de la pluma
está retraída. Haga clic en la parte superior de la pluma y está en un estado nuevo, ampliado y listo
para escribir, que ahora está representado por el círculo inferior. Haga clic de nuevo, y ya está en su
estado original. Bastante simple, ¿no?

Ilustración 1-¡Error! No hay texto con el estilo especificado en el documento.-7 Una Simple Máquina de Estados
Así que cuando usted tiene un conjunto de subtareas que se deben efectuar para obtener movimiento
de su robot, usted debe tener un diagrama de estados que indique las transiciones de su robot de un
estado o subtarea a otro estado o subtarea.
Sin embargo, hacer esto mediante programación en J ava con robots es un poco más difícil de tratar
con la teoría o la imagen que acabamos de discutir, pero la idea de una máquina de estados le ayuda
en la organización de lo que usted quiere que su robot haga, cómo quiere que su robot lo haga, y lo
más importante: cuando usted quiere que su robot lo haga. Por último, para que su programa pase a
la transición correctamente, cuando esté listo tendrá que ser capaz de "pausa" de su programa para
permitir que estos nuevos estados a materializarse.
Para poner en pausa el programa con J ava, utilice las siguientes cuatro formas definidas en la Tabla
1-3.
Tabla 1-¡Error! No hay texto con el estilo especificado en el documento.-3 Pasos para Pausar un Programa en Java
Método Pause Descripción
Thread_Sleep(ms) / Hilo de Sueno(ms) Este es un método estático y le hará al hilo
actual de J ava dormir durante un cierto número
de milisegundos. Tenga en cuenta que esto se
hará en todos los programas J ava que utilizan
este hilo para dormir, así que si usted está
haciendo varias cosas como la espera de un
acontecimiento de serie y control de una lectura
de puerto paralelo, tendrá que crear un nuevo
hilo.
Timer Task / Tiempo de Temporizado Otra forma de obtener algo nuevo que se
produce en un intervalo determinado es crear
una tarea de temporizador que se produce en un
momento fijo en milisegundos desde el
momento en que fue invocado.
Loop Until Finished / Bucle hasta que
termine
Si usted no sabe cuánto tiempo tardará algo en
completarse, pero no quiere hacer nada hasta
que esté terminado, usted puede poner un
programa en un bucle. Asegúrese de insertar
una Thread.sleep (1), en el circuito de modo que
su PC no tenga el 100 por ciento de utilización
de la CPU mientras espera. Se podría evitar lo
que está esperando (como una captura de
imagen, comandos de voz, etc) de conseguir
ciclos suficientes para hacer cualquier cosa.
Wait() and notify() / Espera y notifica Si dispone de dos hilos cooperantes, un hilo
para un puerto serie y otro leyendo una imagen
de la webcam se puede utilizar el wait () en el
puerto serie y luego notificar () en la clase
webcam. El método wait () hará que el hilo
actual del puerto serial espere hasta que el hilo
que invoca a la cámara web notify () o notify ()
método.

Ahora que hemos terminado con algunos de los conceptos importantes en J ava y sabemos cómo
detener nuestros programas, nuestro último paso es organizar nuestro hardware de una manera que
hace que modelar nuestra conducta sea fácil.
1.3 Organizando nuestro Hardware
Los PC y microcontroladores tienen su lugar en la robótica. Cada uno es bueno en algunas cosas y
pobres en otros, pero con tanto usted obtiene más de lo que sería el uso de cada uno por separado.
Los microcontroladores son muy buenos para comunicarse con los pequeños aparatos electrónicos.
Así que si tienes sensores, servos, o controladores de motor, se debe utilizar un microcontrolador
para esto. Por lo general, tienen muchos puertos de E / S, en cualquier lugar 8 a 40 pines
dependiendo del tipo de microcontrolador que se utiliza, donde los PC se limitan a sus puertos de
comunicación. Usted descubrirá más adelante cómo se puede utilizar un puerto paralelo de la PC
para hacer algo básico digital de E / S, pero cuando empiece a hacer por ancho de pulso (PWM) con
un puerto paralelo de la PC, usted se encontrará corriendo a limitaciones.
Las PCs son muy buenas en el control de las decisiones, el almacenamiento de datos, la
interconexión con la gente, y el uso de multimedia. Aunque hay algunos ficheros por ahí que
pueden hacer la síntesis de voz, y que las cámaras están disponibles para que puedan manejar un
poco de color básico y reconocimiento de objetos, verás que tienen una capacidad limitada.
Además, la capacidad del microcontrolador para interactuar con la gente, almacenar datos y tomar
decisiones puede dejar mucho que desear.
Organizando nuestros Componentes
Lo primero que hice fue el modelo de las conexiones físicas entre mi PC y mi robot. Me encontré
con que tiene tres capas simplificado la agrupación. Se puede elegir otro arreglo para su robot, pero
esto es lo que funcionó para mí. Un esquema de la disposición en capas se muestran en la Tabla 1-4.
Tabla 1-¡Error! No hay texto con el estilo especificado en el documento.-4 Capas en Programación Robótica
CAPA DE PC CAPA DE CONTROL CAPA DE DISPOSITIVO
Esta es la capa con la que están
más familiarizados. El plan
incluirá las interfaces a los
periféricos como el puerto
serial, puerto paralelo,
webcam, salida de sonido o
dispositivos de entrada, etc
Esta capa representa los
controladores de otros
fabricantes. Estos
controladores le permiten
comunicarse en la lengua de un
robot y el lenguaje de un
ordenador.
Esta es la capa que representa
los dispositivos de hardware
que se ha conectado.
Puerto Serial
Cámara Web
Tarjeta de Audio
Base de Datos
Parallax Stamp
Controlador Servo MiniSSC II
Microcontrolador
Brazo Robot
Sonar
Pierna Robot
Brújula

Modelando el Hardware y el Comportamiento
Una vez que se organiza los componentes que tienen que trabajar, es el momento de crear unas
"suaves" componentes de hardware.
•Escoja un nombre (por ejemplo, PanTiltCamera).
•Modele lo que usted quisiera que hiciera (mover arriba / abajo, mover hacia la izquierda / derecha,
tomar una foto, y así sucesivamente).
•Apague su clase.
•Planee lo que puede salir mal y cómo quiere tratar con ese problema.
Después de haber modelado el hardware y el comportamiento, usted debe estar listo para el cálculo
de la sincronización entre los dos.
Sincronización
La sincronización en la vida es importante; la sincronización en robótica es obligatoria. Si usted
tiene un microcontrolador más grande, se recomienda usar control de flujo (por ejemplo, tener su
PC y el microcontrolador negociando cuando cada uno esté listo para hablar). Pero ya que sólo tiene
16 puertos E / S con mi BASIC Stamp 2, voy a sincronizar manualmente la comunicación serial.
Usted debe ser consciente de cómo las cosas toman sin embargo mucho tiempo
Por ejemplo, una velocidad de comunicación de 9600 baudios con su microcontrolador tarda unos 3
pies por carácter. Si tiene tres caracteres para transmitir, como el porte de su brújula, podría tomar
menos tiempo para ejecutar la orden de lo que costaría recuperar los datos de su conexión en serie.
Pero el tiempo no es sólo importante para la sincronización. También define la resolución a la que
el robot puede obtener datos de su entorno. Por ejemplo, si usted tiene un sensor que lee un sonar
cada 200 milisegundos, entonces usted tiene un número máximo de 5 lecturas por segundo.
Si el robot se desplaza 1 metro por segundo (un ritmo de marcha lenta), la resolución de su robot
será de 7 pulgadas.
Resumen
A estas alturas, usted debe estar listo para empezar a usar J ava con la robótica. Su PC debe tener
instalado el software y usted debe tener una conexión serial y el microcontrolador. Mientras que no
se necesita un robot para el siguiente capítulo, asegúrese de hacer un poco para que esté listo para el
Capítulo 3, se puede conectar el robot y ponerlo en marcha con algunos de sus propios programas
J ava.
Esperemos que sus programas hagan algo más que evitar el sofá o se mueven en círculos. Así que
tome un poco de tiempo para averiguar lo que usted quiere que su robot realice. Luego, para que sea
más fácil seguir estos pasos: En primer lugar, debe organizar lo que usted quiere que su robot
realice. En segundo lugar, elegir los eventos que determinan la intervención.
En tercer lugar, crear tareas que organizan el comportamiento. En cuarto lugar, crear subtareas que
realizan los detalles.
Finalmente, el modelo de paquetes de datos que representan la información puedan moverse de su
hardware y PC.
También podría ayudar a organizar sus programas crear un diagrama de transición de estados como
la Ilustración 1-2 que se muestra anteriormente de tal manera que se haga fácil cuando se pasa de
subtarea a subtarea o tarea a tarea. Yo no me preocuparía demasiado por los conceptos de J ava en
este momento, pero cuando sea de volver a ellas si te quedas atascado en algún momento más
adelante en el libro. Lo que no se encuentra listado aquí se pueden descubrir en los numerosos
libros Apress que hacen un excelente trabajo explicando estos conceptos.
Por último, una vez que su modelo de comportamiento se define, se debe empezar a modelar su
hardware. Así que a partir de su PC y mover asus periféricos, si es necesario crear modelos simples
del hardware que se asignan fácilmente a la conducta que usted desea que su robot realice. Por
ejemplo, si quiero que mi robot se mueva, me gustaría asignar un puerto serie a un controlador
servo y eso sería todo. Pero si quiero que se enfrentan a una dirección específica, me gustaría tener
un puerto serial asignado a un controlador servo, así como un microcontrolador, que se asigna a una
brújula. Sólo un consejo antes de continuar: comenzar con algo simple, y luego aumentar la
complejidad de su modelo sólo después de haber probado una versión simple de la misma. Usted se
encontrará con muchos problemas en el camino y no hay nada peor que la solución que repetir todo
el código.
CAPÍTULO II

Comunicación Serial

"El problema con la comunicación es la ilusión de que se ha logrado."
--George Bernand Shaw

2.0 Introducción
En este libro, todas las comunicaciones que se utilizan con el microcontrolador son comunicaciones
RS-232 serie a 9600 baudios, ocho bits de datos, un bit de parada y sin control de flujo. Hay otros
métodos de comunicación con los microcontroladores, especialmente I2C (Inter-Integrated
Communication), comunicaciones paralelas, Ethernet, WiFi y Bluetooth sólo para nombrar unos
pocos. Pero he optado por utilizar comunicaciones serie por su popularidad y su extensibilidad con
otro software y dispositivos.
Voy a mostrar y describir las 12 clases de J ava y los programas de BASIC Stamp 2. Todas las
clases están en el paquete com.scottpreston.javarobot.chapter2. Todos los programas sellados se
encuentran en la carpeta / BasicStamp/chapter2.
En este capítulo, voy a presentarles a la API J ava Communications, explicando algunas de sus
clases más importantes, y luego probar su uso de algunos programas sencillos. Más tarde, voy a
simplificar su uso con la robótica y ampliar las comunicaciones serie a través de una red utilizando
J ava Server Pages y un cliente web.
Una vez que he discutido y simplificado las comunicaciones en serie, voy a modelar un programa
de microcontrolador en una clase J ava. Modelando el programa del microcontrolador en J ava, se
debe simplificar la programación de su robot.
El capítulo concluye con un ejemplo que utiliza un adaptador Bluetooth de serie en combinación
con un BASIC Stamp para demostrar comunicaciones serie inalámbricos.
Configuración del Puerto Serie
Una vez más, vamos a configurar el puerto serie a lo siguiente: 9600 baudios, ocho bits de datos,
sin paridad, un bit de parada y sin control de flujo. Para configurar esto para Windows, abra el
Panel de control, seleccione Sistema ➤Hardware ➤ Administrador de dispositivos y, a
continuación, haga clic en Puertos. Asegúrese de anotar el número de puerto (COMx).
Usted puede ver las ventanas de estos en las figuras 2-1 y 2-2 se muestran a continuación.
• Nota: Los usuarios de UNIX, los puertos están numerados de esta forma ttyS0, ttyS1, y así
sucesivamente. Sustituir todas las referencias de COMx a ttySx.

Ilustración 2-1 Ventana de Administrador de Dispositivos

Ilustración 2-2 Ventana de Propiedades de Comunicación de Puertos



El API de Comunicaciones J ava
Voy a utilizar las siguientes clases de la API J ava Communications para acceso al puerto.
Tabla 2-1 Clases Importantes del API de Java Communications
CLASES JAVA DESCRIPCIÓN
javax.comm.CommPortIdentifer Esta es la clase principal para controlar el
acceso a los puertos de comunicaciones.
Proporciona una lista de los puertos de
comunicación puestos a disposición por el
conductor, asiste a la apertura de los puertos de
comunicaciones, y ayuda con la propiedad del
puerto.
javax.comm.SerialPort Este es el estándar RS-232 del Puerto de
comunicaciones provisto por el comm.jar. Por
la documentación de J ava, esta clase define la
funcionalidad mínima necesaria para
puertos de comunicaciones serie.

Objetivos del Código
El objetivo de este ejemplo es la lista de todos los puertos de comunicación disponibles.
• Sugerencia: Hacer que el primer programa se ejecuta, ya que pondrá a prueba la instalación
de la API J ava Communications.
Discusión del Código
Los campos de esta clase son ComPortIdentifer, portId y una enumeración de todos los puertos
llamados portsList. A continuación, voy a crear un constructor vacío donde puedo inicializar la
enumeración de los puertos. Esta será la lista de todos los puertos identificados por el conductor.
El segundo método en la clase es el método list (). La primera línea en el método es un bucle while
que itera a través de la enumeración de los puertos. Al llegar al siguiente elemento de la
enumeración, recibe el portType (serie o paralelo), y luego imprime el nombre del puerto.
Tras la salida del nombre de la consola, voy a hacer un intento de abrir el puerto, hacer una pausa de
250 milisegundos, a continuación, cerrar el puerto. Esto se repite hasta que la enumeración no tiene
más elementos.
Esta clase lanza dos tipos de excepciones. LA primera es el InterruptedException, producida por el
Thread.sleep() método estático, mientras que el PortInUseException producida por el método
portId.open (). (Véase el Ejemplo 2-1.)


Ejemplo 2-¡Error! No hay texto con el estilo especificado en el documento.-1 ListOpenPorts.java
Para las clases posteriores, será útil no usar el método Thread.sleep(), pero en vez de añadir un solo
método estático que se puede llamar, y que se encarga de la InterruptedException. Para ello, voy a
crear una clase de Utilidades para almacenar estos métodos de utilidad estáticos. (Véase el Ejemplo
2-2.)

Ejemplo 2-¡Error! No hay texto con el estilo especificado en el documento.-2 El método Utils.pause()
Resumen de la sección
Todas las comunicaciones que se utilizan en este libro con el microcontrolador empleará
comunicación serie RS-232 a 9600 baudios, ocho bits de datos, un bit de parada y sin control de
flujo. Una vez que se ha configurado en su PC mediante una combinación de clases y
CommPortIdentifier SerialPort de la API J ava Communications para la comunicación serial, usted
debería ser capaz de obtener el acceso que permiten la lectura y escritura desde y hacia el puerto
serial de su PC con J ava.
Las clases que he creado en esta sección fueron:
•ListOpenPorts.java: Esta clase muestra cómo iterar a través de la enumeración prevista por la clase
CommPortIdentifier del J ava API para seleccionar un puerto serie.
•Utils.pause (): Esta clase va a ser sólo una clase de utilidad que en la actualidad cuenta con una
método pausa que hará que el subproceso actual entre a dormir y atrapar su excepción. Mientras que
usted puede utilizar la API directamente, he encontrado más útil escribir una clase contenedora que
simplifica el acceso. Esto es lo que voy a hablar en la próxima sección.
2.1 Un puerto serial simple
En la clase ListOpenPorts, hemos sido capaces de acceder y abrir los puertos serie, pero el uso de
esta técnica presenta tres problemas. En primer lugar, es complicado de crear y utilizar el puerto
serie iterando a través de todos los que están disponibles, y luego, cuando el que está disponible
coincide con la que usted desea, usted puede utilizarlo. En segundo lugar, utilizando los flujos de
entrada y flujos de salida desde el puerto serial es difícil si usted desea enviar y recibir paquetes de
datos tal como se define en el Capítulo 1.En tercer lugar, el uso de este puerto no es lo
suficientemente genérico.
Objetivos del Código
Para compensar estas deficiencias voy a crear lo siguiente:
• Una interfaz de puerto serie para que pueda crear varias clases de serie implantación del
puerto, pero no tendrá que modificar el código a través de la interfaz.
• Un constructor sencillo para que pueda especificar un puerto serie con transmisión e
identificador.
• Métodos que funcionan bien para enviar y recibir paquetes de datos hacia y desde el
microcontrolador.
Discusión del Código
El primer elemento a crear es una interfaz de puerto serie. La interfaz J ava es un medio para ocultar
diferentes implementaciones con el mismo comportamiento. Por ahora voy a crear el acceso al
puerto serie a un puerto local, pero más tarde quiero dar el mismo comportamiento en la red. Lo
primero que se nota desde la interfaz es que no contiene ninguna lógica, sólo apéndices de método.
Esto se debe a que una sola interfaz está allí para definir el comportamiento, para no poner en
práctica cualquiera de la conducta. El trabajo real se llevará a cabo por otra clase que implementa
esta interfaz.
La segunda cosa que usted nota son los nombres de los métodos. Por ejemplo, el método read ()
devuelve una matriz de bytes. El método readString() devuelve un String. El método de escritura no
devolverá nada y tendrá una matriz de bytes, ya que es sólo un parámetro de entrada. También hay
un método close() para liberar recursos y volver a enviar la propiedad para que otras clases o
programas pueden tener acceso al objeto de aplicación.
He añadido dos métodos de descriptor de acceso de puerto serie: setDTR para su uso con las placas
portadoras de sellos Parallax, y setTimeout como un medio de ayuda en la sincronización de los
paquetes de datos con el microcontrolador conectado.
Las tres cadenas estáticas son para uso con el WebSerialClient que se definen más adelante en este
capítulo. El read() y readString() tienen métodos con parámetros de entrada porque (según el valor
de tiempo de espera), a veces es mejor esperar a la respuesta de la clase de puerto serie en lugar de
llamar al Thread.sleep() externamente y luego llamar a dos métodos separados write() y read().
(Véase el Ejemplo 2-3.)

Ejemplo 2-3 JSerialPort.java
Ahora que he creado la interfaz genérica para todos los puertos serie que voy a utilizar en este libro,
es el momento de escribir nuestra primera clase de implementación, StandardSerialPort. La
Ilustración 2-3 muestra el diagrama de clases para J SerialPort y StandardSerialPort.

Ilustración 2-3 Diagrama de clases de JSerialPort y StandardSerialPort
Para empezar vamos a ver las variables de nivel de clase. La lista de puertos están enumerados en
una lista que se obtiene de los puertos por parte del conductor. El ComPortIdentifier, portId, es el
puerto real que estamos interesados en trabajar, mientras que SerialPort es la java.comm.SerialPort
real que vamos a utilizar para leer y escribir paquetes de datos con nuestro microcontrolador.
InputStream y OutputStream, con los nombres de variables con el mismo nombre, son las corrientes
de trabajo para regresar de nuestra SerialPort.
El byte[] readBuffer será un búfer temporal utilizado durante la lectura de corriente de nuestro
puerto serial de entrada. La Boolean, DATAIN, es un indicador que permite marcar la clase esté
sabe cuánto tiempo toma para leer la secuencia de entrada en el readBuffer. Finalmente, las dos
últimas variables currentWrite e i se utilizan en conjunción con lectura-escritura del
comportamiento implementado en el WebSerialClient.
Pasando a los constructores de clase, he creado dos constructores para esta clase que simplifican la
creación de parámetros de entrada a los baudios justos e id. Porque yo sólo estoy comprobando para
ver si el puerto termina con un número específico (por ejemplo, 1,2,3, ..., n), esta clase va a
funcionar ya sea con Windows o UNIX basados en puertos serie. En el caso de que la transmisión
no se ha establecido, me decidí por una tasa de morosidad de 9600. Cada constructor también llama
a un método init común. Dentro de este método se encuentra el Ejemplo 2-1 con la misma lógica
utilizada en el, ListOpenPorts. Una vez que se crea una enumeración, yo itero a través de esta
enumeración hasta que encuentre a los puertos serie (en concreto, el que termina con el int se pasa
como un parámetro de entrada). Luego habrá una instancia con nombre de este puerto y establecer
los parámetros por defecto que son de ocho bits de datos, un bit de parada, sin paridad y sin control
de flujo. A continuación, establezca el flujo de entrada y flujo de salida del puerto para ser igual a
dos variables de clase del mismo nombre, seguido de la adición del detector de eventos y una
bandera notifyOnDataAvailable.
• Nota: Los dos métodos de pausa tienen que esperar al controlador para ajustar los valores
de los puertos. He encontrado en mi máquina de Windows XP que si no me detengo un
poco, los conductores a veces se vuelven excepciones. Puede eliminar estos en el equipo si
lo desea, sólo asegúrese de hacer hincapié en ellos al tratar de probar muchos aperturas y
cierres de puerto en un bucle.
A continuación, voy a hablar de las clases de implementación de la interfaz J SerialPort. (Véase el
Ejemplo 2-4.) el método read () es realmente un método que duerme hasta que el buffer de entrada
está vacío. Una vez vacío, se devuelve el contenido de la readBuffer. El método readString()
simplemente llama al método read() y luego convierte los bytes en una lista delimitada por la tilde
como un String. Dado que todos los datos que vienen del microcontrolador serán un flujo de bytes,
quería una manera de leer bytes individuales sin tener que preocuparse de ellos pero se transformó
en un caracter que no puede ser fácilmente convertido de nuevo a un int.
El método write() es un paso a través de la secuencia de salida con la excepción de añadir el
contenido a la currentWrite byte []. Guardo esto porque quiero pasar por alto si el microcontrolador
hace eco de nuevo al momento de leer la secuencia de entrada.
El método close() cierra el SerialPort.
Los otros dos métodos read() y readString () con parámetros de entrada- no se utilizan pero que una
vez más no porque la interfaz jSerialPort los requiere.
El único que me importa es el evento DATA_AVAILABLE. Cuando este evento se dispara, voy a
iniciar una serie de 32 bytes, a continuación, mientras que la inputStream está disponible, voy a leer
el flujo de entrada en el readBuffer. Luego realizar alguna lógica para asegurarse de que los datos
devueltos no sean igual a los datos que se envían, y si ese es el caso, me ponga el DATAIN
booleana en true. De los últimos tres métodos, setTimeout() no se utiliza, y setDTR() y getName()
están ahí para proporcionar un acceso limitado a sus variables SerialPort correspondientes.
Un ejemplo de secuencia de eventos de una típica escritura / pausa / lectura acción sería la
siguiente:
1. byte [] se escribe en un puerto serie.
2. El microcontrolador lee byte [].
3. El programa externo llama a pausa (x).
4. El tiempo pasa.
5. El tiempo se acabó.
6. El microcontrolador retorna byte [].
7. La norma DATA_AVAILABLE el evento del puerto serial está activado.
8. El programa externo llama a read().
9. Todos los datos se leen; DATAIN se establece en true.
10. El read() retorna el byte [] de datos de microcontrolador.
Ejemplo 2-4 StandardSerialPort.java
package com.scottpreston.javarobot.chapter2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
public class StandardSerialPort implements SerialPortEventListener,
J SerialPort {
private Enumeration portList;
private CommPortIdentifier portId;
private SerialPort serialPort;
private OutputStream outputStream;
private InputStream inputStream;
private byte[] readBuffer;
private boolean dataIn =false;
private byte[] currentWrite;
private int i =0;
public StandardSerialPort(int id) throws Exception {
init(id, 9600);
}
public StandardSerialPort(int id, int baud) throws Exception {
init(id, baud);
}
private void init(int comID, int baud) {
String comIdAsString =new Integer(comID).toString();
try {
portList =CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
portId =(CommPortIdentifier) portList.nextElement();
if (portId.getPortType() ==CommPortIdentifier.PORT_SERIAL) {
if (portId.getName().endsWith(comIdAsString)) {
// Creando el Puerto Serie
serialPort =(SerialPort) portId.open(
"StandardSerialPort", 3000);
// Estableciendo los parámetros de Configuración
serialPort.setSerialPortParams(baud,
SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort
.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
Utils.pause(50);
// Configurando la corriente de Salida
outputStream =serialPort.getOutputStream();
// Configurando la Corriente de Entrada
inputStream =serialPort.getInputStream();
// Agregando Detector de Eventos
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
Thread.sleep(50); // waits till ports change state.
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] read() {
while (!dataIn) {
try {
Thread.sleep(1);
} catch (Exception e) {
}
}
dataIn =false;
return readBuffer;
}
public String readString() {
byte[] b =read();
StringBuffer s =new StringBuffer();
for (int i =0; i <b.length; i++) {
if (b[i] !=0) {
int in =(int) b[i];
if (in <0) {
in =in +256;
}
s.append(in);
s.append("~");
}
}
s.deleteCharAt(s.length() - 1);
return s.toString();
}
public void write(byte[] b) throws Exception {
currentWrite =b;
outputStream.write(b);
}
public void close() {
serialPort.close();
}
public byte[] read(byte[] b) throws Exception {
// No Usado
return null;
}
public String readString(byte[] b) throws Exception {
// No Usado
return null;
}
public void serialEvent(SerialPortEvent event) {
if (event.getEventType() ==SerialPortEvent.DATA_AVAILABLE) {
readBuffer =new byte[32];
i =0;
try {
while (inputStream.available() >0) {
int numBytes =inputStream.read(readBuffer);
}
int byteCount =0;
for (int i =0; i <currentWrite.length; i++) {
if (currentWrite[i] ==readBuffer[i]) {
byteCount++;
}
}
if (byteCount !=currentWrite.length) {
dataIn =true;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void setTimeout(int timeout) {
// No Usado
}
public void setDTR(boolean dtr) {
serialPort.setDTR(dtr);
}
public String getName() {
return serialPort.getName();
}
}
Resumen de la Sección
Para esta sección, he creado un simple uso del puerto serial. Hice esto mediante la simplificación de
la construcción del puerto para tomar solo los parámetros del identificador de puerto serie (1,2,3, ...,
n) y una velocidad de transmisión como un int. En segundo lugar, he modificado los flujos de
entrada y salida para tomar parámetros y devolver datos útiles para la robótica: byte [] y cuerdas.
Por último, creé una interfaz para el puerto serie llamado el J SerialPort, que puede ser utilizado en
las secciones posteriores para forzar el mismo comportamiento para varias implementaciones del
puerto serie.
La interfaz y las clases que he creado en esta sección fueron:
• J SerialPort.java: Esta es la interfaz que va a especificar el comportamiento de todos los
puertos serie.
• StandardSerialPort.java: esta clase es la versión más simple de la SerialPort J ava API.
La única cosa que el StandardSerialPort no hace es manejar el uso simultáneo del puerto serie. Ese
será el tema de la siguiente sección.
2.2 Uso Simultáneo Del Puerto Serie
Si conectamos más de una cosa a un puerto serie, se encontrará con muchos PortInUseExceptions.
Queremos evitar esto, de lo contrario nuestros programas estarán saliendo cuando no queremos que
lo hagan. (Ver Tabla 2-2.)
Tabla 2-2 Pro y Contra del Uso Simultáneo
SOLUCIÓN PRO CONTRA
Cree el puerto serial en el
interior de cada objeto
dependiente.
Cada clase es independiente. El uso concurrente de;
throwPortInUseException más,
la aplicación lo hará. Eierre del
puerto serial se tiene que hacer
a través de llamada a un
método para invocar objeto.
Crear puerto serie fuera de
los objetos de consumo.
El uso concurrente limita a
subproceso actual. Cierre del
puerto serial se puede hacer
fuera de los objetos
individuales.
Cada clase requiere SerialPort
que se enviará en el
constructor. No es seguro para
subprocesos.
Crear una clase única que
tiene el control de todas las
acciones necesarias de puerto
serie.
Auto-contenida. Ejecución de
subprocesos. Clausura del
puerto gestionado dentro de la
clase.
Pobre reutilización
Utilice un singleton de puerto
serie en el interior de cada
objeto dependiente.
La clase es autónoma. El uso
concurrente se limita a J VM y
se rosca safe.Closing de los
objetos se realiza fuera de los
objetos individuales.
Limitado a un solo puerto
serial independientemente de
ID COM.
Utilice un producto único de
los puertos serie dentro de un
grupo de recursos de todos
los puertos serie disponibles.
La clase es autónoma. El uso
concurrente se limita a J VM y
es seguro para subprocesos. El
cierre de los objetos se puede
hacer fuera de los objetos
individuales. Puede solicitar
cualquier sistema disponible
que puede encontrar el puerto
serie.
Ninguno

Objetivo del Código
El objetivo de este ejemplo es mostrar cómo crear un fondo de recursos de los puertos serie sin
tener conflictos si varios objetos desea acceder a ellos a la vez.
Discusión de Código
El único campo en la clase SingleSerialPort es un vector: portsInUse. Este vector es una
recopilación de los Serialports actualmente inicializados. Debido a que un vector se sincroniza, esto
asegura que los puertos son accesibles de una manera segura para los subprocesos. He creado un
constructor privado para evitar la inicialización. Todos los StandardSerialPorts serán devueltos a
través de los getInstanceMethods. El método getInstance utiliza el nombre de la SerialPort (COM1
o stty1) para identificarse y, o bien crear uno nuevo o volver al puerto fuente. Por último, el método
close() elimina los puertos de la piscina y los cierra. (Ver Ejemplo 2-5.)
Ejemplo 2-5 SingleSerialPort.java
package com.scottpreston.javarobot.chapter2;
import java.util.Vector;
private static Vector portsInUse =new Vector();
private SingleSerialPort() {
// Inicializando Preventos
}

public static StandardSerialPort getInstance(int comid) throws Exception {
return getInstance(comid,9600);
}
public static StandardSerialPort getInstance(int comid, int baud)
throws Exception {
StandardSerialPort instance =null;
String tmpComID =new Integer(comid).toString();
// Regresa a un puerto si existe y si esta en uso.
for (int i=0; i<portsInUse.size(); i++) {
StandardSerialPort aPort =(StandardSerialPort)portsInUse.get(i);
if (aPort.getName().endsWith(tmpComID)) {
return aPort;
}
}
// otherwise create the port if its in the list
if (instance ==null) {
instance =new StandardSerialPort(comid,baud);
portsInUse.add(instance);
}
return instance;
}
public static void close(int comid) {
String tmpComID =new Integer(comid).toString();
// return a port in use if it exist.
for (int i=0; i<portsInUse.size(); i++) {
StandardSerialPort aPort =(StandardSerialPort)portsInUse.get(i);
if (aPort.getName().endsWith(tmpComID)) {
aPort.close();
portsInUse.remove(i);
}
}
}
public static void closeAll() {
// Ciclo de todo y cierre
for (int i=0; i<portsInUse.size(); i++) {
StandardSerialPort aPort =(StandardSerialPort)portsInUse.get(i);
aPort.close();
portsInUse.remove(i);
}
}
}
Resumen de la sección
En esta sección, se discuten y comparan cinco formas diferentes de manejar la concurrencia en el
puerto serie. Mediante la colocación de un puerto serie en un grupo de recursos que es thread-safe,
me aseguro de que el puerto serie se puede acceder de manera sincronizada y nunca voy a conseguir
un PortInUseException al acceder al puerto serie al programar mi robot.
La clase que fue creada en esta sección fue:
• SingleSerialPort.java: Esta clase muestra cómo crear un fondo de recursos de los puertos
serie que facilitan el acceso concurrente de varios subprocesos.
2.3 Creación de un puerto serie Web
He descubierto que trabajar con el puerto serial en mi PC de escritorio está muy bien, pero tan
pronto como empiezo a depurar el código con mi robot, me parece que trabajar en un equipo remoto
a través de Servicios de Terminal Server es mucho más lento. Por lo tanto, necesito otra opción.
Quiero trabajar desde el IDE de Eclipse en mi PC de escritorio, pero también quiero hacer la
comunicación serial con un microcontrolador conectado al puerto serie de mi robot. Yo también
quiero una manera fácil de probar esto de forma remota y no quiero escribir software para el manejo
de múltiples conexiones o la gestión de paquetes de datos de secuencias o imágenes que puedan ir y
venir entre la PC de escritorio y el robot. Para solucionar estos problemas, voy a crear un puerto
serial web. Este es un puerto serial que puede acceder a través de Internet, enviar comandos,
obtener datos y, a continuación, utilizar sucesivamente los clientes web para hacer el control remoto
para el diagnóstico.
• Nota: más sobre la configuración de Tomcat se puede encontrar en el Capítulo 8: Temas
avanzados.
Configuración
La configuración siguiente representa mi PC con mi J ava IDE (Eclipse). Tengo una conexión
inalámbrica con el motor de servlets Tomcat que se ejecuta en el ordenador de mi robot. (Ver
Ilustración 2-4).

Ilustración 2-4 Configuración Inalámbrica de WebSerialPort
Objetivo del Código
El objetivo clave es ampliar el puerto serie para que pueda conectarse a ella a través de la conexión
inalámbrica de mi casa a través de HTTP.
Discusión del Código
El ejemplo siguiente será utilizado en un J ava Server Page que reside en el servidor web. La cadena,
CMD_ACK, será de reconocer la cadena devuelta desde el webcom.jsp si todo va según lo previsto
y que no hay errores. La cadena, COMM_J SP, es el nombre de la J SP que toman la entrada y salida
de solicitud desde el cliente.
Las variables READ_ONLY y DEFAULT_TIMEOUT se utilizan para calcular mejor si el cliente
debe esperar a que el servidor web responda con salida desde el puerto serie o hacer una solicitud
por separado para la salida.
Debido a que Tomcat es un servidor web multiproceso, cualquier par de llamadas de un navegador
web o cliente Web que podría suceder en diferentes hilos. Esto no es un efecto deseado, por lo que
para evitar la PortInUseException voy a utilizar el SingleSerialPort.getIntance() en el constructor de
la WebSerialPort.
El único otro método público de esta clase es execute(), que toma los parámetros y acciones que
corresponden a leer, escribir, leer o escribir. La cadena, cmds, será una cadena delimitada por
comas de bytes, mientras que la cadena, tiempo de espera, le dirá a la clase que debe esperar por el
resultado. En este método, también se producen excepciones si alguno de los elementos
constructores son nulos. Los otros métodos que se llama dependen de la acción. El private read()
devuelve el valor de com.readString (). Esta será una lista delimitada de números. El método write()
convierte la cadena delimitada por comas de un byte [] y lo envía al flujo de salida del puerto serie.
Finalmente, el método read() con parámetros de entrada llamará al método write(), y espera un
tiempo, y luego llamar al método read(). (Véase la Ilustración 2-6.).
Ejemplo 2-6 WebSerialPort.java
package com.scottpreston.javarobot.chapter2;
public class WebSerialPort{
J SerialPort com;
public static final String CMD_ACK ="ok";
public static final String COMM_J SP ="webcom.jsp";
public static final byte[] READ_ONLY =new byte[] { (byte) 0 };
public static final int DEFAULT_TIMEOUT =0;
private int timeout;
public WebSerialPort(String comId) throws Exception {
int pId =new Integer(comId).intValue();
com =SingleSerialPort.getInstance(pId);
}
public String execute(String action, String cmds, String timeout,String dtr) ➥
throws Exception{
if (action ==null) {
throw new Exception("Action is null");
}
if (cmds ==null) {
throw new Exception("Commands are null");
}
if (timeout ==null) {
throw new Exception("Timeout is null");
}
if (dtr ==null) {
throw new Exception("DTR is null");
}
int tOut =new Integer(timeout).intValue();
this.timeout =tOut;
//if (tOut !=0) {
// com.setTimeout(tOut);
//}
if (dtr.equalsIgnoreCase("true")) {
com.setDTR(true);
}
if (dtr.equalsIgnoreCase("false")) {
com.setDTR(false);
}
if (action.equalsIgnoreCase(J SerialPort.READ_COMMAND)) {
return read();
} else if (action.equalsIgnoreCase(J SerialPort.WRITE_READ_COMMAND)) {
return read(cmds);
} else if (action.equalsIgnoreCase(J SerialPort.WRITE_COMMAND)) {
return write(cmds);
} else {
return null;
}
}
/**
*
* @param cmd
* this will be comma delimited seq of cmds
*/
private String write(String cmd) throws Exception {
com.write(urlCmdsToBytes(cmd));
return CMD_ACK;
}
private String read(String cmd) throws Exception {
write(cmd);
Utils.pause(timeout);
return read();
}
private String read() {
return com.readString();
}
public void close() {
com.close();
}
private byte[] urlCmdsToBytes(String command) {
String[] commands =command.split(",");
byte[] cmds =new byte[commands.length];
for (int x =0; x <commands.length; x++) {
int i =new Integer(commands[x]).intValue();
cmds[x] =(byte) i;
}
return cmds;
}
}
La siguiente parte de nuestra amplicación del puerto serie para la web es webcom.jsp. Este J SP
importa las clases del Capítulo 2, y luego analiza los parámetros en la URL, luego realiza el envío
de esas cadenas al constructor de la clase anterior, WebSerialPort. Debido a que el constructor lanza
una excepción, voy a envolver el constructor y ejecutar métodos en un bloque try-catch con un
ejemplo de cómo utilizar la J SP. Fuera de la construcción, e invocando el método de ejecución, toda
la funcionalidad y la lógica para el webcom.jsp se encuentra en la clase WebSerialPort. (Véase el
Ejemplo 2-7.)
Ejemplo 2-7 webcom.jsp
<%@ page import="com.scottpreston.javarobot.chapter2.*" %><%
// WebClient class will throw exception if these are not set
String portId =request.getParameter("portid");
String action =request.getParameter("action");
String cmdInput =request.getParameter("commands");
String timeout =request.getParameter("timeout");
String dtr =request.getParameter("dtr");
try {
WebSerialPort com =new WebSerialPort(portId);
out.println(com.execute(action,cmdInput,timeout,dtr));
} catch (Exception e) {
out.println(e);
int term ='!';
%>
usage: /webcom.jsp?portid=[1,2,..]&action=[r,w,wr]➥
&commands=[100,120,222,..]&timeout=[0,50,..]&dtr=true
<p>sample:
<a href="/webcom.jsp?portid=1&action=wr&commands=100,<%=term%>➥
&timeout=0&dtr=true">sample 1</a>
<% }%>

Si no te diste cuenta, el WebSerialPort no implementa la interfaz J SerialPort. ¿Por qué es eso?, por
dos razones. Uno, que no necesitaba ya que el comportamiento es ligeramente diferente que el
puerto serie estándar, y dos, todas nuestras clases de aplicación no volvería a usar este puerto En su
lugar, tendrá que utilizar el conector a la WebSerialPort: el WebSerialClient. La clase
WebSerialClient implementa la interfaz J SerialPort, por lo que ahora cualquier cosa que escribo
sólo puede utilizar esta interfaz y puedo intercambiar el WebSerialClient, el StandardSerialPort, o
mi propia aplicación y no voy a tener que modificar nada del código que los utiliza. bastante
mancha, ¿eh?
El primer campo de esta clase es un objeto formateador. Yo lo uso para la depuración de los
milisegundos de una operación. Usted tendrá que depurar y experimentar con diferentes valores de
tiempo de espera para los elementos conectado al microcontrolador. Demasiado tiempo y usted
estará perdiendo rendimiento, demasiado pequeño y obtendrá nada a cambio o sólo basura. Voy a
hablar más de esto en el capítulo 4, pero es probablemente mejor tomar nota de ello por ahora. La
dirección URL de cadena y el objeto URL se utiliza para conectar con el webcom.jsp en mi robot.
La variable DTR está establecido en false si me estoy conectando a una tarjeta portadora BASIC
Stamp. El tiempo de espera y max_delay son enteros que van a determinar si el cliente debe esperar
un retorno de webcom.jsp, o si sólo debe hacer dos llamadas: una escritura y una lectura. He
encontrado que dependiendo de su conexión Wi-Fi, es posible que desee aumentar o disminuir este
valor. A continuación, la construcción de este cliente tendrá en el servidor de cadena que representa
el servidor nombre o la dirección IP del servidor web que aloja el webcom.jsp. La cadena, tcpport,
representa el puerto donde el servidor web que aloja el webcom.jsp está escuchando. (Véase el
Ejemplo 2-8.)
Ejemplo 2-8 WebSerialClient.java
package com.scottpreston.javarobot.chapter2;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
public class WebSerialClient implements J SerialPort {
private SimpleDateFormat formatter =new SimpleDateFormat(
"MM/dd/yy - HH:mm:ss.SSS");
private String url;
private URL myUrl;
private boolean dtr =false;
private int timeout =0;
public static final int MAX_DELAY =500;
public WebSerialClient(String server, String tcpPort, String portId) {
this.url ="http://" +server +":" +tcpPort
+"/" +WebSerialPort.COMM_J SP +"?portid=" +portId;
}
public byte[] read() {
return readString().getBytes();
}
public String readString() {
return request(WebSerialPort.READ_ONLY, J SerialPort.READ_COMMAND);
}
public void write(byte[] b) throws Exception {
String out =request(b, J SerialPort.WRITE_COMMAND);
if (out.equalsIgnoreCase(WebSerialPort.CMD_ACK) ==false) {
throw new Exception("WebClient Write Failure: " +out);
}
}
// añadido en caso de que usuario desea leer después de enviar comandos
// Esto es específico para el webcom.jsp
public byte[] read(byte[] b) {
return readString(b).getBytes();
}
public String readString(byte[] b) {
return request(b, J SerialPort.WRITE_READ_COMMAND);
}
public void close() {
// no hace nada, ya que tiene más de un puerto
}
public void setDTR(boolean dtr) {
this.dtr =dtr;
}
private String request(byte[] commands, String cmdType) {
// convertir el byte a cadena
String cmdString =byteArrayToString(commands);
log("WebClient: cmds=" +cmdString +", cmdType=" +cmdType
+", timeout=" +timeout);
String out =null;
try {
String urlString =url
+"&action=" +cmdType
+"&commands=" +cmdString
+"&timeout=" +timeout
+"&dtr=" +dtr;
URL myurl =new URL(urlString);
log(urlString);
BufferedReader in =new BufferedReader(new InputStreamReader(
myurl.openStream()));
String str =null;
while ((str =in.readLine()) !=null) {
// str es una línea de texto; readLine () elimina el salto de línea
if (str !=null) {
out =str;
}
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
out =out.trim();
log("WebClient: out=" +out);
return out;
}
private String byteArrayToString(byte[] b) {
String s ="";
for (int x =0; x <b.length; x++) {
s =s +b[x] +",";
}
s =s.substring(0, s.length() - 1);
return s;
}
private void log(String s) {
Date d =new Date();
String dt =formatter.format(d);
System.out.println(dt +" *** " +s);
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout =timeout;
}
public static void main(String[] args) {
}
}
Resumen de la sección
Ahora debería ser capaz de conectarse al puerto serie del robot desde cualquier lugar del mundo.
Usted puede escribir sus programas en su PC y el tiempo que tiene conectividad de red al puerto
serie del robot, todos los programas se pueden ejecutar desde el PC. Las clases y J SP que se
introdujo en este apartado fueron:
•WebSerialPort: La clase que tiene acceso al puerto serie del servidor web de la J SP.
• Webcom.jsp: La página de servidor J ava que proporciona acceso desde el WebSerialPort al
WebSerialClient, o el acceso directo a través del navegador.
• WebSerialClient: La clase que implementa la interfaz J SerialPort que permite el acceso a un
puerto serie de un servidor web de la misma manera se puede acceder a un puerto serie de su
máquina local.
Dependiendo de su configuración, usted está listo para empezar a acceder a su microcontrolador a
través de su puerto serie.

2.4 Comunicaciones En Serie Con Un Microcontrolador
Una vez que haya probado y utilizado algunas de las clases de acceso a puerto serie de su PC, usted
está listo para enviar y recibir algunos datos de la misma. Para ello, conecte el cable serial de su PC
a su J unta de Educación Parallax. Se puede ver en la Ilustración 2-5 que el BOE tiene un lugar, ya
sea para el BASIC Stamp o Stamp, conectores para un cable de serie de la batería, y tel board para
su uso en la experimentación.

Ilustración 2-5 La Parallax Board
• Nota: Si estás empezando con la robótica, es genial tener este board para añadir sensores o
la creación de circuitos.
Una vez que su tarjeta está conectada y se puede ver el microcontrolador que ha conectado, usted
está listo para programar. Su primer objetivo será enviar sólo algunos datos al microcontrolador y
obtener algunos datos a cambio.
Objetivo del Código
Los objetivos de este ejemplo son los siguientes:
• Enviar 2 bytes de datos a un microcontrolador.
• Recibir una copia byte específico que confirma el byte enviado a ella.
Discusión del Código
El programa Stamp tiene una matriz de bytes de tamaño 3 llamado serialIn. Esta matriz de bytes se
rellenará desde el símbolo del SERIN cuando está llena o cuando se recibe una orden de
terminación de "!". Luego, basándose en el primer byte recibido desde el PC, el programa saltará a
SEROUT con una "a" o "b". (Véase el Ejemplo 2-9.)
• Nota: Ajustar el tiempo de espera del puerto serie o el tiempo entre la escritura y la demora.
A continuación, ajuste el tiempo de pausa en el código Stamp y ver cómo varían los
resultados.
Ejemplo 2-9 StampSerialTest.java
'{$STAMP BS2}
'{$PORT COM1}
serialIn VAR Byte(3)
foo VAR Byte
main:
foo =255
serialIn(0) =0
serialIn(1) =0
serialIn(2) =0
SERIN 16,16468,1000,main,[STR serialIn###BOT_TEXT###quot;!"]
PAUSE 100
LOOKDOWN serialIn(0),[100,101,102],foo
BRANCH foo,[test1, test2, getCompass]
PAUSE 5
GOTO main
test1:
SEROUT 16,16468,["a"]
GOTO main
test2:
SEROUT 16,16468,["b"]
GOTO main
getCompass:
SEROUT 16,16468,["180"]
GOTO main

Resumen de la sección
El programa Stamp y la clase J ava creado en esta sección son:
•SerialEcho.bs2: Este programa se encuentra en el microcontrolador y se hacen eco de una "a" y
"b" en función de los comandos enviados al controlador.
•StampSerialTest.java: Esta clase está diseñada para enviar y recibir información específica para el
microcontrolador en coordinación con SerialEcho.bs2.
Una vez que han probado el acceso básico a su microcontrolador, ahora es el momento de extender
en este concepto un poco además del modelo de su microcontrolador, primero mediante la creación
de uno genérico que puede ser utilizado para cualquier tipo de microcontrolador, a continuación,
mediante la creación de una versión que corresponde precisamente a su programa de Stamp.


2.5 Modelado de un microcontrolador con J ava
Mientras que podría utilizar la StandardSerialPort para enviar y recibir datos hacia y desde un robot,
esto hace que sea más difícil en el futuro a medida que aumenta la capacidad del robot. Así que,
para empezar se necesita un microcontrolador. Elijo el BASIC Stamp de Parallax, porque es fácil de
programar y hay un montón de ejemplos y apoyo disponible para este modelo.
El primer Stamp Parallax BASIC viene en nueve versiones diferentes, sin incluir las versiones
OEM. Vienen con 8, 16, y 32 pines E / S que operan a partir de 4 MHz a 50 MHz y se puede
programar con hasta 12.000 instrucciones. Son muy versátiles y hay un montón de ejemplos de
software a través de Internet, así como los prestados en el sitio web del fabricante en
www.parallax.com.
Los dos se muestran en la Figura 2-6 y la Figura 2-7 son el BASIC Stamp 2 y el J avalin Stamp. El
J avelin Stamp es la versión de J ava. Usted puede encontrar todos los ejemplos de programas en este
libro para el J avalin Stamp en el Apéndice 2. Todos los otros ejemplos serán para el BASIC Stamp
2, ya que es el más popular y, como he dicho antes, hay más ejemplos de este microcontrolador en
la actualidad.

Ilustración 2-6 El Parallax BASIC Stamp

Ilustración 2-7 El Paralllax Javalin Stamp
Al utilizar los Stamp con los programas J ava, he encontrado que es tedioso para llevar a cabo el
mismo puerto serial y la gestión de byte para cada clase que tenga acceso al Stamp. Para resolver
este problema, voy a crear una clase que maneja toda la comunicación con el controlador. Pero al
igual que el puerto serie, puede que tenga diferentes implementaciones de acceso, por lo que
primero quiero crear una interfaz para todos los controladores, y luego quiero escribir una clase de
implementación específicamente para mi sello.
Objetivo del Código
El objetivo de este ejemplo es para simplificar la comunicación para mi robot mediante el modelado
de un programa de Stamp en J ava.
Discusión del Código
La primera interfaz que voy a crear se llamará J Controller. Esta interfaz tiene tres métodos
execute() y un método close(). La única diferencia entre los dos métodos Execute será el tipo de
retorno. En execute(), el tipo de cambio será una cadena. Esto llamará la readString() de la
J SerialPort. En execute2(), el tipo de retorno será un byte []. Esto llamará al método read() de la
J SerialPort. (Véase el Ejemplo 2-11.)
Ejemplo 2-11 StampSerialTest.java
package com.scottpreston.javarobot.chapter2;
public interface J Controller {
public String execute(byte[] cmd, int delay) throws Exception;
public byte[] execute2(byte[] cmd, int delay) throws Exception;
public void close();
}

A continuación, voy a escribir la implementación de la interfaz definida en el ejemplo anterior. Al
empezar a escribir clases de implementación para el J avalin Stamp, y seis versiones del BASIC
Stamp, me encontré a mí mismo repitiendo muchas de las mismas llamadas a los métodos Execute.
Así, en lugar de escribirlos en siete ocasiones, he decidido crear un controlador maestro que
implementaría la funcionalidad de todos ellos. También será capaz de manejar todos los
controladores nuevos que puedan surgir en capítulos posteriores. Voy a llamar a este controlador de
clase, y para que las clases de implementación reales se crean, voy a hacer lo genérico. Esta clase
tiene un solo campo, es de tipo SerialPort J SerialPort. El constructor de esta clase toma la interfaz
J SerialPort para que pueda utilizar el WebSerialClient o el StandardSerialPort. También establece la
DTR en false ya que ninguno de los controladores que uso va a utilizar esto, y por los consejos de
Stamp vehículo que tiene este conjunto en true pondrá el Stamp en el modo de programa. El primer
método, execute(), devolverá una cadena. Lo primero que se comprueba es la instancia de la
J SerialPort. Si se trata de tipo WebSerialClient, entonces quiero poner el retraso en el puerto serie
en el servidor web. Esto es debido a un retraso de tiempo entre la máquina y la ejecución de
conexión con el servidor web. Puse el máximo retraso en la clase WebSerialClient y si el retraso es
inferior o igual a este número, el retardo se establece en la WebSerialClient, de lo contrario, lo haré
llamar Utils.pause() y hacer dos llamadas al cliente. Además, en ambos casos, tengo que comprobar
para ver si el retraso es cero. Si ese es el caso, yo no quiero nada preparado, yo sólo quiero escribir.
(Ver Ejemplo 2-12.)
Ejemplo 2-12 Controller.java
package com.scottpreston.javarobot.chapter2;
public abstract class Controller implements J Controller {
private J SerialPort serialPort;
public Controller(J SerialPort sPort) throws Exception {
serialPort =sPort;
serialPort.setDTR(false);
}
public String execute(byte[] cmd, int delay) throws Exception {
String out =null;
if ((serialPort instanceof WebSerialClient)
&& delay <=WebSerialClient.MAX_DELAY) {
serialPort.setTimeout(delay);
if (delay ==0) {
serialPort.write(cmd);
} else {
out =serialPort.readString(cmd);
}
} else {
if (delay ==0) {
serialPort.write(cmd);
} else {
serialPort.write(cmd);
Utils.pause(delay);
out =serialPort.readString();
}
}
return out;
}
public byte[] execute2(byte[] cmd, int delay) throws Exception {
byte[] out =null;
if ((serialPort instanceof WebSerialClient)
&& delay <=WebSerialClient.MAX_DELAY) {
serialPort.setTimeout(delay);
if (delay ==0) {
serialPort.write(cmd);
} else {
out =serialPort.read(cmd);
}
} else {
if (delay ==0) {
serialPort.write(cmd);
} else {
serialPort.write(cmd);
Utils.pause(delay);
out =serialPort.read();
}
}
return out;
}
public void close() {
serialPort.close();
}
}
Para dar un ejemplo de cómo estas tres clases encajan -StandardSerialPort, J Controller y Controller
he proporcionado el diagrama de clases UML en la Figura 2-8. A principios de SimpleStamp, creo
tres constantes. Estas constantes se utilizan de dos formas. La primera es para que sea más fácil
modificar las cadenas de comandos cuando se sincroniza el programa de Stamp. En segundo lugar,
porque los comandos reales enviados a la Stamp son bytes, puedo usar estas constantes como las
órdenes reales para el byte [] envió al método write() del puerto serie. El constructor de esta clase
tendrá una instancia de una clase SerialPort del SingleSerialPort.

Ilustración 2-¡Error! No hay texto con el estilo especificado en el documento.-8 StandardSerialPort, JController,
Controller, and SimpleStamp
Los métodos comando create byte [] con los comandos especificados a través de las constantes de la
clase, y luego invocan el método execute() de la matriz con un tiempo de retardo de 150
milisegundos para cada método. (Véase el Ejemplo 2-13.)
Ejemplo 2-13 SimpleStamp.java
package com.scottpreston.javarobot.chapter2;
public class SimpleStamp extends Controller {
public static final int COMMAND_A ='d';
public static final int COMMAND_B ='e';
public static final int COMMAND_TERM ='!';
public SimpleStamp(int id) throws Exception {
super(SingleSerialPort.getInstance(id));
}
public String cmdA() throws Exception {
byte[] a =new byte[] { (byte) COMMAND_A, (byte) COMMAND_TERM };
return execute(a, 150);
}
public String cmdB() throws Exception {
byte[] b =new byte[] { (byte) COMMAND_B, (byte) COMMAND_TERM };
return execute(b, 150);
}
public static void main(String[] args) throws Exception {
SimpleStamp t =new SimpleStamp(1);
System.out.println(t.cmdA());
System.out.println(t.cmdB());
t.close();
}
}
Resumen de la sección
En esta sección, hemos creado una interfaz de controlador llamado J Controller que especifica el
comportamiento entre todos los controladores que utilizaremos en este libro. También hemos
creado una clase abstracta que lleva consigo dos métodos de aplicación para ejecutar la
comunicación. Con los dos diferentes métodos de aplicación sólo leer, execute() devolverá una
cadena, y execute2() devolverá un byte []. Una vez que el controlador genérico se crea podemos
extender esta clase para nuestras implementaciones específicas del programa del BASIC Stamp,
mientras que sólo se centra en los bytes que necesitan para enviar y el nombre del método que
queremos crear te que corresponderá a los comandos del programa de Cupones.
Las clases e interfaces creadas en esta sección son:
• J Controller.java: Esta es la interfaz que va a especificar el comportamiento de todos los
controladores.
• Controller.java: Este es en resumen una super-clase que implementa execute() y execute2()
para todos los controladores en el futuro.
• SimpleStamp.java: Esta es una clase de implementación del programa SerialEcho.bs2
presentado en la sección 2.3.
Lo único que queda por crear es hacer que la comunicación inalámbrica con la combinación de
nuestra BASIC Stamp y el dispositivo Bluetooth.
2.6 Comunicaciones Bluetooth Serie
Esto es tan fácil una vez que el dispositivo Bluetooth está configurado. Todo lo que necesitas hacer
es cambiar el ID de puerto com. He utilizado el EB500 de Parallax. Esto conecta directamente a las
tablas que tienen otros y que es un gran valor de menos de $ 100 en comparación con los
adaptadores Bluetooth de serie. Asegúrese de que utiliza el puerto COM según se especifica bajo el
puerto serie Bluetooth en la pestaña de aplicaciones de cliente. Puede encontrar las instrucciones
para configurar el microcontrolador y el adaptador EB500 en el sitio de Parallax o en el manual
bajo el título "Conexión entre un PC con DBT-120 y un BOE." Las fotos de la EB500 y DBT-120
se muestran en las figuras 2-9 y 2-10.

Ilustración 2-¡Error! No hay texto con el estilo especificado en el documento.-9 El módulo Parallax Bluetooth EB 500

Ilustración 2-¡Error! No hay texto con el estilo especificado en el documento.-10 Adaptador USB Bluetooth Inalámbrico
DLink DBT-120

Objetivos del Código

Los objetivos de este código son:

• Demostrar una conexión serie inalámbrica
• Demostrar que una conexión en serie es el mismo que una red cableada con el
software adecuado instalado en el Stamp
Discusión del Código
La tarjeta Bluetooth conectado a nuestro BOE (Board of Education) se comunicará directamente a
nuestro PC a través de una de sus conexiones en serie. Mientras que nuestro PC no notará ninguna
diferencia, hay algunos pequeños cambios que deben hacerse en el lado del Stamp. En primer lugar,
algunos comandos de inicialización necesita ser enviado a la EB500, junto con la dirección de
nuestro adaptador Bluetooth USB en el PC. Una vez conectado, nuestro programa se parece mucho
a la original, con la excepción del pasador SEROUT y SERIN el pin: pin 1 frente al pin 16. El
código J ava es el mismo código que el utilizado anteriormente en el Ejemplo 2-4. Sólo cambia el
identificador de puerto para que coincida con el adaptador Bluetooth y ya está. (Véase el Ejemplo
2-14.)
Ejemplo 2-14 BluetoothStamp.bs2
' {$STAMP BS2}
serialin VAR Byte
INPUT 5
PAUSE 1000
SEROUT 1,84, ["con 00:11:95:4F:54:39",CR]
SERIN 0,84,[WAIT("ACK",CR)]
WaitForConnection:
IF IN5 =0 THEN WaitForConnection
main:
serialIn(0) =0
SERIN 0,84,1000,main,[STR serialIn###BOT_TEXT###quot;!"]
PAUSE 100
LOOKDOWN serialIn(0),[100,101],serialIn
BRANCH serialIn,[test1, test2]
SEROUT 1,84,["none", CR]
PAUSE 5
GOTO main
test1:
SEROUT 1,84,["a"]
GOTO main
test2:
SEROUT 1,84,["b"]
GOTO main

Al copiar este código en su BASIC Stamp, para tener acceso completo de su robot ahora sin cables,
todo lo que tiene que hacer es cambiar el ID de puerto serie.
2.7 Resumen Del Capítulo
Mi objetivo en este capítulo es presentarle a la utilización de la API J ava Communications para
hablar con su microcontrolador. Esperemos que, ahora sabe un poco más de cómo hacer esto. En la
sección 2.0, he creado ListOpenPorts.java. Esta clase le enseñó a iterar a través de todos los puertos
de comunicación para llegar a los puertos serie con una identificación com específico en el nombre
del puerto. También he añadido una clase de Utilidades que me permita llamar a la función
Thread.sleep mientras se pone la excepción.
En la sección 2.1, he creado la interfaz J SerialPort y StandardSerialPort. La interfaz proporciona un
comportamiento uniforme para todos los puertos serie, incluyendo el WebSerialClient que se
discute en la sección 2.3. La clase StandardSerialPort prevé un acceso más sencillo a la API COM
para nuestro uso de la robótica.
En la sección 2.2, se creó un fondo de recursos de StandardSerialPorts para que estos puertos se
puede acceder al mismo tiempo de una manera multiproceso.
En la sección 2.3, he creado una forma de acceder al puerto serie a través de Internet con el
WebSerialPort, webcom.jsp y WebSerialClient.
En la sección 2.4, he conectado al microcontrolador Basic Stamp.
En la sección 2.5, he creado la interfaz J Controller y Contralor. La interfaz proporciona un
comportamiento estandarizado para todos los controladores y el controlador es una superclase
abstracta que proporciona funcionalidad para todos los controladores de Parallax que se utilizan en
este libro.
Por último, en la sección 2.6 te mostré un ejemplo de programa BASIC que permite el acceso
inalámbrico a Bluetooth con su microcontrolador de un puerto serie proporcionado por un
adaptador de Bluetooth.
En el siguiente capítulo, nos basaremos en la comunicación serie y modelos más componentes del
robot para conseguir que el robot se mueva. Vamos a trabajar con robots con patas, robots con
ruedas, brazos robóticos, y algunos otros tipos de controladores robóticos.






















CAPÍTULO 3


Movimiento



"Cada objeto en un estado de movimiento uniforme tiende a permanecer en ese estado de
movimiento a menos que una fuerza externa se aplica a ella."
--Primera Ley de Newton

3.0 Introducción
La fabricación para que su robot se mueva es mucho más fácil hoy en día con el advenimiento de
Controladores Servo serie (SSC) y controladores electrónicos de velocidad (ESC). Todos ellos
utilizan el mismo mecanismo para mover, un ancho de pulso (PWM) diseñado para controlar la
posición de un servo. Un servo es un pequeño motor que permite colocar la posición de su
engranaje de salida con precisión por una señal PWM. La Figura 3-1 muestra una imagen del servo
estándar, que es lo principal, he usado para las unidades diferenciales, los brazos, las piernas y los
robots.

Ilustración 3-1 Servo Standard Hitec HSS-422

En un SSC, se tienen entre 8 a 32 servos que usted puede controlar. Usted digitalmente puede
colocarlos con byte de precisión (0-255) donde 0 sería completamente en sentido horario (CW) y
255 sería completamente en sentido horario (hacia la izquierda). En un CES, los mismos intervalos
digitales (0-255) representan la velocidad de un motor de corriente continua hacia adelante o hacia
atrás. Así, en función de cómo tenga los terminales conectados, 0 podría representar toda velocidad
hacia delante, hacia atrás 255 podría ser toda velocidad, y 127 podría significar detención. Mientras
que usted puede controlar servos PWM mediante el envío de señales a través de un
microcontrolador, está limitado en el número de servos que usted puede controlar a la vez, ya que
por lo general tendrá que tomar lecturas de los sensores, tomar decisiones sobre qué camino tomar,
o qué medidas tomar a continuación , y así sucesivamente. Si usted no tiene un controlador servo,
puede escribir un programa BASIC Stamp que simulará un controlador servo, pero te recomiendo
que conseguir uno para el Capítulo 7. En el Ejemplo 3-1, el programa realizará un bucle en
intervalos de 10-milisegundos si no se recibe de la serie en (SERIN) se mueve al antiguo. Debido a
que los valores anteriores no se han sobrescrito, el programa envía los antiguos valores de pulsout
para el antiguo pin y pos. Este ejemplo sólo funciona para un pin a la vez.
Ejemplo 3-1 Servo.bs2
'{$STAMP BS2}
'{$PORT COM1}
pin VAR Byte
oldPin VAR Byte
pos VAR Byte
oldPos VAR Byte
pulse VAR Word
main:
SERIN 16,16468,old,10,[WAIT(255), pin, pos]
pulse =(pos/255)*750
pulsout pin,750+pulse
oldPin =pin
oldPos =pos
GOTO main
old:
pulse =(oldPos/255)*750
pulsout oldPin,750+pulse
GOTO main

Este capítulo contiene 21 ejemplos de clases de J ava y el ejemplo anterior BASIC Stamp. El
primero de ellos se encargará del acceso a controladores de servo, seguido de ejemplos de robots
con ruedas, los brazos robot, y robots con patas.

Ilustración 3-2 Un controlador servo y un servo con ruedas
Puede conectar el controlador servo para el puerto serie a través del conector RJ -11 (conector de
teléfono) o por el puente de la placa. No he mostrado la conexión de alimentación a los servos. Esto
debería ser 3,8 a 6,0 voltios (a veces se puede ir tan alto como 7,2 voltios para servos de alta
calidad). También hay un conector para una batería de 9 - a 12-voltios para la alimentación del
circuito del controlador.
• Nota: Consulte el Apéndice B para obtener más información sobre mas controladores.
Una vez que conecte el controlador servo al puerto serie de su PC, usted está listo para programar.
3.0 Controladores Servo
Los controladores servo simplifican en gran medida la capacidad de la PC para comunicarse con los
servos y los controles electrónicos de velocidad, al igual que un microcontrolador simplifica la
capacidad de la PC para comunicarse con los sensores.
Antes de empezar a programar en realidad nuestros controladores, me gustaría hacer una nota sobre
la sincronización. Cuando se mueve un servo a una posición entre 0 y 180 grados, hay un tiempo
mínimo que se necesita para mover el servo a esa posición. Para su servo estándar, toma 480
milisegundos para mover 180 grados. También, puesto que va a enviar esta solicitud a través de un
puerto serie, el tiempo que se tarda en enviar un comando de 3 bytes a una velocidad de 9.600
baudios tarda unos 3 milisegundos por byte, para un total de 12 milisegundos. Para ayudar con la
discusión, he incluido un diagrama de clases (ver Ilustración 3-3) de las tres clases principales, así
como sus homólogos del Capítulo 2: J SerialPort para comunicaciones serie, J Controller para la
normalización del controlador y el Controlador, que se extiende en SSC.

Ilustración 3-3 Diagrama de clases de la clases de la sección 3-1
La Ilustración 3-4 ofrece una foto de primer plano de la MiniSSC-II. Empecé a trabajar con esta
SSC hace unos años y me encanta. En la actualidad, hay controladores más poderosos, pero este era
el original y tengo tres, uno para Feynman5, uno por un brazo de robot, y uno para un repuesto.


Ilustración 3-4 Controlador Servo MiniSSC-II
Puede conectarse a él con 2400 o 9600 baudios y tiene una potencia de hasta 8 servos. Para obtener
más información detallada, por favor referirse a cualquier de las siguientes páginas
www.lynxmotion.com o www.seetron.com / ssc.htm. Asegúrese de consultar el manual para
finalizar las conexiones.
Objetivos del Código
Los objetivos de este código de ejemplo son los siguientes:
• Utilice nuestro puerto serial para controlar el posicionamiento del servo (SerialSsc.java)
• Crear una interfaz de protocolo estandarizado para el Stamp y otras implementaciones de la
clase (SSC.java).
Discusión del Código
El primer ejemplo muestra cómo se puede obtener una SSC a trabajar sólo por el uso de la
StandardSerialPort (aplicación de un J SerialPort) del último capítulo.
La clase moverá el servo completo de CW a completo CCW (0 a 255). Hice una pausa para el
servo de 100 milisegundos entre las posiciones para que podamos ver como para en cada posición.
Una vez que este ciclo se ha completado, cierro el puerto serie. (Véase el Ejemplo 3-2.)
Ejemplo 3-2 Servo.bs2
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.StandardSerialPort;
public class SerialSsc {
public static void main(String[] args) {
try {
// Crea el Puerto Serie
StandardSerialPort serialPort =new StandardSerialPort(1);
// Incrementa la posicion por 5 cada vez en el bucle.
for (int pos =0; pos <255; pos =pos +5) {
// Crea un arreglo de byte para los comandos del SSC
byte[] sscCmd =new byte[] { (byte) 255, 0, (byte) pos };
// Envia el arreglo de byte al puerto serie
serialPort.write(sscCmd);
// Pausa entre los comandos
Thread.sleep(100);
}
// Cierra el Puerto Serie
serialPort.close();
} catch (Exception e) {
// Imprime hasta encontrar la pila de salida
e.printStackTrace();
System.exit(1);
}
}
}

Mientras que la clase anterior, hace exactamente lo que yo quiero, yo pensaba que, dado todo el
trabajo en las siguientes secciones y capítulos que sería una buena idea para estandarizar la
comunicación al SSC, ya que su protocolo de comunicación es fija. Para ello, he creado la interfaz
SSCProtocol.java. Tiene un único método definido, move (pin, pos). El método tiene los siguientes
parámetros: pin-pin de la posición que el servo esté enchufado, y pos-la posición del servo de 0 a
255. También he añadido algunas constantes para simplificar clases usando este protocolo. (Véase
el Ejemplo 3-3.)
Ejemplo 3-3 SSCProtocol.java
package com.scottpreston.javarobot.chapter3;
public interface SSCProtocol {
// Máximo
public static final byte MAX =(byte) 255;
// Neutral
public static final byte NEUTRAL =(byte)127;
// Mínimo
public static final byte MIN =(byte) 0;
/**
* @param pin - connector on the MiniSSC 0-7
* @param pos - byte from 0-255
*/
public void move(int pin, int pos) throws Exception;
}

Ahora que tengo una interfaz definida para todas las comunicaciones SSC, estoy listo para crear la
clase base SSC. Al igual que Controller.java hice esta clase abstracta porque quiero escribir dos
implementaciones que la funcionalidad de reutilización (por ejemplo, el método move ()). Esta
clase tiene un solo campo, maxPin, porque también quiero diferenciar cuántos pines de cada clase
hija de la SSC tiene. Dependiendo del controlador servo que tiene, asegúrese de establecer esta
consecuencia.

El constructor toma el J SerialPort. En el método de movimiento, agrego el manejo de errores para
los parámetros de entrada, lanzando una excepción si los parámetros están fuera de los límites, y
luego crear un byte [] con los parámetros antes de llamar al método execute de la clase principal
Controller. En el byte [] envió a través del método execute(), he añadido el byte de sincronización
de 255 cada vez, porque sabemos que tenemos que enviar como parte de la SSCProtocol. (Véase el
Ejemplo 3-4.)
Ejemplo 3-4SSC.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.Controller;
import com.scottpreston.javarobot.chapter2.J SerialPort;
public abstract class Ssc extends Controller implements SSCProtocol{
//Máximo posible del LM32
private int maxPin =31;
// Toma el J SerialPort
public Ssc(J SerialPort serialPort )throws Exception {
super(serialPort);
}
// El movimiento enviará una señal al pin (0-7) and pos (0-255)
public void move(int pin, int pos) throws Exception{
// Mantiene en un rango válido en POS
if (pos <0 || pos >255) {
throw new Exception("Position out of range, must be ➥
between 0 and 255. Value was " +pos +".");
}
//Mantieneen un rango válido el PIN
if (pin <0 || pin >maxPin) {
throw new Exception("Pin out of range, must be between 0 and "
+maxPin +". Value was " +pin +".");
}
// Crea byte[] para los comandos
byte [] b =new byte[] {(byte)255,(byte)pin,(byte)pos};
// Envia los bytes al Controlador
execute(b,0);
}
// Acceso
public int getMaxPin() {
return maxPin;
}
// setter
public void setMaxPin(int maxPin) {
this.maxPin =maxPin;
}
}

Ahora que en general la super-clase ha sido creada, es mommento de crear una clase específica para
MiniSSC-II. Esta clase no tiene campos y simplemente llama al constructor padre y al método
setMaxPin para limitar los siete pins en total. En el ejemplo programo en el main(), llamo a la
misma lógica que compone la clase SerialSSC en el Ejemplo 3-2. Muevo el servo a través del rango
de movimiento en incrementos de 5-byte. Se habrá dado cuenta de que su estructura de mando es
más simple (no bytes para crear o lanzar), y usted tiene el control de errores construido adentro
(Vea el Ejemplo 3-5.).
Ejemplo 3-5 MiniSSC.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
import com.scottpreston.javarobot.chapter2.Utils;
public class MiniSsc extends Ssc implements SSCProtocol {
// calls super and sets max pin to 7
public MiniSsc(J SerialPort serialPort) throws Exception {
super(serialPort);
setMaxPin(7);
}
// Programa de Ejemplo
public static void main(String[] args) {
try {
// Obtener una sola instancia del Puerto Serie
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
// Crea un nuevo MiniSSC
MiniSsc ssc =new MiniSsc(sPort);
// Muevo desde la posición 0 a 255, 5 por 100 ms
for (int pos =0; pos <255; pos =pos +5) {
// Muevo
ssc.move(0, pos);
// Espera 100 milisegundos
Utils.pause(100);
}
// Cierro el Puerto Serie
sPort.close();
} catch (Exception e) {
// Imprime hasta encontrar la pila de salida
e.printStackTrace();
System.exit(1);
}
}
}

Resumen de la Sección
En esta sección, se mostró una manera difícil y una forma fácil de modelar un controlador servo.
También se agrego una interfaz para asegurar la comunicación para controladores diferentes y se
añadió una implementación para el MiniSSC-II. Las clases tratados fueron los siguientes:
• SerialSsc.java: Una versión de serie del control de servo (un ejemplo de una manera dura)
• SSCProtocol.java: una interfaz diseñada para estandarizar la comunicación a un controlador
servo.
• SSC.java: Super-clase utilizada por las clases MiniSSC y otro para la comunicación servo
• MiniSSC.java: Clase de Implementación para el de Scott Edwards MiniSSC-II
Ahora que ya sabe cómo controlar servos con su PC, usted está listo para conseguir un robot para
moverlo .En la siguiente sección, voy a hablar acerca de los robots de accionamiento diferenciales
(con dos ruedas) y va a utilizar la MiniSSC y puerto serial de su PC para que se mueva.
3.2 Movimiento de ruedas
El uso de un controlador servo conectado a un controlador electrónico de velocidad o un par de
"hackeado" o servos de rotación continua es una manera excelente para facilitar el movimiento de
ruedas. La Ilustración 3-5 muestra una imagen de la unidad diferencial, un CubeBot conectado a un
MiniSSC-II. Observe que los cables de servo son para la parte trasera de la plataforma. Esto
significa que los motores están invertidos, así que voy a tener que dar cuenta de ello en las clases de
esta sección.

Ilustración 3-5 La unidad diferencial de una CubeBot
Tres clases y una interfaz se analizará en esta sección. La Ilustración 3-6 muestra un diagrama de
clases que resume las clases.


Ilustración 3-6 Un diagrama de clase de las clases en la sección 3.2
Objetivos del Código
El objetivo de esta sección es proporcionar a los movimientos básicos: adelante, atrás, giro a la
derecha, giro a la izquierda, y se detendrá.
Discusión del Código
Voy a empezar esta sección escribiendo una clase básica de manejo diferencial, llamado
BasicDiffDrive. Los campos de esta clase tienen un campo de instancia única, ssc, para la clase
MiniSSC, que controla los servos y proporciona su funcionalidad. También tengo dos constantes
que representan las conexiones de hardware para las ruedas izquierda y derecha. Los campos
restantes se utilizan para mantener el estado de las posiciones de los servos para velocidades
constantes o variadas.
El constructor para esta clase toma un J SerialPort, que construye la MiniSSC. El método
setMotors() establece los parámetros relativos a la posición y el movimiento de la SSC. Este método
es seguido por move(), que llama al método MiniSSC del mismo nombre.
Los cuatro métodos de dirección- forward(), reverse(), pivotLeft(), y pivotRight()-tienen dos
funciones: primero, para comprobar si los motores están conectados en una forma invertida (como
el CubeBot), y luego a establecer los valores de los motores, y en segundo lugar, para llamar al
método move. Aunque podría haber llamado a ssc.move (), lo que más tarde me permite ampliar y
agregar un control de velocidad, no habría podido volver a utilizar el método de las subclases
posteriores. Sin embargo, si no desea el control de velocidad, puede simplificar esto con sólo
introducir las posiciones para que se muevan directamente en cada uno de los cuatro métodos de
dirección.
Los emisores y los métodos de descriptor de acceso se incluyen para que las clases pueden acceder
a las variables de derecha e izquierda de las subclases TimedDiffDrive. Por último, en el main()
puedo probar la clase enviando el robot hacia adelante por 2 segundos, y luego se detienen.(Véase
el Ejemplo 3-6.)
Ejemplo 3-6 BassicDriffDriver.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
import com.scottpreston.javarobot.chapter2.Utils;
public class BasicDiffDrive {
// Driver que usará el MiniSSC
private MiniSsc ssc;
// Rueda izquierda enganchada al pin0
public static final int LEFT_WHEEL =0;
// Rueda derecha enganchada al pin1
public static final int RIGHT_WHEEL =1;
// Establece todo los valores neutrales
private int right =SSCProtocol.NEUTRAL;;
private int left =SSCProtocol.NEUTRAL;
private int rightHigh =SSCProtocol.MAX;
private int rightLow =SSCProtocol.MIN;
private int leftHigh =SSCProtocol.MAX;
private int leftLow =SSCProtocol.MIN;
// right will always be the one inverted can change this
private boolean motorsInverted =false;
// El constructor toma a J SerialPort
public BasicDiffDrive(J SerialPort serialPort) throws Exception {
// Crea MiniSSC
ssc =new MiniSsc(serialPort);
}
// Configura los valores del motor
public void setMotors(int left, int right) {
this.left =left;
this.right =right;
}
// Mueve realmente los motores
private void move() throws Exception {
// Rueda izquierda
ssc.move(LEFT_WHEEL, left);
// Rueda derecha
ssc.move(RIGHT_WHEEL, right);
}
// Mueve en reversa
public void reverse() throws Exception {
// if inverted move motors opposite or same.
if (motorsInverted) {
// Direccion opuesta
setMotors(leftHigh, rightLow);
} else {
// Misma dirección
setMotors(leftHigh, rightHigh);
}
// Mueve el motor
move();
}
// Mueve hacia adelante
public void forward() throws Exception {
if (motorsInverted) {
setMotors(leftLow, rightHigh);
} else {
setMotors(leftLow, rightLow);
}
move();
}
// Gira el eje a la derecha
public void pivotRight() throws Exception {
if (motorsInverted) {
setMotors(leftLow, rightLow);
} else {
setMotors(leftLow, rightHigh);
}
move();
}
// Gira el eje a la izquierda
public void pivotLeft() throws Exception {
if (motorsInverted) {
setMotors(leftHigh, rightHigh);
} else {
setMotors(leftHigh, rightLow);
}
move();
}
// Para el movimiento
public void stop() throws Exception {
// Establece los motores al mismo valor
setMotors(SSCProtocol.NEUTRAL, SSCProtocol.NEUTRAL);
move();
}
// Acceso
public boolean isMotorsInverted() {
return motorsInverted;
}
// Seteo
public void setMotorsInverted(boolean motorsInverted) {
this.motorsInverted =motorsInverted;
}
// Acceso
public int getLeftHigh() {
return leftHigh;
}
// Seteo
public void setLeftHigh(int leftHigh) {
this.leftHigh =leftHigh;
}
// Acceso
public int getLeftLow() {
return leftLow;
}
//Seteo
public void setLeftLow(int leftLow) {
this.leftLow =leftLow;
}
// Acceso
public int getRightHigh() {
return rightHigh;
}
// Seteo
public void setRightHigh(int rightHigh) {
this.rightHigh =rightHigh;
}
// Acceso
public int getRightLow() {
return rightLow;
}
// Seteo
public void setRightLow(int rightLow) {
this.rightLow =rightLow;
}
// Simple Programa
public static void main(String[] args) {
try {
// Obtener la instancia de SingleSerialPort
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
// Crea una instancia de BasicDiffDrive
BasicDiffDrive diffDrive =new BasicDiffDrive(sPort);
// Mueve hacia adelante
diffDrive.forward();
// Pausa de 2 segundos
Utils.pause(2000);
// Parada
diffDrive.stop();
// Cierra el puerto serie
sPort.close();
} catch (Exception e) {
// Imprime hasta obtener la pila de salida
e.printStackTrace();
System.exit(1);
}
}
}

La siguiente clase simplifica un poco el movimiento mediante la adición de pause() y stop(). Al
extender la clase BasicDiffDrive y la creación de nuevos métodos con parámetros para tener un
argumento milisegundo, nuestro robot puede moverse en una dirección particular durante una
unidad de tiempo dada. (Véase el Ejemplo 3-7.)
• Nota: he encontrado que el uso de resolución de milisegundos es tan exacta como los
codificadores de rueda a través de distancias cortas (<3 metros o segundos <10). Esto es
debido a que el deslizamiento de las ruedas y el tiempo para detener las exactitudes son en
su extremo inferior con estas distancias y velocidades. Pero incluso estas deficiencias son
superadas por los sensores de medición de distancia con el fin de eliminar la "práctica"
necesidad de encoders de rueda.
Ejemplo 3-7 TimedDiffDriver.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
import com.scottpreston.javarobot.chapter2.Utils;
public class TimedDiffDrive extends BasicDiffDrive {
//Constructor con J SerialPort
public TimedDiffDrive(J SerialPort serialPort) throws Exception {
super(serialPort);
}
// Hacia adelante
public void forward(long ms) throws Exception {
// Super llamada
forward();
// Pausa
Utils.pause(ms);
// Parada
stop();
}
// Reversa
public void reverse(long ms) throws Exception {
reverse();
Utils.pause(ms);
stop();
}
// Giro hacia la izquierda
public void pivotLeft(long ms) throws Exception {
pivotLeft();
Utils.pause(ms);
stop();
}
// Giro hacia la derecha
public void pivotRight(long ms) throws Exception {
pivotRight();
Utils.pause(ms);
stop();
}
// Programa Simple
public static void main(String[] args) {
try {
// Obtener instancia de SingleSerialPort
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
// Creando la instancia de TimedDiffDrive
TimedDiffDrive diffDrive =new TimedDiffDrive(sPort);
// Mueve hacia adelante por 2 segundos
diffDrive.forward(2000);
// Cierre del puerto serie
sPort.close();
} catch (Exception e) {
// Imprime hasta encontrar en la pila la salida
e.printStackTrace();
System.exit(1);
}
}
}

La última cosa que necesito para la unidad diferencial sea completa es un control de velocidad. Sin
embargo, no siempre se han rodado robots. Yo podría querer implementar clases de navegación con
robots con patas o las implementaciones de otros sectores de la unidad diferencial (tal vez incluso
un carro con el acelerador, freno y volante). En este caso, porque quiero volver a usar mis clases de
navegación (véase el capítulo 7), debería crear una interfaz y luego usar esa interfaz en clases
posteriores. La interfaz que voy a crear es J Motion. Esta clase tiene todos los métodos de
BasicDiffDrive y TimedDiffDrive, además de los métodos para el control de velocidad. (Véase el
Ejemplo 3-8.)
Ejemplo 3-8 La interface JMotion.java
package com.scottpreston.javarobot.chapter3;
public interface J Motion {
// hacia adelante
public void forward() throws Exception;
// reversa
public void reverse() throws Exception;
// giro derecho
public void pivotRight() throws Exception;
// giro izquierdo
public void pivotLeft() throws Exception;
// parada
public void stop() throws Exception;
// hacia adelante
public void forward(int ms) throws Exception;
// reversa
public void reverse(int ms) throws Exception;
// giro derecho
public void pivotRight(int ms) throws Exception;
// giro izquierdo
public void pivotLeft(int ms) throws Exception;
// ajuste de velocidad del robot
public void setSpeed(int speed)throws Exception ;
// obtener la velocidad del robot
public int getSpeed();

• Nota: La velocidad no funcionará en un servo hackeado porque es bien completa o total en
off. Allí tendrá que retrasar los ciclos de encendido y apagado de tu servo a algo muy
rápido. Puede ser difícil conseguir que esto funcione y sea suave dada nuestra tasa de
baudios. Sin embargo, no va a funcionar bien para un control electrónico de velocidad
(ECS), pero es posible que desee ajustar la velocidad a una resolución mayor que 10.
En la clase SpeedDiffDrive, yo implemento la interfaz J Motion y tiene una velocidad de campo que
he de pagar a 5. El setSpeed () es el corazón del método, ya que establece los valores altos para el
servo controlador, así como los valores bajos. Por lo tanto, a una velocidad de 10, el alto valor sería
255, mientras que a una velocidad de 9 sería 255 a 13 (12,7) =242, y así sucesivamente. En la parte
inferior al de la clase, por eso tengo que implementar los métodos de la interfaz que ya existen en la
super-clase. ¿Por qué tenemos que crear sólo tiene que pasar a través de? J ava no soporta herencia
múltiple, por lo que el compilador sólo ve el método BasicDiffDrive para la interfaz y no la clase
TimedDiffDrive. (Véase el Ejemplo 3-9.)
Ejemplo 3-9SpeedDiffDrive.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
public class SpeedDiffDrive extends TimedDiffDrive implements J Motion{
// Ajuste de Velocidad Inicial
private int speed =5;
// Constructor con J SerialPort
public SpeedDiffDrive(J SerialPort serialPort) throws Exception{
super(serialPort);
}
// Acceso para la Velocidad
public int getSpeed() {
return speed;
}
// Seteo de Velocidad
public void setSpeed(int speed) throws Exception {
// Mantiene la Velocidad en tre MIN y MAX
if (speed <1 || speed >10) {
throw new Exception("Speed out of range 1-10.");
}
// Ajuste de Velocidad
this.speed =speed;
// get high for left
setLeftHigh(getSpdHI());
// get low for left
setLeftLow(getSpdLO());
// get high for right
setRightHigh(getSpdHI());
// get low for right
setRightLow(getSpdLO());
}
// get speed as fraction of 127 (half of MiniSSC)
private int getSpd() {
double s =(double) 127 * (speed / 10.0);
return (int) s;
}
// Retorna Velocidad alta
private int getSpdHI() {
return getSpd() +127;
}
// Retorna Velocidad baja
private int getSpdLO() {
return 127 - getSpd();
}
// Codigo simple
public static void main(String[] args) {
try {
// Obtiene la instancia de SingleSerialPort
J SerialPort sPort =(J SerialPort)SingleSerialPort.getInstance(1);
// Crea la instancia de SpeedDiffDrive
SpeedDiffDrive diffDrive =new SpeedDiffDrive(sPort);
// Ajuste de Velocidad de 5
diffDrive.setSpeed(5);
// Avanzar 2 segundos
diffDrive.forward(2000);
// Cierra el puerto
sPort.close();
} catch (Exception e) {
// Imprima hasta conseguir la pila de salida
e.printStackTrace();
System.exit(1);
}
}
// Para interface passthroughs
public void forward(int ms) throws Exception{
super.forward(ms);
}
public void reverse(int ms) throws Exception{
super.reverse(ms);
}
public void pivotRight(int ms) throws Exception{
super.pivotRight(ms);
}
public void pivotLeft(int ms) throws Exception{
super.pivotLeft(ms);
}
}

Resumen De La Sección
Las tres clases de esta sección te llevará a través del movimiento de más ruedas utilizando un
controlador servo de serie y / o control de velocidad electrónico. Las clases que se trataron fueron:
• BasicDiffDrive.java: El control diferencial de la unidad básica.
• TimedDiffDrive.java: La versión extendida de BasicDiffDrive que permite el movimiento
que se producen a intervalos de tiempo específicos.
• J Motion.java: La interfaz que define los movimientos básicos de todos los tipos de
movimiento (para ruedas y robots con patas)
• SpeedDiffDrive.java: La versión extendida de TimedDiffDrive que le da el control de
velocidad a cualquier movimiento.
El siguiente tipo de movimiento todavía va a hacer con servos, pero esta vez se pasará; algo en su
robot en lugar del propio robot. Se basan en los mismos principios discutido aquí, pero en vez de
crear métodos como forward () o pivotRight (), se creará métodos como lookup () o lookRight ()
para mover la cámara.......
3.3 Pan Y Mecanismos De Inclinación
A veces sólo quiero trasladar parte de su robot. Si usted tiene una cámara y están haciendo algunas
cosas con visión artificial (véase el capítulo 6), entonces usted definitivamente quiere un pan y un
sistema de cámara de inclinación. El que yo uso se muestra en la Ilustración 3-7 y comprende unos
pocos soportes y dos servos, que se pueden adquirir a partir de Lynxmotion por menos de $ 35. Yo
tomo a los mismos conceptos utilizados en nuestros sistemas de accionamiento diferencial como
agrupar servos juntos en una clase, y luego vamos a usar nuestra clase MiniSSC para controlar los
servos.

Ilustración 3-7 El Pan Tilt Lynxmotion y su Kit
La Ilustración 3-8 muestra un diagrama que resume las clases.

Ilustración 3-8 Resumen de las Clases
Objetivos del Código
El objetivo de esta sección es crear una clase para controlar un mecanismo de inclinación de la base
y de un controlador servo.
Discusión del Código
La parte más importante de esta clase es el preconfigurado de constantes, por ejemplo, qué pins
conectar los servos? ¿Hasta qué punto pueden los servos moverse? ¿Cuáles son las posiciones de
reposo? Estas son las cosas que usted tendrá que experimentar. Los campos restantes son stepSize
(cantidad de bytes que el sistema se moverá en pasos por defecto en tres), velocidad (la velocidad
del servo se moverá entre los pasos) y el MiniSSC, que hace el trabajo.
El constructor es la J SerialPort y el método de movimiento llama a métodos separados para mover
los servos de control horizontal y vertical. Los dos métodos horz() y vert() se verá en los valores de
posición actuales y luego envia correspondientes señales en serie a la SSC, siempre y cuando las
posiciones están dentro del alcance del sistema de giro e inclinación. En lugar de siempre en
posiciones de byte de 0 a 255, he añadido dos métodos horzDegree() y vertDegree() que convierte
ángulos de 0 a 180, y bytes desde 0 a 255. Los métodos existen para mover la base y mecanismo de
inclinación en pasos. Esto es útil si usted tiene un sistema de cámaras de seguimiento y usted sólo
quiere dar un paso en una dirección, pero no sé hasta qué punto a la izquierda, derecha, arriba o
abajo desea mover.
Porque quiero que el pan y tilt para moverse sin problemas desde una posición a otra en el método
setServoTiming (), para realizar alguna comprobación de errores y ver si el tipo de movimiento
especificado es mayor que la velocidad máxima. Por ejemplo, si el servo puede pasar de 0 a 90
grados en 240 milisegundos, y quiero que se mueva allí en 200 milisegundos, necesito una
excepción porque el servo no puede moverse tan rápido.
Además, si el tamaño de paso es menor que el tamaño mínimo, necesito una excepción porque el
servo sólo puede responder a las señales tan rápido como el controlador serial pueda enviar a una
velocidad de 9600 baudios.
En la prueba el método main (), que es una instancia de la clase PanTilt con el StandardSerialPort
(J SerialPort), y luego moverse hacia la izquierda hasta que esté en su límite, luego a la derecha,
luego hacia arriba y luego hacia abajo. Aunque una excepción es una manera bastante descuidada
de codificación, yo quería mostrar cómo se pueden utilizar las excepciones para evitar que el
sistema se haga daño a sí mismo. (Véase el Ejemplo 3-10.)





Ejemplo 3-10 PanTilt.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
public class PanTilt{
// Conectado el pin 6 a MinSSC-II
public static final int HORZ_SERVO =6;
// conectada a la patilla 7 de MinSSC-II
public static final int VERT_SERVO =7;
private int horzPos =SSCProtocol.NEUTRAL;
private int vertPos =SSCProtocol.NEUTRAL;
// should set these to the best limits of your pan/tilt system
public static final int MAX_UP =145;
public static final int MAX_DOWN =45;
public static final int MAX_RIGHT =235;
public static final int MAX_LEFT =25;
public static final int VERT_NEUTRAL =95;
public static final int HORZ_NEUTRAL =140;
// 3 milisegundos a 9600 baudios
public static final int MIN_STEP_SIZE =3;
// 2 milisegundos para servo standard
public static final int MIN_DELAY_SIZE =2;
// retardo en milisegundos entre movimientos
private int moveDelay =50;
// tamaño en bites de único paso
private int stepSize =MIN_STEP_SIZE;
private int speed =0;
// MiniSSC haciendo el trabajo
private MiniSsc ssc;
// tomando el constructor J SerialPort
public PanTilt(J SerialPort sPort) throws Exception{
ssc =new MiniSsc(sPort);
}
// moviendo los servos a las posiciones
private void move() throws Exception {
horz(horzPos);
vert(vertPos);
}
mover los servos con parámetros de entrada
// h =horizontal servo
// v =vertical servo
public void moveBoth(int h, int v) throws Exception{
// establece campos privados
horzPos =h;
vertPos =v;
// move
move();
}
public void horz(int pos) throws Exception{
// check to see if position within limits
if (pos <MAX_LEFT || pos >MAX_RIGHT ) {
throw new Exception("Out of horizontal range.");
}
// establece el pos
horzPos =pos;
// movimiento
ssc.move(HORZ_SERVO,pos);
}
public void horzDegree(int angle) throws Exception{
// comprobar para ver si el ángulo está dentro de los límites de 0-180
if (angle <0 || angle >180) {
throw new Exception("Out of range, angle 0-180.");
}
// convierte fracción de 255
double theta =((double)angle/180 ) * 255.0 ;
// movimiento
horz((int)theta);
}
public void vert(int pos) throws Exception{
if (pos <MAX_DOWN || pos >MAX_UP ) {
throw new Exception("Out of vertical range.");
}
vertPos =pos;
ssc.move(VERT_SERVO,pos);
}
public void vertDegree(int angle) throws Exception{
if (angle <0 || angle >180) {
throw new Exception("Out of range, angle 0-180.");
}
double theta =((double)angle/180 ) * 255.0 ;
vert((int)theta);
}
// reseteo a posicion actual
public void reset( ) throws Exception{
horzPos =HORZ_NEUTRAL;
vertPos =VERT_NEUTRAL;
move();
}
// movimiento derecho con pasos específicos
public void moveRight(int size) throws Exception{
horz(horzPos+size);
}
// movimiento actual derecho stepSize
public void moveRight()throws Exception {
moveRight(stepSize);
}
public void moveLeft(int size) throws Exception{
horz(horzPos-size);
}
public void moveLeft()throws Exception {
moveLeft(stepSize);
}
public void moveUp(int size) throws Exception{
vert(vertPos+size);
}
public void moveUp()throws Exception {
moveUp(stepSize);
}
public void moveDown(int size) throws Exception{
vert(vertPos-size);
}
public void moveDown()throws Exception {
moveDown(stepSize);
}
// acceso
public int getHorzPos() {
return horzPos;
}
// seteo
public void setHorzPos(int horzPos) {
this.horzPos =horzPos;
}
// acceso
public int getVertPos() {
return vertPos;
}
// seteo
public void setVertPos(int vertPos) {
this.vertPos =vertPos;
}
// acceso
public int getSpeed() {
return speed;
}
// seteo
public void setSpeed(int speed) {
this.speed =speed;
}
// seteo sincronizado del servo
// stepSize =size of the step as long as it's not minimum step size
// moveDelay =tiempo de retardo entre los pasos
public void setServoTiming(int stepSize, int moveDelay)
throws Exception {
// asegura el funcionamiento
if (stepSize <MIN_STEP_SIZE) {
throw new Exception("Step size not possible at 9600 baud.");
}
if (moveDelay <(stepSize * MIN_DELAY_SIZE)) {
throw new Exception("Move delay not practical for given step size.");
}
this.stepSize =stepSize;
this.moveDelay =moveDelay;
}
public int getMoveDelay() {
return moveDelay;
}
public int getStepSize() {
return stepSize;
}
// programa simple
public static void main(String[] args) {
try {
// obtiene la instancia de SingleSerialPort
J SerialPort sPort =(J SerialPort)SingleSerialPort.getInstance(1);
// crea la instancia de PanTilt
PanTilt pt =new PanTilt(sPort);
// pan izquierda hasta excepción
while (true) {
try {
pt.moveLeft();
} catch (Exception e) {
break;
}
}
// pan derecho
while (true) {
try {
pt.moveRight();
} catch (Exception e) {
break;
}
}
// reset head
pt.reset();
// tilt arriba
while (true) {
try {
pt.moveUp();
} catch (Exception e) {
break;
}
}
// tilt abajo
while (true) {
try {
pt.moveDown();
} catch (Exception e) {
break;
}
}
// resetea la cabecera
pt.reset();
// cierra el puerto serie
sPort.close();
} catch (Exception e) {
// imprime hasta encontrar la salida en la pila
e.printStackTrace();
System.exit(1);
}
}
}

Resumen De La Sección
Así que ahora usted puede mover el robot y la posición de su cámara/ojo (s). Si lo mueve con gracia
todavía puede tomar un poco de experimentación, pero creamos algunas clases que proporcionan la
base para la panorámica y la inclinación y otras configuraciones de servo similares. En esta sección,
he creado las siguientes dos clases:
• PanTilt.java: La clase base para las operaciones de giro e inclinación
• PanTiltSpeed.java: Esta se extiende desde PanTilt para proporcionar un movimiento más
suave de una posición a otra.
Aunque esto va a funcionar adecuadamente para la mayoría de tareas, es posible que aún desea un
movimiento más suave o necesita más servos para mover. En tales casos, es posible que desee
probar el Lynxmotion SSC-32 y luego implementar otro protocolo además de la SSCProtocol lo que
puede pasar más de un servo con un comando de serie único. Voy a hablar de eso y más en la
siguiente sección.
3.4 Control Servo Avanzada
En el ejemplo anterior, lo que mostró pan y tilt con velocidad y control de errores, se puede ver que
el control de unos pocos servos pueden llegar a ser muy complicado. Mientras se preparan para
discutir los brazos robóticos y robots con patas, voy a estar trabajando con más de dos servos, a
veces hasta 12 en el caso de los Extremos Hexapod 2. Yo también quería tener el mismo nivel de
control de la velocidad como lo hice con dos servos, y también coordinar los movimientos de más
de un servo al mismo tiempo. En este ejemplo, quiero centrarme en hacer mi robot resolviendo los
problemas de más alto nivel, como la navegación en lugar de dedicar todo mi código y ciclos de
CPU para manejar el control de servo. Afortunadamente, hay un control de servo nuevo en el
mercado con todas esas características: la Lynxmotion SSC-32 (véase la Ilustración 3-9). Este
controlador servo permite el control de velocidad y temporización. Lo usaremos cuando se habla de
controles avanzados servo y movimientos de grupos.

Ilustración 3-9 Controlador Servo Lynxmotion SSC-32
El Lynxmotion SSC-32 servo controlador tiene 32 pines de salida en comparación con los ocho
pines del MiniSSC-II. También permite que el mismo protocolo de comunicación, por lo que si se
crea algo de código para el MiniSSC, se puede volver a usar con el SSC-32 y puede aumentar la
velocidad de transmisión a 115.200. Así, cuando el modelo de este controlador, puede implementar
la misma interfaz SSCProtocol, sino porque viene con algunos otros elementos de construcción en
características como movimientos agrupados y en su momento, vamos a querer añadir un nuevo
protocolo llamado GroupMoveProtocol. Aunque este protocolo es muy útil con el LM32, también
puede escribir una clase para el MiniSSC para implementar la interfaz. Entonces usted debe ser
capaz de utilizar hardware Plug N Play (PnP), sin cambiar mucho software.
El Lynxmotion SSC-32 controlador servo tiene 32 pines de salida en comparación con los ocho
pines del MiniSSC-II. También permite el mismo protocolo de comunicación, por lo que si se crea
algo de código para el MiniSSC, se puede volver a usar con el SSC-32 y puede aumentar la
velocidad de transmisión a 115.200. Así, con el modelo de este controlador, puede implementar la
misma interfaz SSCProtocol, ademásviene con algunos otros elementos de construcción en
características como movimientos agrupados y en su momento, noxotros vamos a querer añadir un
nuevo protocolo llamado GroupMoveProtocol. Aunque este protocolo es muy útil con el LM32,
también puede escribir una clase para el MiniSSC para implementar la interfaz. Entonces usted
debe ser capaz de utilizar hardware Plug N Play (PnP), sin cambiar mucho software.
El GroupMoveProtocol es diferente a la SSCProtocol por tres razones: una, puede agrupar un
número de servos juntos en un solo comando en lugar de enviar cadenas de comandos para cada
servo, dos, puede introducir la velocidad a la que desea desplazarse por cada canal para desplazarse,
y tres, se puede establecer el movimiento máximo para todo el canal.
Usando el GroupMoveProtocol es dThese tres características le dan la GroupMoveProtocol un
montón de ventajas sobre el SSCProtocol y ahora ya estamos controlando el tiempo con el
controlador y no el método Thread.sleep (), nuestro programa de control tendrá que cambiar
también. Estas tres características le dan la GroupMoveProtocol un montón de ventajas con respecto
a la SSCProtocol y ahora porque estamos controlando sincronización con el controlador y no el
método Thread.sleep (), nuestro programa de control tendrá que cambiar también. En mi clase, yo
quiero tres tipos de métodos. El primer movimiento se acaba de hacer lo que el SSCProtocol hace,
excepto que voy a dar al método un argumento extra que designa el momento de pasar en
milisegundos. El segundo tipo de movimiento será un movimiento de grupo. Esto moverá todos los
servos en el grupo asociado a la posición deseada. El tercer tipo de movimiento será determinar
cómo establecer los grupos y pines. He incluido un diagrama de clases de estas clases en la
Ilustración3-10.

Ilustración 3-10 Diagrama UML de las clases de la sección 3.4
Objetivos Del Código
El objetivo aquí es crear una interfaz para gestionar la GroupMoveProtocol para que pueda ser
implementado por el MiniSSC y LM32.


Ejemplo 3-11GroupMoveProtocol.java
package com.scottpreston.javarobot.chapter3;
public interface GroupMoveProtocol {
public static final String CMD_TERM ="\r";
/**
* This is the SSC Constructor Mode w/500 default speed
* @param ch - channel 0-31
* @param pos - position 0-255
*/
public void sscCmd(int ch, int pos) throws Exception;
/**
* This is the native constructor mode.
* @param ch - channel 0-31
* @param pos - position 0-255
* @param spd - speed in ms
* @param tm =time to move in milliseconds
*
*/
public void cmd(int ch, int pos, int spd) throws Exception;
/**
*
* @param time - length in milliseconds to move
* @throws Exception
*/
public void move(int time) throws Exception;
}
Debido a que el LM32 tiene comandos para la sincronización y podemos agrupar los servos, vamos
a tener que hacer mucho menos en nuestra clase, y nuestros tiempos se verán más suave y más
fluido.
Objetivos Del Código
El objetivo es poner en práctica el GroupMoveProtocol para el LM32.
Discusión del Código
Uno de los beneficios de un lenguaje agradable es la reutilización de código. Tenga en cuenta que
acabo de ampliar la clase SSC, por lo que esta clase va a hacer lo mismo que un estándar MiniSSC-
II....
La diferencia observada en la siguiente clase es que la interfaz es el formato real de la cadena de
comandos en la createCmd método(). Además, debido a que estamos acostumbrados a tratar con las
posiciones del servo entre 0-255, me dejó esto en lugar de que el programa de trabajadores para
realizar un seguimiento de los anchos de pulso entre 750 y 2250 milisegundos.

Los dos campos de la clase son cmds-un StringBuffer y un booleano para indicar el estado de
cualquier clase con este objeto. Debido a que el tiempo está determinado por el LM32, opto por
utilizar un temporizador para indicar la clase de cambio de estado (ocupado =false). Esto se hace a
través de la setBusy(), método en el que se establece una única tarea que se ejecute a una hora
determinada en el futuro (ahora +milisegundos en el futuro).
El constructor llama al super constructor con el J SerialPort, y establece el campo maxPins a 32. El
método move() convierte el StringBuffer a un byte [] antes de enviar el puerto serie a través del
controlador, ejecute método.
• Nota: Tenga en cuenta que podría haber puesto en un parámetro aquí por un retraso en la
llamada a execute(), pero yo quería mostrar otra forma de hacer lo mismo sin ocupar
recursos durante un movimiento.
La construcción del comando serie tiene la siguiente sintaxis:
"#" +channel (0-31)
+"P" +pulsewidth (750-1500milliseconds)
+"S" +speed(milliseconds for move)
Puede encadenar hasta 32 comandos juntos antes de tener que darlo por terminado añadiendo lo
siguiente:
"T" +time for total move(milliseconds) +"\r"
El ancho de pulso es el tiempo en milisegundos que he simplificado a través del método getpw().
Éste entregará el ancho de pulso que va de 750 a 1500 de un byte entre 0 y 255. Finalmente, el
programa de prueba utiliza sólo dos servos y los mueve a las posiciones 100 y 200,
respectivamente, durante un plazo de tiempo de 1 segundo. (Véase el Ejemplo 3-12.)
Ejemplo 3-12 LM32.java
package com.scottpreston.javarobot.chapter3;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
import com.scottpreston.javarobot.chapter2.Utils;
public class LM32 extends Ssc implements SSCProtocol, GroupMoveProtocol {
// buffer para almacenar comandos
private StringBuffer cmds =new StringBuffer();
// velocidad predeterminada en milisegundos
public static int DEFAULT_SPEED =500;
// ocupado o no
private boolean busy =false;
// tomando el constructor J SerialPort
public LM32(J SerialPort sPort) throws Exception {
super(sPort);
super.setMaxPin(32);
}
// mover comando con el parámetro de milisegundos
public void move(int ms) throws Exception {
// Esto detiene el subproceso actual para el movimiento del brazo hasta
/ / que termina de completar su acción
while (busy) {
Utils.pause(2);
}
// establecer el estado de los objetos de ocupado
setBusy(ms);
// anexar orden final
String cmd =cmds.append("T" +ms +CMD_TERM).toString();
// Enviar bytes al LM32
execute(cmd.getBytes(), 0);
// limpia el comando String
cmds =new StringBuffer();
/ / se restablece la cadena de buffer para nuevo conjunto de
/ / Comandos
}
/ / Sobrescribir el actual comando SSC
public void sscCmd(int ch, int pos) throws Exception {
cmd(ch, pos, DEFAULT_SPEED);
}
/**
* @param ch - channel 0-31
* @param pos - position 0-255
* @param spd - speed in milliseconds
*/
public void cmd(int ch, int pos, int spd) throws Exception {
/ / Asegurar que la posición es válida
if (pos <0 || pos >255) {
throw new Exception("position out of bounds");
}
/ / Llamada createCmd luego añadir al búfer de cadena
cmds.append(createCmd(ch, pos, spd));
}
/ / Permite una cadena de comandos en bruto para ser enviados
public void setRawCommand(String rawCmd) {
cmds.append(rawCmd);
}
/ / Este es el protocolo para la cadena de comandos para el LM32
public static String createCmd(int ch, int pos, int spd) {
String out ="#" +ch +"P" +getPw(pos) +"S" +spd;
return out;
}
/ / Establece el LM32 ocupado durante milisegundos específicos
private void setBusy(long ms) {
// the set busy function
busy =true;
/ / Obtiene momento en que se debe hacer
Date timeToRun =new Date(System.currentTimeMillis() +ms);
Timer timer =new Timer();
/ / Horarios que se ejecute tan ocupada puede establecer en false
timer.schedule(new TimerTask() {
public void run() {
busy =false;
}
}, timeToRun);
}
// acceso
public boolean isBusy() {
return busy;
}
// método de utilidad estática
public static int getPw(int pos) {
int pulsewidth;
double percent =(double) pos / 255;
double pwfactor =percent * 1500;
// establece anchura de pulso como función del tamaño de byte
pulsewidth =750 +(int) pwfactor;
return pulsewidth;
}
// programa simple
public static void main(String[] args) {
try {
// obtener una sola instancia puerto serial
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
// creado la nueva LM32
LM32 lm32 =new LM32(sPort);
// establece la posicón del servo en pin 0
lm32.sscCmd(0, 100);
// establece la posicón del servo en pin 1
lm32.sscCmd(1, 200);
// dice a los servos para mover allí en 1 segundo.
lm32.move(1000);
// cierra el puerto serie
sPort.close();
} catch (Exception e) {
// print stack trace and exit
e.printStackTrace();
System.exit(1);
}
}
}



Mover grupo con el MiniSSC-II

Esto será más difícil en el MiniSSC-II ya que hay que controlar dos series de tiempo. El primer
momento será el paso de la posicióndel servo A a la posición del servo B. El segundo momento es
el tamaño de paso limitada por 9600. Esto significa que el tamaño de paso del servo para cada uno
de los servos es dependiente del número de servos que se han conectado. Debido a que cada
comando está a unos 3 milisegundos si tiene dos servos tomará cerca de 6 milisegundos, 9
milisegundos para tres servos, etc. Para que esto funcione, tendremos que crear una manera de
procesar estos comandos por separado para cada paso, para cada servo, y para cada intervalo de
tiempo.
Objetivos del Código
Nuestro objetivo es duplicar en un MiniSSC-II lo que ya está hecho por nosotros en el LM32.
Discusión del Código
Para facilitar las cosas, voy a crear una estructura de datos llamada ServoPosition, que voy a
guardar en una lista de comandos. A pesar de que podría haber usado una segunda matriz, esto
parecía más legible. (Véase el Ejemplo 3-13.)
Ejemplo 3-13 ServoPosition.java
package com.scottpreston.javarobot.chapter3;
public class ServoPosition {
public int pin;
public int pos;
public ServoPosition (int pin, int pos) throws Exception{
if (pos >255 || pos <0) {
throw new Exception("Position out of range, 0-255 only.");
}
this.pin =pin;
this.pos =pos;
}
}
En MiniSscGM, tengo dos ArrayLists como campos. Los primeros comandos ArrayList almacena
todos los comandos como una lista de ServoPositions. El segundo almacena todos los servos según
la definición de sus posiciones actuales. El constructor toma el J SerialPort y createServos
llamadas(). Este método sólo crea un ServoPosition nuevo y lo agrega a la clase ArrayList.
El método sscCmd(), requiere de la interfaz GroupMoveProtocol acaba de llamar el método Move
del mismo nombre y los parámetros.
E método cmd()agrega la posición de los servos al ArrayList hasta que el método move() se llama
desde mov () es donde está toda la acción tiene lugar. En move(), lo primero que tenemos que hacer
es conseguir la máxima diferencia entre las posiciones de los servos en el comando. Este número
determinará el tamaño de paso para cada duración. Así que si el movimiento total es de 1000
milisegundos y el tamaño de paso es de 100 posiciones, me di cuenta de que el servo se mueve una
posición cada 10 milisegundos si el protocolo y servo eran lo suficientemente rápido.
Lo siguiente en move(), es necesario determinar el número total de pasos basados en el tamaño de
paso mínimo. Dado que el tamaño mínimo es de 3, tendríamos un total de 33 pasos en el orden,
teniendo cada uno de ellos (1000/33) =30. La última parte del move() es incrementar la posición,
moviendo el servo, y después haciendo una pausa el programa antes de que lo hace la siguiente
etapa. (Véase el Ejemplo 3-14.)
Ejemplo 3-14 MiniSscGM.java
package com.scottpreston.javarobot.chapter3;
import java.util.ArrayList;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
import com.scottpreston.javarobot.chapter2.Utils;
public class MiniSscGM extends Ssc implements SSCProtocol, GroupMoveProtocol {
// comandos de almacenamiento en la lista
private ArrayList commands =new ArrayList();
// store servos in list
private ArrayList servos =new ArrayList();
// constructor takes J SerialPort as parameter
public MiniSscGM(J SerialPort jSerialPort) throws Exception {
super(jSerialPort);
setMaxPin(7);
// create servos
createServos();
}
// add servos to list
private void createServos() throws Exception{
for (int i =0; i <getMaxPin() +1; i++) {
ServoPosition svo =new ServoPosition(i, SSCProtocol.NEUTRAL);
// index will be same as id.
servos.add(svo);
}
}
public void sscCmd(int ch, int pos) throws Exception {
// calls overridden move method later in this class
move(ch, pos);
}
public void cmd(int ch, int pos, int spd) throws Exception {
// not going to implement the spd variable for the MiniSSC-II
ServoPosition svoPos =new ServoPosition(ch, pos);
commands.add(svoPos);
}
public void move(int time) throws Exception {
// all servo moves will have a minimum step-size of 3
/*
* gets maximum difference between current positions and new position
*/
int maxDiff =0;
for (int i =0; i <commands.size(); i++) {
ServoPosition newPos =(ServoPosition) commands.get(i);
ServoPosition curPos =(ServoPosition) servos.get(newPos.pin);
int tmpDiff =Math.abs(newPos.pos - curPos.pos);
if (tmpDiff >maxDiff) {
maxDiff =tmpDiff;
}
}
// total steps since 3 is min size.
double totalSteps =((double) maxDiff / 3.0);
/ / Calcular el tiempo de pausa
/ / Tiempo total de movimiento divded por el total de pasos
int pauseTime =(int) ((double) time / totalSteps);
// bucle hasta que la diferencia total entre todos los servos// posición actual y la posición meta es
cero
while (getTotalDiff() >0) {
for (int i =0; i <commands.size(); i++) {
ServoPosition newPos =(ServoPosition) commands.get(i);
ServoPosition curPos =(ServoPosition) servos.get(newPos.pin);
int tmpDiff =Math.abs(newPos.pos - curPos.pos);
if (newPos.pos >curPos.pos) {
if (tmpDiff >2) {
curPos.pos =curPos.pos +3;
} else {
curPos.pos =newPos.pos;
}
} else if (newPos.pos <curPos.pos) {
if (tmpDiff >2) {
curPos.pos =curPos.pos - 3;
} else {
curPos.pos =newPos.pos;
}
}
// mover la posición del servo de corriente más o menos 3
move(curPos.pin, curPos.pos);
Utils.pause(pauseTime);
}
}
// comandos que restablece lista.
commands =new ArrayList();
}
// ayudante método para obtener la diferencia
private int getTotalDiff() {
int totalDiff =0;
for (int i =0; i <commands.size(); i++) {
ServoPosition newPos =(ServoPosition) commands.get(i);
ServoPosition curPos =(ServoPosition) servos.get(newPos.pin);
int tmpDiff =Math.abs(newPos.pos - curPos.pos);
totalDiff =totalDiff +tmpDiff;
}
return totalDiff;
}
private ServoPosition getServo(int id) {
return (ServoPosition) servos.get(id);
}
// misma muestra como programa LM32
public static void main(String[] args) {
try {
// obtener una sola instancia puerto serial
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
// crear nuevos LM32
MiniSscGM miniSscGM =new MiniSscGM(sPort);
// establece la posición de servo en el pin 0
miniSscGM.sscCmd(0, 100);
// establece la posición de servo en el pin 1
miniSscGM.sscCmd(1, 200);
// dice a los servos para mover allí en 1 segundo.
miniSscGM.move(1000);
// close serial port
sPort.close();
} catch (Exception e) {
// Imprime hasta encontrar en la pila la salida
e.printStackTrace();
System.exit(1);
}
}
}

Resumen De La Sección
Se puede ver en la GroupMoveProtocol que el LM32 tiene un montón de ventajas con respecto a la
SSCProtocol cuando se desea un movimiento más suave o tener un montón de servos que quiere
mandar a la vez. En esta sección, he creado las siguientes cuatro clases:
• GroupMoveProtocol.java: Al igual que el Protocolo de cooperación Sur-Sur sino que se
utiliza para los movimientos agrupados del LM32.
• LM32.java: La clase de implementación del Lynxmotion SSC-32.
• ServoPosition.java: Una posición servo estructura de datos para ayudar a aplicar el Grupo
MoveProtocol en el MiniSSC.
• MiniSscGM: La implementado GroupMoveProtocol para la MiniSSC. En la siguiente
sección, hablaremos de cómo utilizar el LM32 y el GroupMoveProtocol con un brazo
robótico.


3.5 El Brazo Robot
Mover el robot en el suelo es sólo un tipo de movimiento. El segundo tipo es el movimiento desde
una posición fija. Para demostrar esto, yo voy a usar un brazo robótico. Si usted no tiene un brazo
de robot, puede adquirir los componentes de Lynxmotion, Inc. al www.lynxmotion.com (ver
Ilustración 3-11) o hacerlo por sí mismo.

Ilustración 3-11 Brazo Robótico
He incluido un diagrama de clases de estas clases en la Ilustración 3-12.

Ilustración 3-12 Diagrama UML de LA Sección 3.5


Objetivos del Código
El objetivo en este ejemplo es crear un modelo simple de un brazo de robot.
Discusión del Código
Los campos de esta clase son en su mayoría constantes estáticas que definirán el rango de
movimiento de sus dos ejes: el hombro y el codo. De los campos restantes, ssc de tipo MiniSSC es
el trabajador, y shoulderPos y elbowPos están en la clase para mantener el estado. El constructor de
la clase toma el J SerialPort, y el método move() es sólo un paso a través de la MiniSS. Los dos
métodos, shoulder() y elbow(), toma como parámetros de entrada posiciones desde 0 a 255 para los
miembros respectivos, y el rest() se mueve tanto en el hombro y el codo en sus respectivas
posiciones de reposo.
• Nota: Si utiliza esta clase, es posible que el movimiento sea más rápido y brusco. Para
reducir la velocidad y que sea suave, mirar hacia adelante a la discusión de la clase
ComplexArm.
Por último, en main() Acabo en mover el brazo a su posición de reposo, y luego a otra posición, a
continuación, cierre el puerto serie. (Véase el ejemplo 3-15.)
Ejemplo 3-15 BasicArm.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
public class BasicArm {
private MiniSsc ssc;
// establecer los parámetros de hombro y codo
public static final int SHOULDER_PIN =0;
public static final int SHOULDER_MAX =SSCProtocol.MAX;
public static final int SHOULDER_MIN =SSCProtocol.MIN;
public static final int SHOULDER_REST =55;
public static final int ELBOW_PIN =1;
public static final int ELBOW_MAX =SSCProtocol.MAX;
public static final int ELBOW_MIN =SSCProtocol.MIN;
public static final int ELBOW_REST =65;
// variables de instancia de la posición actual
private int shoulderPos =SSCProtocol.NEUTRAL;
private int elbowPos =SSCProtocol.NEUTRAL;
//habla con el constructor J SerialPort como parámetro
public BasicArm(J SerialPort sPort) throws Exception {
ssc =new MiniSsc(sPort);
}
// passthrough to ssc
private void move(int pin, int pos) throws Exception {
ssc.move(pin, pos);
}
// mueve el hombro
public void shoulder(int pos) throws Exception {
if (pos <SHOULDER_MIN || pos >SHOULDER_MAX) {
throw new Exception("Out of shoulder range.");
}
shoulderPos =pos;
move(SHOULDER_PIN, pos);
}
// mueve el codo
public void elbow(int pos) throws Exception {
if (pos <ELBOW_MIN || pos >ELBOW_MAX) {
throw new Exception("Out of elbow range.");
}
elbowPos =pos;
move(ELBOW_PIN, pos);
}
public void rest() throws Exception {
shoulder(SHOULDER_REST);
elbow(ELBOW_REST);
}
public static void main(String[] args) {
try {
// obtiene una instancia básiica del puerto
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
// create new BasicArm
BasicArm arm =new BasicArm(sPort);
// mueve a posición res
arm.rest();
// mueve el codo 150
arm.elbow(150);
// mueve el hombro a 200
arm.shoulder(200);
// cierra el puerto serie
sPort.close();
} catch (Exception e) {
// imprime hasta que encuntre en la pila la salida
e.printStackTrace();
System.exit(1);
}
}
}

La próxima clase será formalizar posiciones un poco más que un simple byte 150 para el codo y el
byte 200 para el hombro.
Objetivos del Código
El objetivo aquí es hacer que las posiciones sean más fáciles de invocar, y también para simplificar
el uso del brazo.


Discusión del Código
El único campo que se va a utilizar en esta clase será el brazo de tipo BasicArm. El constructor
toma el J SerialPort y mueve el brazo a su posición de reposo. De los dos métodos de posición, Toa )
y Tob() encapsula las posiciones de A y B en un método para que usted no tenga que recordar
dentro de una clase de invocación. Hago una pausa entre los métodos para que el movimiento puede
parar desde que el movimiento sigue siendo desigual. (Véase el ejemplo 3-16.)
Ejemplo 3-16 ArmTesy1.java
package com.scottpreston.javarobot.chapter3;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
import com.scottpreston.javarobot.chapter2.Utils;
public class ArmTest1 {
private BasicArm arm;
public ArmTest1(J SerialPort sPort) throws Exception {
arm =new BasicArm(sPort);
arm.rest();
}
// a posición A
public void toA() throws Exception {
arm.shoulder(50);
Utils.pause(1000);
arm.elbow(200);
}
// a posición B
public void toB() throws Exception {
arm.shoulder(150);
Utils.pause(1000);
arm.elbow(50);
}
// programa simple
public static void main(String[] args) {
try {
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
ArmTest1 arm1 =new ArmTest1(sPort);
arm1.toA();
arm1.toB();
arm1.toA();
sPort.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}


El brazo en el ejemplo siguiente tendrá un servo más que el brazo Lynxmotion de 5 Ejes
anteriormente. Este brazo tendrá un total de seis servos para controlar, y porque esta vez quiero
eliminar el movimiento espasmódico, voy a utilizar el controlador LM32 y la clase. El brazo tiene
los siguientes grados de libertad que se muestra en la Tabla 3-1.
Tabla 3-1 Servos del Brazo y su Descripción
NOMBRE DEL SERVO FUNCIÓN
Servo de Rotación del Hombro Esto hace girar el brazo izquierdo y derecho
alrededor de su base. (Hombro izquierdo-
derecho)
Servo de Altura de Hombro Esto mueve el brazo superior hacia arriba y
hacia abajo junto a su base. (Hombro arriba-
abajo)
Codo Servo Este movimiento del codo hacia arriba y hacia
abajo con respecto tanto a su apéndice apéndice
base para la muñeca. (Bíceps - Tríceps)
Servo de Muñeca Esto mueve la muñeca hacia arriba y hacia
abajo con respecto a su codo.
(Antebrazo)
Servo de Pinza de Rotación Esto hace girar la pinza izquierda y derecha de
la misma manera que la muñeca gira a la
izquierda y la derecha. (Muñeca)
Servo de Pinza Esta se abre y se cierra la pinza. (Dedos)

Objetivos del Código
Los objetivos aquí son los siguientes:
• Para modelar el brazo humano lo mejor que sea posible para que sea fluido y no requiere
una gran cantidad de codificación.
• Para escribir una clase de aplicación similar a lo que hicimos con el grupo básico.
Discusión del Código
Antes de crear la clase ComplexArm, tengo que tener más información disponible no sólo la
posición de un brazo y su número de pin. Para almacenar esta información, extendí la clase
ServoPosition y agregó tres campos adicionales: min, max, y neutral. Esta información adicional le
será útil al mover seis servos ya que nos estamos moviendo lentamente de una posición a otra a
través de una cierta cantidad de tiempo. También tengo que utilizar estas estructuras de datos
debido a que el LM32 utiliza una serie de posiciones de los servos por comando en lugar de
enviarlos por separado. (Véase el ejemplo 3-17.)



Ejemplo 3-17 ServoPosition2.java
package com.scottpreston.javarobot.chapter3;
public class ServoPosition2 extends ServoPosition {
// mínima posición del brazo
public int min;
// máxima posición del brazo
public int max;
// posición neutral del brazo
public int neutral;
public ServoPosition2(int pin) throws Exception {
super(pin,SSCProtocol.NEUTRAL);
min =SSCProtocol.MIN;
max =SSCProtocol.MAX;
neutral =SSCProtocol.NEUTRAL;
}
public ServoPosition2(int pin, int pos, int min, int max) throws Exception{
super(pin,pos);
if (min >255 || min <0) {
throw new Exception("Minimum out of range, 0-255 only.");
}
if (max >255 || max <0) {
throw new Exception("Maximum out of range, 0-255 only.");
}
this.min =min;
this.max =max;
this.neutral =pos;
}
}

La clase ComplexArm en este ejemplo utiliza campos de tipo ServoPosition2. Nombré estos
campos de acuerdo con la extremidad que representan (shoulder1, shoulder2, elbow, y así
sucesivamente). En los servos ArrayList que almacena estas posiciones de los servos para su uso
posterior. En lm32, tengo una instancia de la clase trabajadora LM32. El constructor toma el
J SerialPort y llama al método init(). Init() crea nuevas instancias de las posiciones de los servos y
los agrega a la ArrayList de los servos (es un método separado para un constructor simple). El rest()
en ComplexArm es similar a BasicArm, excepto que en lugar de llamar a cada servo
separadamente, me itera a través de la lista de los servos, crear el comando, y luego llamar a move()
durante un tiempo de 1 segundo. Los métodos de PosA() y posB() tienen posiciones específicas
para cada servo, pero en vez de sacudir a una posición y haciendo una pausa, los movimientos son
lentos durante un tiempo total de 1 segundo El método move() comprueba el intervalo de iteración a
través de la lista y comprueba los límites de los pines. Luego llama a los comandos de movimiento
LM32().
El resultado es el mismo que BasicArm, pero más suave, y con más ejes. (Véase el Ejemplo 3-18.)


Ejemplo 3-18 ComplexArm.java
package com.scottpreston.javarobot.chapter3;
import java.util.ArrayList;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
public class ComplexArm{
// servo positions for differnt servos
// hombro 1
private ServoPosition2 s1;
// hombro 2
private ServoPosition2 s2;
// codo
private ServoPosition2 e;
// muñeca
private ServoPosition2 w;
// grip 1
private ServoPosition2 g1;
// grip 2
private ServoPosition2 g2;
// trabajador LM32
private LM32 lm32;
/ / Lista de servos
private ArrayList servos;
public ComplexArm(J SerialPort serialPort) throws Exception {
lm32 =new LM32(serialPort);
/ / Poner en el método particular para la limpieza
init();
}
private void init() throws Exception {
/ / Note el pasador de posición no se utiliza para el LM32 porque recuerda
/ / La posición
s1 =new ServoPosition2(0);
s2 =new ServoPosition2(1);
e =new ServoPosition2(2);
w =new ServoPosition2(3);
g1 =new ServoPosition2(4);
g2 =new ServoPosition2(5);
// añadir a la colección para facilitar las comprobaciones
servos.add(s1);
servos.add(s2);
servos.add(e);
servos.add(w);
servos.add(g1);
servos.add(g2);
}
public void rest() throws Exception {
for (int i =0; i <servos.size(); i++) {
ServoPosition2 tmpPos =(ServoPosition2) servos.get(i);
lm32.sscCmd(tmpPos.pin, tmpPos.neutral);
}
lm32.move(1000);
}
// mueve a posición A (determinado experimentalmente)
public void posA() throws Exception {
lm32.sscCmd(s1.pin, 50);
lm32.sscCmd(s2.pin, 135);
lm32.sscCmd(e.pin, 75);
lm32.sscCmd(w.pin, 200);
lm32.sscCmd(g1.pin, 150);
lm32.sscCmd(g2.pin, 255);
lm32.move(1000); // move in 1 second
}
// mueve a position B (determinado experimentalmente)
public void posB() throws Exception {
lm32.sscCmd(s1.pin, 220);
lm32.sscCmd(s2.pin, 135);
lm32.sscCmd(e.pin, 100);
lm32.sscCmd(w.pin, 190);
lm32.sscCmd(g1.pin, 130);
lm32.sscCmd(g2.pin, 255);
lm32.move(1000); // move in 1 second
}
private void move(int pin, int pos) throws Exception {
// comprueba el primer rango
checkRange(pin, pos);
// a continuación
lm32.move(pin, pos);
}
// comprobará los servos para ver si la posición solicitada esta
// dentro de los parámetros del servo
private void checkRange(int pin, int pos) throws Exception {
for (int i =0; i <servos.size(); i++) {
ServoPosition2 tmpPos =(ServoPosition2) servos.get(i);
if (tmpPos.pin ==pin) {
if (pos >tmpPos.max || pos <tmpPos.min) {
throw new Exception("Positions out of bounds for pin "
+pin +".");
}
}
}
}
public static void main(String[] args) {
try {
// obtener una sola instancia del puerto serial
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
// crea un nuevo ComplexArm
ComplexArm arm =new ComplexArm(sPort);
arm.rest();
arm.posA();
arm.posB();
sPort.close();
} catch (Exception e) {
// Imprime hasta encontrar en la pila la salida
e.printStackTrace();
System.exit(1);
}
}
}

Resumen De La Sección
El movimiento con un brazo complejo es casi todo lo que necesitará siempre con control servo.
Tenemos un control preciso sobre la posición y la velocidad de movimiento, así como los
movimientos coordinados y precisos.
En esta sección, he creado las siguientes clases:
BasicArm.java: Esta clase modela el brazo robot básico, con un hombro y un codo.
ArmTest1.java: Esta clase explica cómo mover el brazo básico en dos posiciones diferentes.
ServoPosition2.java: Esta clase extiende la clase ServoPosition creado anteriormente para el
mínimo, máximo y valores neutros que se utilizarán en la ComplexArm.
•ComplexArm.java: Esta clase se utiliza la clase ServoPosition2 y cuenta con un total de cinco ejes
de movimiento frente a los dos en el class.Since BasicArm. Puesto que hemos creado una
extremidad en esta sección, dos, cuatro, o seis servos no debería ser mucho más difícil. En la
siguiente sección, te voy a mostrar cómo crear las piernas de la misma manera que hemos creado
brazos y luego me iré a mover todos juntos sin problemas usando el LM32.
3.6 Robots con Patas
Mover un robot con patas es muy similar a la modelización del ComplexArm en la sección 3.5.
Tiene múltiples servos y múltiples posiciones que las piernas necesita. La única cosa que no se
incluye es un modo de andar. El modo de andar en robots con patas es el orden y la dirección de los
movimientos de las piernas. Por ejemplo, un ser humano tiene el paso siguiente:
1. Levante la pierna izquierda hacia arriba.
2. Mueva la pierna izquierda hacia adelante.
3. Ponga la pierna izquierda hacia abajo.
4. Cambie su peso a la pierna izquierda.
5. Levante la pierna derecha hacia arriba.
6. Mueva la pierna derecha hacia adelante.
7. Ponga la pierna derecha hacia abajo.
8. Cambie su peso a la pierna derecha.
9. Repetir.
Esos son nueve comandos de dos piernas en una sola dirección, que es más complicado de lo que
las clases de la unidad diferencial creada en la sección 3.1. Pero debido a que el hexápodo
implementa la interfaz J Motion si nuestro robot tiene patas o ruedas, la navegación será la misma.
Un diagrama de clases para esto se muestra en la Ilustración 3-13. Para tener una mejor idea de lo
que vamos a tener en movimiento, observe la foto en la Figura 3-14. Cuenta con un total de 12
servos, con cuatro grados de libertad por pata para un total de 48 movimientos posibles.

Ilustración 3--13 UML e la Sección 3.6

Ilustración 3-14 Hexapodo Lynxmotion
Objetivos Del Código
El objetivo es implementar J Motion para un robot con patas.
Discusión del Código
Creo que usted encontrará que un robot hexápodo es nada más que algunos brazos complejos que
tienen que trabajar juntos. La clase que sigue los dos grupos de servos de la pierna hexápodo y
añade algunos métodos de movimiento para la pierna. Los dos campos son de tipo ServoPosition2:
uno para el movimiento horizontal y uno para el vertical. El constructor no hace falta ser un
J SerialPort porque a diferencia de la ComplexArm, el partido de ida será sólo una estructura de
datos compleja. Funcionará para establecer y obtener los comandos que se utilizan con el LM32.
Los Métodos de up(), down(), forward() y backwards() establecen los mandatos para las posiciones
predeterminadas definidas por las posiciones de los servos o los valores predeterminados. El
método neural hace lo mismo para los dos servos. (Véase el Ejemplo 3-19.)





Ejemplo 3-19 BasicLeg.java
package com.scottpreston.javarobot.chapter3;
public class BasicLeg {
// cada pata tiene 2 servos
private ServoPosition2 vertServo;
private ServoPosition2 horzServo;
// constructor genérico simplemente toma los pines
public BasicLeg(int vPin, int hPin)throws Exception {
vertServo =new ServoPosition2(vPin);
horzServo =new ServoPosition2(hPin);
}
// constructores con ServoPosition2's
public BasicLeg(ServoPosition2 vertServo, ServoPosition2 horzServo) {
this.vertServo =vertServo;
this.horzServo =horzServo;
}
// mueve la pierna hacia arriba
public String up() {
return LM32.createCmd(vertServo.pin,vertServo.max,LM32.DEFAULT_SPEED);
}
// mueve la pierna hacia abajo
public String down() {
return LM32.createCmd(vertServo.pin,vertServo.min,LM32.DEFAULT_SPEED);
}
// mueve la pierna hacia adelante
public String forward() {
return LM32.createCmd(horzServo.pin,horzServo.max,LM32.DEFAULT_SPEED);
}
// mueve hacia atrás la pierna
public String backward() {
return LM32.createCmd(horzServo.pin,horzServo.min,LM32.DEFAULT_SPEED);
}
// resetea servo horizontal
public String neutralHorz() {
return LM32.createCmd(horzServo.pin,horzServo.neutral,LM32.DEFAULT_SPEED);
}
// resetea servo vertical
public String neutralVert(){
return LM32.createCmd(vertServo.pin,vertServo.neutral,LM32.DEFAULT_SPEED);
}
// restablece los servos
public String neutral() {
return neutralVert() +neutralHorz();
}
}


La clase hexápodo tiene como campos el LM32 como la clase trabajadora y seis patas definidas
como BasicLegs. Yo también definió dos grupos de la pierna como ArrayList. Debido a la marcha
que elegí, me iré a mover tres patas al mismo tiempo. Al poner en una lista, puedo mover todos los
tramos de este grupo con un solo comando.
Los campos UP, DOWN, y así sucesivamente. La velocidad es la variable int velocidad y
MAX_SPEED representa lo el tiempo mínimo que debe ser para el movimiento de grupo de tres
patas. El constructor toma, lo has adivinado, el J SerialPort y llama a dos métodos init() y
setLegGroups(). El método init crea todas las posiciones de las piernas de los seis BasicLegs. El
método setLegGroups los añade a estos métodos legGroup1 y legGroup2.
El paso forward() consiste en una combinación de ocho comandos separados. Los comandos de
marcha se crean mediante el método getTotalMove() que comprende un StringBuffer. El método
funciona mediante la iteración a través de todas las piernas y (en función del comando) devuelve la
cadena del método BasicLeg.motion(). Esto se repite hasta que todas las patas lo hacen. A
continuación, el grupo que se ejecute en el tiempo especificado por el método getSpeedInMs().
El método getSpeedInMs () utiliza una relación inversa entre el tiempo de la pierna en movimiento
y la velocidad. Esto es así que el 10 sigue siendo rápido y 1 sigue siendo lento. Por ejemplo: la
velocidad del robot a la velocidad de 10 es 2500 a 2500 +250 milisegundos por movimiento de un
grupo de la pierna, y a una velocidad de 1 la velocidad del robot es de 2500 a 250 +250 =2500
milisegundos por la pierna.
En el método forward() con un parámetro de milisegundos, recorre llamando hacia adelante hasta
que se acabe el tiempo. Todo esto es una función de la velocidad del robot y que incluso produce
una excepción si el tiempo de desplazamiento solicitado es menor que el tiempo mínimo. (Véase el
ejemplo 3-20.)
Ejemplo 3-20 Hexapod.java
package com.scottpreston.javarobot.chapter3;
import java.util.ArrayList;
import com.scottpreston.javarobot.chapter2.J SerialPort;
import com.scottpreston.javarobot.chapter2.SingleSerialPort;
import com.scottpreston.javarobot.chapter2.Utils;
public class Hexapod implements J Motion {
private LM32 lm32;
private BasicLeg leg1; // left front
private BasicLeg leg2; // left middle
private BasicLeg leg3; // left back
private BasicLeg leg4; // right front
private BasicLeg leg5; // right middle
private BasicLeg leg6; // right back
private ArrayList legGroup1 =new ArrayList();
private ArrayList legGroup2 =new ArrayList();
private static final int UP =0;
private static final int DOWN =1;
private static final int FORWARD =2;
private static final int BACKWARD =3;
private static final int NEUTRAL =4;
private int speed =5;
private static final int MIN_SPEED =250;
public Hexapod(J SerialPort serialPort) throws Exception {
lm32 =new LM32(serialPort);
// 2 métodos para limpiar el constructor
init(); // inicializa las piernas
setLegGroups(); // fijar las patas a los grupos
}
// crea las piernas
private void init() throws Exception {
// 1st posición vertical del servo (up/down)
// 2nd posición horizontal del servo (forward/backward)
leg1 =new BasicLeg(new ServoPosition2(0, 127, 50, 200),
new ServoPosition2(1, 127, 50, 200));
leg2 =new BasicLeg(new ServoPosition2(4, 127, 50, 200),
new ServoPosition2(5, 127, 100, 150));
leg3 =new BasicLeg(new ServoPosition2(8, 127, 50, 200),
new ServoPosition2(9, 127, 50, 200));
leg4 =new BasicLeg(new ServoPosition2(16, 127, 200, 50),
new ServoPosition2(17, 127, 200, 50));
leg5 =new BasicLeg(new ServoPosition2(20, 127, 200, 50),
new ServoPosition2(21, 127, 150, 100));
leg6 =new BasicLeg(new ServoPosition2(24, 127, 200, 50),
new ServoPosition2(25, 127, 200, 50));
}
// poner las piernas en grupos de caminantes
private void setLegGroups() throws Exception {
legGroup1.add(leg1);
legGroup1.add(leg3);
legGroup1.add(leg5);
legGroup2.add(leg2);
legGroup2.add(leg4);
legGroup2.add(leg6);
}
// esto creará una cadena completa de comandos para todos los tramos
public String getTotalMove(ArrayList legs, int cmd) throws Exception {
StringBuffer cmds =new StringBuffer();
for (int i =0; i <legs.size(); i++) {
BasicLeg tmpLeg =(BasicLeg) legs.get(i);
if (cmd ==UP) {
cmds.append(tmpLeg.up());
}
if (cmd ==DOWN) {
cmds.append(tmpLeg.down());
}
if (cmd ==FORWARD) {
cmds.append(tmpLeg.forward());
}
if (cmd ==BACKWARD) {
cmds.append(tmpLeg.backward());
}
if (cmd ==NEUTRAL) {
cmds.append(tmpLeg.neutral());
}
}
return cmds.toString();
}
// Simple movimiento hacia adelante
public void forward() throws Exception {
lm32.setRawCommand(getTotalMove(legGroup1, DOWN));
lm32.move(getSpeedInMs());
lm32.setRawCommand(getTotalMove(legGroup2, UP));
lm32.move(getSpeedInMs());
lm32.setRawCommand(getTotalMove(legGroup2, FORWARD));
lm32.move(getSpeedInMs());
lm32.setRawCommand(getTotalMove(legGroup1, BACKWARD));
lm32.move(getSpeedInMs());
lm32.setRawCommand(getTotalMove(legGroup2, DOWN));
lm32.move(getSpeedInMs());
lm32.setRawCommand(getTotalMove(legGroup1, UP));
lm32.move(getSpeedInMs());
lm32.setRawCommand(getTotalMove(legGroup1, FORWARD));
lm32.move(getSpeedInMs());
lm32.setRawCommand(getTotalMove(legGroup2, BACKWARD));
lm32.move(getSpeedInMs());
}
public static void main(String[] args) {
try {
J SerialPort sPort =(J SerialPort) SingleSerialPort.getInstance(1);
Hexapod hex =new Hexapod(sPort);
hex.forward();
hex.forward();
sPort.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void forward(int ms) throws Exception {
if (getSpeedInMs() * 8 <ms) {
throw new Exception("Speed requested is less than minimum speed.");
}
int remaining =ms;
while (remaining >getSpeedInMs() * 8) {
forward();
remaining =remaining - getSpeedInMs() * 8;
}
Utils.pause(remaining);
}
public void stop() throws Exception {
lm32.setRawCommand(getTotalMove(legGroup1, DOWN));
lm32.setRawCommand(getTotalMove(legGroup2, DOWN));
lm32.move(getSpeedInMs());
}
public void reverse() throws Exception {
}
public void pivotRight() throws Exception {
}
public void pivotLeft() throws Exception {
}
public void reverse(int ms) throws Exception {
}
public void pivotRight(int ms) throws Exception {
}
public void pivotLeft(int ms) throws Exception {
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed =speed;
}
private int getSpeedInMs() {
return (MIN_SPEED* 10) - (MIN_SPEED * speed) +MIN_SPEED;
}
}

Resumen De La Sección
Con las clases creadas en esta sección, le animo a experimentar con sus andares propios o diferentes
números de patas.
En esta sección, he creado las siguientes clases:
• BasicLeg.java: esta clase es similar a la ComplexArm creado en la sección anterior.
• Hexapod.java: Esta clase implementa la interfaz J Motion para mover el robot patas de la
misma manera que lo haría un robot con ruedas.
3.7 Resumen Del Capítulo
Mi objetivo en este capítulo es presentarle a la solución de problemas de movimiento en robótica.
mostré cómo resolver tres tipos de movimiento (ruedas, servo fijo, gaited) con dos tipos diferentes
de servo-controladores: el de Scott Edwards MiniSSC-II y la Lynxmotion SSC-32. Ambos son muy
buenos.Yo uso el MiniSSC-II en mi robot principal Feynman5, y el LM32 en mi hexápodo.
En la sección 3.1, he creado el protocolo SerialSSC y ha creado una super-clase en general, tanto
para los MiniSSC y LM32 clases de implementación. También creamos la clase MiniSSC que puso
a prueba nuestro control servo primero desde el PC.
En la sección 3.2, he creado tres clases de unidades diferenciales para el movimiento de ruedas y
generado una interfaz común que se llama movimiento J Motion.
En la sección 3.3, he utilizado la clase MiniSSC para realizar operaciones de giro e inclinación para
la configuración de una cámara web.
En la sección 3.4, para resolver algunos de los problemas de movimiento experimentado en el
apartado 3.3, que introdujo el servo controlador LM32, así como un nuevo protocolo para el
movimiento llamado GroupMoveProtocol. He implementado este protocolo con el LM32 y la
implementación MiniSscGM
En la sección 3.5, he utilizado la clase LM32 para crear un brazo robótico movimiento fluido con
seis servos.
Por último, en la sección 3.6, he implementado la interfaz J Motion en un robot de seis patas para
demostrar que podríamos utilizar la clase J Motion con un robot de accionamiento diferencial o un
robot piernas alternativamente.
En el próximo capítulo, vamos a dejar de moverse un poco y usar el BASIC Stamp para
comunicarse con algunos de los sensores que pueden utilizar en su robot. No, vamos a discutir las
brújulas digitales, sensores de la lógica, y el sonar y sensores infrarrojos a distancia.