lunes, 29 de octubre de 2012

Robotizando un coche teledirigido con Arduino

Esta es la primera entrega de una serie (espero) de ellas sobre cómo hackear un coche teledirigido y ponerle todos los sensores y cacharros que se nos ocurran.

Por supuesto, empezaremos por el principio: cómo hacer que el coche sea autónomo a través de un Arduino. El elegido en este caso es el Arduino Leonardo, pero vale  casi cualquier otro.

Materiales necesarios:

  • Un coche teledirigido baratillo, de los chinos mismo

  • Una placa Arduino

  • Cuatro resistencias (yo usé de 1K, pero valen de un valor +-50%)

  • Estaño

  • Funda termoretráctil

  • Varios cables de colores (a poder ser) de unos 20cm

  • Una batería de 9V


Herramientas necesarias:

  • Estañador

  • Destornillador

  • Pelacables (o una navaja, en su defecto)

  • Alicates de corte diagonal

  • Desoldador de estaño (no imprescindible, pero sí recomendable)


Pasos a seguir:

1. Desmonta el coche

Photobucket

Photobucket

Photobucket

2. Desatornilla la placa

Photobucket

3. Elimina el circuito integrado, ya que no lo necesitaremos para nada. Para ello tienes dos opciones:

a) Consigues calentar el estaño de sus patitas y lo sacas como Dios manda o...
b) Con los alicates le cortas las patitas por la parte de arriba y lo sacas con unas pinzas. Yo me he decidido por esta segunda opción. ;)

Photobucket

Éste es el aspecto que mostrará cuando las hayas cortado todas:

Photobucket

Photobucket

4. Prepara las resistencias

Lo que vamos a hacer ahora es proteger nuestra placa, por lo que vamos a coger las cuatro resistencias que tenemos (en mi caso de 1K, pero ya digo que el valor no es crítico, pueden ir desde 0,5K a 1,5K) y cuatro cables de colores de unos 10cm de largo, y los vamos a unir formando binomios resistencia-cable:

Photobucket

Cuando ya tengas las parejas hechas, consolida la unión con estaño.

Photobucket

Las cuatro parejas tendrán este aspecto:

Photobucket

Elimina el trozo sobrante con los alicates de corte.

5. Estudia el circuito integrado que desechaste

Fíjate en las letras impresas que tiene encima para poder Googlearlo. Si has comprado un coche en un chino o en algún sitio por el estilo, seguramente tendrás un integrado como este:

http://jumpjack.altervista.org/digitalrome/progetti/macchinina/TX-2C%28RX-2C%29AY.pdf

Lo que se trata es de buscar a qué corresponde cada pata del integrado para poder controlar nosotros a voluntad el coche. Fïjate que en este pdf aparecen tanto las especificaciones del transmisor (el que está en el mando), como del receptor (que es el que nos interesa). Los pines que estamos buscando son los correspondientes a:

  • Tierra (GND)

  • Derecha (RIGHT)

  • Izquierda (LEFT)

  • Marcha atrás (BACKWARD)

  • Hacia delante (FORWARD)


En mi caso, se trata de los pines 2, 6, 7, 10 y 11.

6. Introduce las parejas que preparaste y el quinto cable en los pines que has identificado

Lo que tienes que hacer ahora es, con ayuda del estañador y el desoldador, eliminar las patitas correspondientes a esos pines para poder introducir las resistencias por los agujeros. Procura limpiar bien la zona con el desoldador para que sea más fácil introducir la pata de la resistencia, aunque ya te digo que yo no tenía y no me costó excesivo trabajo dejar la zona presentable).

A continuación, introduce las cuatro resistencias por los pines correspondientes a las dos marchas y a los lados izquierdo y derecho de la siguiente manera:

Photobucket

Puedes observar que la resistencia queda hacia el lado de arriba, y cómo están limpios y preparados el resto de agujeros. Éste es el aspecto que tiene por debajo:

Photobucket

Una vez introduzcas las cuatro resistencias y el quinto cable que tenías apartado, pero aun no habías usado (es el que va en la patilla de GND, efectivamente), estaña los cinco pines y corta el sobrante tanto de las resistencias como del cable de tierra que te sobrará.

Photobucket

Photobucket

Éste es el aspecto que tendrá tu placa entonces:

Photobucket

7. Protegiendo tu placa

Lo que vas a hacer ahora es proteger esas parejas que hemos introducido con la funda termoretráctil. Para ello corta en varios trozos la funda de tal manera que cada trozo cubra totalmente la resistencia, el trozo estañado y un poco del cable. Unos 10-15 cm, vamos. Y como bien dice su nombre, aplícale calor para que se retraiga y se moldee según la resistencia y el cable. Puedes usar desde un mechero o una cerilla a un secador de pelo. Tú mismo. El objetivo es darle un mejor acabado a las conexiones eléctricas y dotar de protección mecánica y anti-abrasiva a los cables y demás componentes eléctricos.

Photobucket

Photobucket

Éste será el aspecto que tendrá finalmente tu placa.

8. Preparando el Arduino

Si no lo has hecho antes, ahora es el momento de anotar a qué color corresponde cada pin. Puedes hacer una tabla como la siguiente (la que resultó en mi caso):

PIN                  COLOR                  FUNCIÓN

2                               Verde                             GND

6                               Gris                                 Derecha

7                               Azul                                Izquierda

10                            Blanco                           Marcha atrás

11                            Amarillo                       Adelante

El código que vamos a preparar es muy sencillo, ya que únicamente se trata de verificar las cuatro funciones: las dos direcciones marcha atrás y adelante, y los dos lados izquierda y derecha. Se trata del siguiente:

[sourcecode language="c"]
/*
Probando las cuatro órdenes del coche
*/

int forward = 12;  // Forward pin
int reverse = 11;  // Reverse pin
int left = 10;     // Left pin
int right = 9;     // Right pin

void setup()       // Configuración de los pines como salidas
{
pinMode(forward, OUTPUT);
pinMode(reverse, OUTPUT);
pinMode(left, OUTPUT);
pinMode(right, OUTPUT);
}

void go_forward()
{
digitalWrite(forward,HIGH);  // Da la orden de adelante
digitalWrite(reverse,LOW);   // Apaga la orden de marcha atrás
}
void go_reverse()
{
digitalWrite(reverse,HIGH);  // Da la orden de marcha atrás
digitalWrite(forward,LOW);   // Apaga la orden de adelante
}
void stop_car()
{
digitalWrite(reverse,LOW);   // Apaga todas las órdenes
digitalWrite(forward,LOW);
digitalWrite(left,LOW);
digitalWrite(right,LOW);
}
void go_left()
{
digitalWrite(left,HIGH);     // Da la orden de izquierda
digitalWrite(right,LOW);     // Quita la orden de derecha
}
void go_right()
{
digitalWrite(right,HIGH);    // Da la orden de derecha
digitalWrite(left,LOW);      // Quita la orden de izquierda
}

void loop()
{

go_forward();
go_left();
delay(500);

stop_car();
delay(500);

go_reverse();
go_left();
delay(500);

stop_car();
delay(500);

go_forward();
go_right();
delay(500);

stop_car();
delay(500);

go_reverse();
go_right();
delay(500);

stop_car();
delay(500);

}
[/sourcecode]

9. Conectando y probando el Arduino

Y por fin llega el último paso: donde por fin pruebas si todo esto funciona. Elimina la antena del coche si no lo has hecho ya (obviamente, no nos hará falta) y atornilla la placa con los tornillos que quitaste en el paso 2.

Conecta los cables según los pines que has declarado en el programa (en mi caso del 9 al 12) y los colores que anotaste antes. El color de tierra lo llevarás al GND de la placa, que como ves en la foto, está junto a los otros cuatro cables (en mi caso, repito):

Photobucket

Para realizar las pruebas de código, o variaciones, te recomiendo que aun no alimentes la placa con una batería, de tal manera que tendrás que tener la placa accesible al USB. Puedes volver a montar el coche y sujetar la placa con una goma elástica, como en mi caso, o dejarlo ya desmontado para introducir la placa y la batería dentro. Ahí según tu elección.

10. Alimentando la placa

Tan sólo falta el toque final: hacer el coche totalmente autónomo. Con el código ya probado ya sabes que se mueve solo, así que sólo falta el tema de la alimentación. Para ello puedes usar una batería normal de 9V, como esta:

Photobucket

Puedes fijarla tanto en el propio chasis del coche (si tienes sitio), como en la carrocería (algo como esto):

Photobucket

La conexión la puedes realizar con un enchufe centro-positivo en el conector de alimentación de la placa, o con unos simples cables como los ya empleados, insertándolos en los pines GND y Vin del conector POWER de la placa. Según tengas el adaptador o no.

El resultado será algo como esto:

[youtube http://www.youtube.com/watch?v=ulftGvqm1LU]

Espero que te haya resultado divertido. Si tienes cualquier pregunta o duda, estamos aquí para ayudarte.

Un saludo y nos vemos en la siguiente entrega! :D

domingo, 22 de julio de 2012

Raspberry Pi and Pandaboard

Raspberry Pi and Pandaboard embedded programming and robotics

[caption id="attachment_707" align="alignleft" width="300"]Pandaboard and Raspberry Pi Pandaboard and Raspberry Pi[/caption]

In a few days [C# part ìt's already here, very soon the starting of the  C++ part] will start a tutorial about programming Pandaboard and Raspberry Pi, specially oriented towars robotics programming using the wonderful Robotis Bioloid kit.

It will try to explain clearly how to install the Raspbian and Ubuntu GNU Linux operating systems and the GNU C++ development environment.

The C++ robotics tutorial will start with a quick introduction to C++, examples using the AX-12 servos, communications using serial port and wireless connections, and, finally, the development of a 6 wheeled hexapod robot, that will be used to introduce advanced techniques like concurrent programming that the new C++ 11 bring to us.

[caption id="attachment_705" align="alignleft" width="300"]HexaWheels_01 HexaWheels_01[/caption]

By the way, Programming -- Principles and Practice Using C++ by Bjarn Stroustrup (the "father of C++) and C++ Concurreny in Action are two great books that cover wide and wisely all these subjects.

A video (excuse me for the poor quality, it willbe improved) with the first steps of the Raspberry Pi based robot

[youtube http://www.youtube.com/watch?v=Yhv43H5Omfc]

viernes, 11 de mayo de 2012

Programacion C con CM-510: leyendo y moviendo Dynamixel AX-12 (III y ultimo)

Programacion C con CM-510: leyendo y moviendo Dynamixel AX-12 (III y último)

Finalizaremos esta primera serie de programación del CM-510 en C moviendo un Dynamixel AX12 en función de los valores leídos con el sensor DMS.

[caption id="attachment_660" align="aligncenter" width="300" caption="DMS sensor"]DMS sensor[/caption]

La función "main" es así de sencilla:
[sourcecode language="c"]
int main(void)
{
int idAX12=4;
int puertoDelSensorDMS=3;

init();

// los dos ejemplos anterior refactorizados en una función

// ordenesDesdeTerminal();
// datosDesdeOtroAX12();

puts("Situaremos el AX12 en la posicion que nos indique el sensor DMS");
ordenesDesdeSensoresPorPasos(idAX12, puertoDelSensorDMS);

// una prueba cruda
//ordenesDesdeSensoresCrudo();

puts("The End");

return 0;
}
[/sourcecode]

Siendo "void ordenesDesdeSensoresPorPasos(int idAX12, int puertoDelSensor)" la función principal del ejemplo:

[sourcecode language="c"]
void ordenesDesdeSensoresPorPasos(int idAX12, int puertoDelSensor)
{
/*
Para evitar las habituales fluctuaciones que sufren los sensores
sólo tendremos en cuenta las diferencias superiores al siguiente valor
entre la anterior lectura y la actual
*/
int minimaDiferencia=25;
int diferencia=0; // la diferencia entre el valor anterior y el actual

int anteriorValor=0; // el anterior valor obtenido del sensor
int valor=0; // el de la lectura actual

while (true)
{
anteriorValor=valor; // guardamos el anterior valor leído del sensor

valor=leerSensor(puertoDelSensor); // leemos el actual

diferencia=anteriorValor-valor;
//printf("n%i", valor); // por si queremos ir viendo los valores que envía el sensor

_delay_ms(100); // una brevisima pausa

// diferencias menores que esta las consideramos fluctuaciones del sensor
if (abs(diferencia)>minimaDiferencia)
{
// utilizamos el valor leído del sensor como posición a situar el AX12
dxl_write_word( idAX12, P_GOAL_POSITION_L, valor);
}
}
}
[/sourcecode]

Utiliza la función leerSensor que tiene cierta dificultad, ya que utiliza la conversión analógico-digital de los microcontroladores ATMega. De momento no entraremos en los detalles, creo que será mejor explicarlo en una próxima serie que trate cuestiones más avanzadas. De todas formas, por si os despierta la curiosidad, os la incluyo a continuación; está basada en los ejemplos de Robotis:

[sourcecode language="c"]
int leerSensor(unsigned char idPuerto)
{
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // ADC Enable, Clock 1/64div.

// printf( "nnIR example for CM-510nn" );

asignarPuerto(idPuerto);
//PORTA &= ~0x80;
//PORTA &= ~0x20;

//_delay_us(12); // Short Delay for rising sensor signal
_delay_us(24);
ADCSRA |= (1 << ADIF); // AD-Conversion Interrupt Flag Clear
ADCSRA |= (1 << ADSC); // AD-Conversion Start

while( !(ADCSRA & (1 << ADIF)) ); // Wait until AD-Conversion complete

PORTA = 0xFC; // IR-LED Off

//printf( "%drn", ADC); // Print Value on USART

//_delay_ms(50);
_delay_ms(esperaLeerSensorMS);

return ADC;
}
[/sourcecode]

Y aquí os podéis descargar el ejemplo completo.

miércoles, 9 de mayo de 2012

Programacion C con CM-510: leyendo y moviendo Dynamixel AX-12 (II)

Programación C con CM-510: leyendo y moviendo Dynamixel AX-12 (II)

En este programa utilizaremos un servo AX-12 para mover otro tal cual movamos el primero. Utilizaremos el ejemplo anterior con algunos cambios para incorporar esta nueva función, como habitualmente ocurre cuando se desarrolla software.

La función que realiza este control es void controlPorAX12(int parametroIdAX12Entrada, int parametroIdAX12Salida):

[sourcecode language="c"]
int esperaMientrasSeSitua(int idAX12)
{
int estado=COMM_TXSUCCESS;
boolean enMovimiento=true;

while (enMovimiento==true)
{
enMovimiento = dxl_read_byte(idAX12, P_MOVING);
estado = dxl_get_result();
if (estado!=COMM_RXSUCCESS)
break;
}

return estado;
}

void controlPorAX12(int parametroIdAX12Entrada, int parametroIdAX12Salida)
{
int posicion=512;

dxl_write_word( parametroIdAX12Entrada, P_GOAL_POSITION_L, posicion);
esperaMientrasSeSitua(parametroIdAX12Entrada);
dxl_write_byte (parametroIdAX12Entrada, P_TORQUE_ENABLE, 0); // quitar toque

dxl_write_word( parametroIdAX12Salida, P_GOAL_POSITION_L, posicion);
esperaMientrasSeSitua(parametroIdAX12Salida);

while(posicion>5 && posicion <1000)
{
posicion = dxl_read_word( parametroIdAX12Entrada, P_PRESENT_POSITION_L );
dxl_write_word( parametroIdAX12Salida, P_GOAL_POSITION_L, posicion );
}
printf ("nFin controlPorAX12 idAXEntrada:%i, posicion: %in", parametroIdAX12Entrada, posicion);
}
[/sourcecode]

Pero previamente hemos de entrar por RoboPlus Terminal el ID del servo AX-12 mando y del que queremos mover.

[sourcecode language="c"]
void datosDesdeOtroAX12()
{
int idAX12Entrada=0;
int idAX12Salida=0;

idAX12Entrada=obtenerId("de entrada");
if (idAX12Entrada!=0)
{
idAX12Salida=obtenerId("de salida");
if (idAX12Salida!=0)
{
printf("nFinaliza llevando el AX12 %i de entrada a su posición inicial (0) o final (1023)n", idAX12Entrada);
controlPorAX12(idAX12Entrada, idAX12Salida);
}
}
}
[/sourcecode]

La función principal (main) quedaría así:

[sourcecode language="c"]
int main(void)
{
init();

// ordenesDesdeTerminal(); el ejemplo anterior refactorizado en una función
datosDesdeOtroAX12();

puts("The End");

return 0;
}
[/sourcecode]

Aquí te puedes descargar el ejemplo completo

lunes, 7 de mayo de 2012

Programming CM-510 with C: reading values from terminal and moving a Dynamixel AX-12

Programming CM-510 with C: reading values from terminal and moving a Dynamixel AX-12

In this post we are going to ask the ID AX-12+ that we want to move and the goal position.

The explanations are in the code as comments, I hope that there are enough comments to understand it, let me know if you can't understand it.

The main loop is that easy:

[sourcecode language="c"]
int main(void)
{
init();

while(true) // we'll repeat this looop forever
{
int id=getId(); // get the ID of the AX-12 that we want to move
int position=getPosition(); // get the goal position
dxl_write_word( id, P_GOAL_POSITION_L, position); // sent the command to the Dynamixel
}

return 0;
}
[/sourcecode]

A brief explanation of printf: printf function is much more powerful than it seems at a first sight, it admits many parameters that allow us to display a large amount of data types and formats. In In the following example %i means that in that position the message will include an integer that will be passed as a parameter after the string "AX12 ID:". The control character "n" means a line break.

Each character in the string is stored in a memory location [A][X][1][2][ ][I][D] strings are a special case of array.

getID and getPosition are also very easy, isn't?

[sourcecode language="c"]
/*
The next functions asks for the ID of the AX-12 to move, checking that the ID is a value between 1 and 18
*/

int getId()
{
/*
We define an array enough large, 256 bytes (characters). Probably it's enough with 4 bytes, but if we type more than the defined size we will get an error*/
char buffer[256];

/*
And we define another integer variable, it's very advisable to asign a value in the definition, in this case we assign the minimun value, 1*/
int ax12Id=1;

// puts is very similar to printf, it shows the string that it receives as parameter
puts ("nnMoving a Dynamixel");

do
{ // starting the loop
puts ("Enter the ID of the AX-12 that you wwant to move, between 1 y 18, ");
ax12Id=readInteger(buffer); // this function will read from what we type in the keyboard
//// exclamation (!) is the NOT logical operator. It will repeat the loop while the value is not valid
}while(!isValid(ax12Id, 1, 18));

// Showing the typed value
printf("AX12 ID: %in", ax12Id);

return ax12Id;
}

// Now we will repeat almost the same code that above, it should be pretty easy to write a reusable function, isn't?

int getPosition()
{
char buffer[256];
int position=0;

do
{
puts ("Enter a value between 0 and 1023 as the goal position");
position=readInteger(buffer);
}while(!isValid(position, 0, 1023));

printf("nPosition: %in", position);

return position;
[/sourcecode]

The functions used to read the text from the Terminal are quite interesting, showing the use of a string. It also shows how to use the .h file (declaration) and the .c (definitions, the content of the functions):

[sourcecode language="c"]
// Body (content) of the functions that read data

/*
Recibimos una variable que tiene reservado espacio en memoria para almacenar
la cadena introducida
*/

void readString(char bufferParameter[])
{
int i=0; // We'll use this variable as index of the buffer where we will store data
do
{
bufferParameter[i]=getchar(); // it store the read character in the i position of bufferParameter
putchar(bufferParameter[i]); // showing it
if (bufferParameter[i]=='b') // if Backspace was pressed
i--; // it goes to the previous position, rewritting the previoulsy typed character
else //
i++; // it will write in the next position
}while(bufferParameter[i-1]!='n'); // while the last values is not INTRO. The symmbol ! represents the logical operator NOT

bufferParameter[i]=0; // A NULL (0, zero) is necessary in the last position of any string
}

/*
It read an string, it's converted to integer and returned
*/
int readInteger(char bufferParameter[])
{
readString(bufferParameter);
return atoi(bufferParameter);
}
[/sourcecode]

You can download the sourcecode here

The language C, also C++, has some very interesting features such as the inclusion of code depending on certain conditions. This lets you use the same code for different processors by simply changing one or more parameters.

As an example, this ZIP contains a project for Dev-CPP with a version of the source files for the PC and the CM-510; simply commenting or uncommenting a line in the file "myCM510.h" (for AVR Studio you should create the appropriate project and include the sources files).

Instead of moving AX-12 it displays the text "dxl_write_word" with the parameters received. We can practice C and perform different tests on the PC without connecting any servo.

sábado, 5 de mayo de 2012

Programacion C con CM-510: leyendo y moviendo Dynamixel AX-12 (I)

Programación C con CM-510: leyendo y moviendo Dynamixel AX-12 (I)

Como segunda entrega de este taller de programación de Bioloid vamos a realizar un programa que nos pedirá el identificador (ID) del AX-12+ a mover y la posición en la que lo situaremos.

Las explicaciones las he ido incluyendo en el código como comentarios, espero que los comentarios sean suficientes como para poderlo seguir, ya me diréis si es así.

El bucle principal es así de sencillo:

[sourcecode language="c"]

int main(void)
{
init();

while(true) // repetiremos eternamente este bucle
{
int id=obtenerId(); // obtenemos el ID del AX-12 a utilizar
int posicion=obtenerPosicion(); // obtenemos la posición en la que situar el AX-12 seleccionado
dxl_write_word( id, P_GOAL_POSITION_L, posicion); // enviamos la orden al Dynamixel
}

return 0;
}

[/sourcecode]

Unas breves explicaciones sobre printf: La función printf es mucho más potente de lo que parece a primera vista, admitiendo bastantes parámetros que nos permiten mostrar una gran cantidad de tipos de datos y formatos diferentes. En el siguiente ejemplo %iindica que en dicha posición del mensaje se incluirá un entero que le pasaremos como parámetro a continuación de la cadena "ID del AX12:". El carácter de control "n" indica que incluya un salto de línea.

Cada carácter de la cadena se almacena en un posición de memoria [I][D][ ][d][e][l]... siendo las cadenas un caso especial de vector o, en inglés, "array".

Descárgate aquí una presentación en PDF con explicaciones muy detalladas sobre cadenas en C, de la Universidad del País Vasco.

Las funciones obtenerId() y obtenerPosicion() son también bastante sencillas, ¿verdad?

[sourcecode language="c"]

/*
La siguiente función solicita la entrada de un valor para seleccionar el ID del Dynamixel al que
enviar las órdenes, Comprobando que el que esté entre 1 y 18
*/

int obtenerId()
{
/*
Creamos una variable de un tamaño amplio, 256 bytes (posiciones de un carácter), aunque con 4
valdría, pero si se introdujeran más carácteres de los definidos provocaría un error.
*/
char cadena[256];

/*
Y otra variable de tipo entero, es recomendable asignar siempre un valor, en este caso
la inicializamos con el valor mínimo, 1
*/
int ax12Id=1;

// puts es muy similar a printf, muestra la cadena que recibe como parámetro por la pantalla
puts ("nnVamos a mover un Dynamixel a voluntad. V02");

do
{    // inicio del bucle
puts ("Introduce el ID del servo a mover, entre 1 y 18, ");
ax12Id=leerEnteroComoCadena(cadena); // llamamos a esta función  para entrar por pantalla el valor
//// la admiración (!) es el operador lógico NOT. Repetiremos el bucle mientras el rango NO se valido
}while(!enRangoValido(ax12Id, 1, 18));

// Mostramos el valor introducido
printf("ID del AX12: %in", ax12Id);

return ax12Id;
}

// Repetiremos prácticamente el mismo código que la función anterior, ¿sería fácil crear una función reutilizable para ambos, verdad?
int obtenerPosicion()
{
char cadena[256];
int posicion=0;

do
{
puts ("Introduce un valor entre 0 y 1023 para situarlo en esa posicion");
posicion=leerEnteroComoCadena(cadena);
}while(!enRangoValido(posicion, 0, 1023));

printf("nPosicion: %in", posicion);

return posicion;
}
[/sourcecode]

Las funciones utilizadas para leer el texto de la consola son bastante interesantes,
ya que nos muestran la utilización de una cadena. También nos muestra como utilizar
los fichero .h (declaraciones) y .c (definiciones, el contenido de las funciones):

[sourcecode language="c"]
// Cuerpo (contenido) de las funciones de entrada de datos

/*
Recibimos una variable que tiene reservado espacio en memoria para almacenar
la cadena introducida
*/

void leerCadena(char parametroCadena[])
{
int i=0; // Utilizaremos esta variable como índice para ir almacenando los caracteres introducidos
do
{
parametroCadena[i]=getchar();  // almacenamos el carácter obtenido en la posición i de parametroCadena
putchar(parametroCadena[i]);   // lo mostramos por pantalla
if (parametroCadena[i]=='b')  // si se ha pulsado la tecla <Borrar> (justo encima de <Intro>)
i--;                       //    nos situamos en la posición anterior para escribir de nuevo sobre ella
else                           // si no
i++;                       //    escribiremos en la siguiente posición
}while(parametroCadena[i-1]!='n'); // mientras el último valor guardado NO sea INTRO. El símbolo ! representa el operador NOT
parametroCadena[i]=0;           // en la última posición de una cadena ha de estar el valor cero (NULO, null en Inglés)
}

/*
Leemos una cadena, la convertimos a entero y devolvemos el valor obtenido
*/
int leerEnteroComoCadena(char parametroCadena[])
{
leerCadena(parametroCadena);
return atoi(parametroCadena);
}
[/sourcecode]

El código fuente entero os lo podéis descargar desde aquí.

El lenguaje C, también C++, tiene algunas características muy interesantes, como la inclusión de código dependiendo de determinadas condiciones. Esto permite utilizar el mismo código fuente para distintos procesadores, simplemente cambiando uno o varios parámetros.

A modo de ejemplo este ZIP contiene un proyecto preparado para Dev-CPP con una versión de los ficheros fuente válida para PC y para CM-510; simplemente comentando o descomentando una línea del fichero "myCM510.h" (para utilizarlo con AVR Studio se ha de crear el correspondiente proyecto e incluir estos fuentes).

En lugar de mover el servo AX-12 muestra en pantalla el texto "dxl_write_word" con los parámetros recibidos. Podemos practicar C y realizar distintas pruebas en el PC sin conectar ningún servo.

[sourcecode language="c"]

// Si no está comentada la siguiente línea podremos compilar el programa para PC
// Si está comentada la siguiente línea podremos compilar el programa para CM-510
#define __PC_TEST_

[/sourcecode]

martes, 1 de mayo de 2012

Bioloid CM-510 programming tutorial: First steps with C

Bioloid programming workshop: First steps with C

(En español)

This brief post starts the Bioloid programming workshop, using ​C, C + + and C# languages  and different controllers: ATMega (CM-510), PC, SBC.

The first steps in C programming

C language is a simple, powerful and extremely versatile tool used to develop software for industries as diverse as the automobile , medical equipment or for the software industry itself, from Microsoft Office to operating systems like Windows or Linux.

This will be a very practical programming workshop with Robotis Dynamixel servos, so I will include links tutorials anb books that include broader and deeper explanations, like C introduction (pdf). But there are a lot:

C Language Tutorial (html)
How C Programming Works (html)
Several C programming tutorials (html)

One of the simplest programs in C:

[sourcecode language="c"]
// This line that begins with two slashes is a comment

/*
These others, starting with a slash and an asterisk
are a comment too, ending with another asterisk and a slash.

The comments are very useful for explaining what we do and,
especially, why we do so, because after a few months we will not remember the details.
*/

/*
The includes are useful to announce the compiler that we will use
existing functions from other files, such as stdio.h, in this example,  to get
the printf function to display information on screen.
(This is not exactly true, but more on that later)
*/
#include

/*
This is one way to start a C program,
Creating the main function as the starting point of every C program:
*/
void main ()

// The body or content of the function starts with the following curly bracket
{

// Guess what does the following function?
printf ("Hello, World");

// And, predictably, the function ends with the closing curly bracket
}
[/sourcecode]

Now we will write the first program for the CM-510

But previously you should install the software needed to program the CM-510. If you install WinAVR in "C:tools WinAVR-20100110" you can download a zip with everything ready to use.

After loading our program in the CM-510, to use RoboPlus Tasks, Motion RoboPlus Robotis and other programs, we will have to restore Robotis firmware.

[sourcecode language="c"]
# Include stdio.h
# Include "myCM510.h"

executeMovement1 void (int ax12Id)
{
dxl_write_word (ax12Id, P_GOAL_POSITION_L, 512);
}

executeMovement2 void (int ax12Id)
{
dxl_write_word (ax12Id, P_GOAL_POSITION_L, 600);
}

int main (void)
{
ax12Id int = 6;

init ();

printf ("\r \n A simple example");

printf ("\r \n Perform movement 1 with the AX-12% i", ax12Id);
executeMovement1 (ax12Id);

printf ("\r \n Pause half a second");
_delay_ms (500); // half-second pause

printf ("\r \n Beep!");
buzzOn (100); // beep

printf ("\r \n Pause for a second");
_delay_ms (1000); // pause for 1 second

printf ("\r \n Perform movement 2 with the AX-12% i", ax12Id);
executeMovement2 (ax12Id);

printf ("\r \n End");
}
[/sourcecode]

The characters "\r \n" are used to jump to the next line in Windows.

If you have installed the necessary software (WinAVR must be installed in "C:tools WinAVR-20100110") and unzip this zip file in the root directory (C: ) you have to be ready to modify, compile, or simply load the executable "hello_world.hex" in the CM-510. You will see something similar to:

[caption id="attachment_584" align="aligncenter" width="300"]01_Hello_World_CM-510 01_Hello_World_CM-510[/caption]

Some explanations
dxl_write_word (ax12Id, P_GOAL_POSITION_L, 600);

This function is included in the Robotis CM-510 libraries allowing us to send commands to a Dynamixel actuator very easily. We only have to indicate the ID of the AX-12 to move (ax12Id), the code of the order that the AX-12 should execute, in this case go to the goal position (P_GOAL_POSITION_L), and the position in which has to be placed between 0 and 1024 (600 in the example).

dx_series_goal


Highlights:

Decompose the program into different parts

  •     Having previously created the init () function in myCM510.h/myCM510.c allows us to include it easily in this program.

  •     In addition to simplifying programming we can reuse the same code in different programs. This saves us from having to repeat the same code many times and, especially, have to correct faults or improve in only one point, . Later we will see how to organize directories and even how to create libraries.

  •     It also allows us to encapsulate the details, so that when the program starts growing we can handle them easily without being overwhelmed.


Showing what is doing running the program


Using the printf function we can send text to the screen that lets us know what is doing the program (printf sends to the serial port, "RoboPlus Terminal" read it  and displays it on the screen. We will lear how to read from the serial port when we start programming Bioloid using a PC or SBC)

Can you think of an easy way to avoid having two similar functions such as "void executeMovement1 (int ax12Id)" and "void executeMovement2 (int ax12Id)"?

sábado, 28 de abril de 2012

Programacion C con CM-510: vectores (arrays), puertos y LEDs

Programanción C con Bioloid CM-510: "arrays", puertos y LEDs

Cadenas y Vectores ("Strings y Arrays)


Una de las formas más habituales y fáciles de manejar un conjunto de datos en C, y en muchos otros lenguajes como C++, Java y C#,  es mediante cadenas y vectores.

Cadenas

Una cadena consiste en un conjunto de caracteres, como las que utilizamos en el programa "holaMundo.c" del anterior artículo:

[sourcecode language="c"]

int main(void)
{
int ax12Id=6;

init();

printf("rn Un sencillo ejemplo");

...
}
[/sourcecode]

A la función printf le pasamos como parámetro la cadena "rn Un sencillo ejemplo"
printf("/r/n Un sencillo ejemplo");

En este caso no hemos utilizado ninguna variable para almacenarla, sino que se la hemos pasado directamente, como un literal. Si quisiéramos utilizar dicha cadena en distintas partes la hubiéramos almacenado en una variable, aunque también existen otras razones para utilizar no utilizar literales en el código, como agruparlas en un único punto para facilitar su localización o su traducción).
char titulo[]="Un sencillo ejemplo";

printf("rn %s", titulo);

Unas breves explicaciones sobre printf: La función printf es mucho más potente de lo que parece a primera vista, admitiendo bastantes parámetros que nos permiten mostrar una gran cantidad de tipos de datos y formatos diferentes. En este caso %s indica que en dicha posición del mensaje se incluirá una cadena que le pasaremos como parámetro a continuación, "titulo" en este ejemplo.

Cada carácter de la cadena se almacena en un posición de memoria [U][n][ ][s][e][n]... siendo las cadenas un caso especial de vector o, en inglés, "array".

Descárgate aquí una presentación en PDF con explicaciones muy detalladas sobre cadenas en C, de la Universidad del País Vasco.

Vectores

Un vector es probablemente la forma más sencilla de manejar o almacenar un conjunto de datos. En el ejemplo que viene a continuación utilizaremos el siguiente vector de enteros:

int pin[]={1,2,4,8,16,32,64};

Aunque quizás sea más claro si utilizamos la forma "completa", en lugar de la abreviada, de cargar datos:
int pin[7] //  creamos un vector con 7 posiciones de memoria para almacenar un entero (int)

int[0]=1; // vamos asignando cada valor... ¡Ojo, que el primero es la posición 0 (cero)!

int[1]=2;

int[2]=4;

int[3]=8;

int[4]=16;

int[5]=32;

int[6]=64;

Descárgate aquí una presentación en PDF con explicaciones muy detalladas sobre vectores en C, también de la Universidad del País Vasco.

Los puertos de los microcontroladores

Probablemente el elemento más característico de los microcontroladores son los puertos de Entrada/Salida E/S (Input/Output, I/O en inglés), con los cuales podemos enviar y recibir información para controlar distintos elementos electrónicos como sensores, actuadores y LEDs.

El controlador de Robotis CM-510 nos ofrece 6 conexiones donde podremos utilizar los puertos de entrada salida que el microcontrolador ATMega 2561 (página en inglés del fabricante ATMEL) incorpora.

[caption id="attachment_449" align="alignnone" width="300"]Controlador CM-510 Controlador CM-510[/caption]

Cada puerto se controla mediante tres registros (un registro es básicamente una zona de memoria):

  • DDRx: donde se indica si se enviarán o recibirán datos

  • PINx: aquí se reciben los datos

  • PORTx: y desde aquí se envían los datos al exterior del microcontrolador


Para manejar los puertos se han de utilizar los operadores de C a nivel de bits para activar y desactivar cada uno de los bits que representan los puntos de conexión (PIN) que componen los puertos. Estas operaciones utilizan los mismos operadores booleanos que las puertas lógicas y tablas de verdad

[caption id="attachment_461" align="alignnone" width="165"]tabla y puerta or tabla y puerta or[/caption]

[caption id="attachment_460" align="alignnone" width="167"]tabla y puerta and tabla y puerta and[/caption]

Mediante los puertos podremos controlar los LEDs y podremos comprobar si está pulsado alguno de los botones. Por ejemplo:

// El puerto se inicializa con los valores a 1, 1111 1111 ó 0x7F en hexadecimal. OJO 1 (uno) es LED apagado, 0 (cero) es encendido.

// Al ejecutar:
PORTC &= ~0x01; // el complementario de 0000 0001 es 1111 1110

/* la operación AND entre
1111 1111       el puerto C
1111 1110       y el valor complementario de 0000 0001
--—- —---
1111 1110       el resultado es que sólo el LED 1 estará encencido

Son operaciones sencillas pero en las cuales es fácil equivocarse. Las funciones son uno de los elementos fundamentales de C para encapsular los detalles y, una vez comprobado que funcionan perfectamente, “olvidarnos” de ellos:

[sourcecode language="c"]
int pin[]={1,2,4,8,16,32,64};

void encenderYapagarLEDs()
{
for (int i=0;i<=6;i++)
{
ledOn(pin[i]); //enciende LED
_delay_ms(500); // una pausa de medio segundo
ledOff(pin[i]); // apaga LED
}
}
[/sourcecode]

teniendo definido previamente, claro:

[sourcecode language="c"]
void ledOn(unsigned char ledId)
{
PORTC &= ~ledId;
}

void ledOff(unsigned char ledId)
{
PORTC |= ledId;
}
[/sourcecode]

Habitualmente en lugar de funciones se utiliza #define, pero creo que ahora es mucho más claro utilizar funciones. Por cierto, ¿por qué utilizo al array "int pin[]={1,2,4,8,16,32,64};"?, ¿de qué otras formas se puede hacer?

jueves, 26 de abril de 2012

Taller de programacion Bioloid: Primeros pasos en C

Taller de programación Bioloid: Primeros pasos en C

[This post is also in English]

Con este breve artículo comenzamos el taller de programación Bioloid con distintos lenguajes (C, C++ y C#) y en distintos entornos (ATMega, PC, SBC). Partiendo prácticamente de cero y hasta donde nos lleguen las fuerzas.

Los primeros pasos los daremos en C

C es un lenguaje sencillo, potente y extremadamente versátil con el que se desarrolla una gran cantidad de software para industrias tan diferentes como la del automóvil (enlace a traducción automática), el equipamiento médico o para la propia industria del software, desde Microsoft Office hasta sistemas operativos como Windows o Linux. (está en inglés pero se entiende fácilmente porque es una tabla de productos software bastante conocidos y lenguajes de programación utilizados).

Como va a ser un taller de programación muy práctico y dirigido a la programación de los servos Dynamixel de Robotis incluyo un enlace a un completo y popular libro Aprenda ANSI C como si estuviera en primero; si quieres una introducción más rápida descárgate esta presentación de 13 páginas, y aquí el documento con el estándar completo en inglés, pero ten en cuenta que es denso y no lo he encontrado en castellano.

{ Actualización:

He descubierto este estupendo y detallado curso de introducción a la programación con lenguaje C de la Universidad del País Vasco dirigido a personas que no tengan ningún conocimiento previo de programación.

Introducción a la programación con C, libro/curso de la UOC (Universidad abierta de Cataluña) práctico y muy fácil de seguir.

}

Uno de los programas más sencillos en C:

[sourcecode language="c"]
// Esta línea que empieza por dos barras inclinadas es un comentario

/*
Igual que éstas, que empiezan con una barra inclinada y un asterisco
y seguirá siendo un comentario que finaliza con otro asterisco y otra barra inclinada.

Los comentarios son muy útiles para realizar explicar qué vamos a hacer y,
especialmente, por qué lo hacemos así, ya que pasados unos meses no recordaremos los detalles.
*/

/*
Los includes nos sirven para anunciar al compilador que vamos a utilizar
funciones existentes en otros ficheros, como stdio.h, que en este ejempo
nos proporcionará la función printf para poder mostrar información en la pantalla.
(Esto no es exactamente así, pero ya lo veremos más adelante)
*/
#include

/*
Ésta es una de las formas de empezar un programa en C,
Creando la función principal (main) que todo programa en C necesita para empezar
*/
void main()

// El cuerpo o contenido de la función empieza con la siguiente llave
{

// ¿Adivinas qué hace la siguiente función?
printf ("Hola, Mundo");

// y, previsiblemente, la función acaba con esta otra llave
}
[/sourcecode]

Prueba a hacer algunas modificaciones en esta web, "output" es lo que mostraría el programa en la pantalla, "submit" significa enviar y simula la ejecución del programa. Si te equivocas te indicará los errores, también te puede mostrar "warnings", avisos.

Ahora realicemos el primer programa para el CM-510

Pero antes instalaremos el software necesario para programar el CM-510 (inglés). Si instalas WinAVR en "C:herramientasWinAVR-20100110" te podrás descargar un zip con todo preparado.

Cuando queramos volver a utilizar los programas RoboPlus Tasks, RoboPlus Motion y demás programas de Robotis deberemos cargar de nuevo el firmware de Robotis, restaurar firmware del CM-510 (inglés)

[sourcecode language="c"]
#include
#include "myCM510.h"

void ejecutarMovimiento1(int ax12Id)
{
dxl_write_word( ax12Id, P_GOAL_POSITION_L, 512);
}

void ejecutarMovimiento2(int ax12Id)
{
dxl_write_word( ax12Id, P_GOAL_POSITION_L, 600);
}

int main(void)
{
int ax12Id=6;

init();

printf("/r/n Un sencillo ejemplo");

printf("/r/n Realizar movimiento 1 con el AX-12 %i", ax12Id);
ejecutarMovimiento1(ax12Id);

printf("/r/n Pausa de medio segundo");
_delay_ms(500); // una pausa de medio segundo

printf("/r/n Pitido!");
buzzOn(100); // pitido

printf("/r/n Pausa de un segundo");
_delay_ms(1000); // una pausa de 1 segundo

printf("/r/n Realizar movimiento 2 con el AX-12 %i", ax12Id);
ejecutarMovimiento2(ax12Id);

printf("/r/n Fin");
}
[/sourcecode]

Los carácteres "/r/n" se utilizan para saltar a la siguiente línea en Windows.

Si has instalado el software necesario (WinAVR debe estar instalado en "C:herramientasWinAVR-20100110") y descomprimes el fichero TallerProgramacionBioloid_01.zip en el directorio raíz (C:) has de tener todo listo para poder modificar, compilar o simplemente cargar el ejecutable "hola_mundo.hex" en el CM-510. Has de ver algo similar a:

[caption id="attachment_381" align="alignnone" width="300"]01_Hola_Mundo_Salida_RoboPlus_Terminal 01_Hola_Mundo_Salida_RoboPlus_Terminal[/caption]

Algunas explicaciones
dxl_write_word( ax12Id, P_GOAL_POSITION_L, 600);

Es el comando incluído en las librerías de Robotis para CM-510 que nos permite enviar órdenes a un actuador Dynamixel de forma muy sencilla. Sólo le tenemos que indicar el ID del AX-12 a mover (en ax12Id), el código de la órden que el AX-12 ha de ejecutar, en este caso situarse en una posición determinada (P_GOAL_POSITION_L) y la posición en la que se ha de situar entre entre la 0 y la 1024 (600).

[caption id="attachment_416" align="alignnone" width="300"]dx_series_goal dx_series_goal[/caption]

Puntos principales:

Descomponer el programa en distintas partes

  • Al haber creado previamente la función init() en myCM510.h/myCM510.c nos permite incluirla en este programa simplificandolo mucho.

  • Además de simplificar la programación permite reutilizar el mismo código en distintos programas. Lo cual nos evita tener que repetir el mismo código muchas veces y, sobre todo, tener que corregir los fallos o mejorarlo sólo en un único sitio, no en todos los programas que se ha repetido. Más adelante veremos cómo organizar los directorios e incluso cómo crear librerías.

  • También nos permite encapsular los detalles de forma que cuando el programa empiece a crecer podamos manejarlos con facilidad sin que nos veamos desbordados.


Mostrar qué está ejecutando el procesador

  • Mediante la función printf podemos enviar a la pantalla texto que nos permite saber qué es lo que está haciendo el programa (printf lo envía al puerto serie y "RoboPlus Terminal" lee de éste y lo muestra por pantalla. Aprenderemos a hacerlo cuando empecemos a programar Bioloid desde el PC)


¿Se te ocurre una forma sencilla de evitar tener dos funciones tan parecidas como "void ejecutarMovimiento1(int ax12Id)" y "void ejecutarMovimiento2(int ax12Id)"?

lunes, 9 de abril de 2012

Learning scurves with AX-12

I'm learning how to use scurves with AX-12, so I've created a test CM-510 C program where I try different approachs. Any help will be very well received, because my goal is to control several AX-12 and I'm far far away from it!

Here is the program with an spreadsheet with the calculations (LibreOffice and Excel). I have started from an old post from Bullit in the Tribotix forum (now in PDF format at Robosavvy)

Clockwise is the standard motion, counter clockwise is the scurve intended motion

[youtube http://www.youtube.com/watch?v=YBdO0232QvQ]

lunes, 5 de marzo de 2012

Linux C++ Dynamixel reading and writing example

If you will like to use some boards like Raspberry or Beagleboard C++ is a great choice. So here you have a working Linux C++ Dynamixel reading and writing example. The main difference is the serial port access:

Here you can download the Eclipse project zipped

Here you can find several combinations of hardware, firmware and programming tools.

The main body


[sourcecode language="cpp"]
#include <iostream>
using namespace std;

#include "SerialPort.h"
#include "Dynamixel.h"

int main() {
cout << "AX Control starts" << endl; // prints AX Control

int error=0;
int idAX12=18;

SerialPort serialPort;
Dynamixel dynamixel;

if (serialPort.connect("//dev//ttyS0")!=0) {
dynamixel.sendTossModeCommand(&serialPort);

int pos=dynamixel.getPosition(&serialPort, idAX12);

if (pos>250 && pos <1023)
dynamixel.setPosition(&serialPort, idAX12, pos-100);
else
printf ("nPosition <%i> under 250 or over 1023n", pos);

serialPort.disconnect();
}
else {
printf ("nCan't open serial port");
error=-1;
}

cout << endl << "AX Control ends" << endl; // prints AX Control
return error;
}
[/sourcecode]

Header


[sourcecode language="cpp"]
#ifndef SERIALPORT_H_
#define SERIALPORT_H_

#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>

class SerialPort {
private:
int fileDescriptor;

public:
int connect ();
int connect (char * device);
void disconnect(void);

int sendArray(unsigned char *buffer, int len);
int getArray (unsigned char *buffer, int len);

int bytesToRead();
void clear();
};

#endif /* SERIALPORT_H_ */
[/sourcecode]

Body:


[sourcecode language="cpp"]
#include <string.h>
#include <sys/ioctl.h>

#include "SerialPort.h"

int SerialPort::connect() {
return connect("//dev//ttyS0");
}

int SerialPort::connect(char *device) {
struct termios terminalAttributes;

/*
* http://linux.die.net/man/2/open
*
* Open the serial port
* read/write
* not become the process's controlling terminal
* When possible, the file is opened in nonblocking mode
*
*/
fileDescriptor = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_FSYNC );

// clear terminalAttributes data
memset(&terminalAttributes, 0, sizeof(struct termios));

/*    http://linux.die.net/man/3/termios
*
*  control modes: c_cflag flag constants:
*
* 57600 bauds
* 8 bits per word
* Ignore modem control lines.
* Enable receiver.
*/

terminalAttributes.c_cflag = B57600 | CS8 | CLOCAL | CREAD;

/*
* input modes: c_iflag flag constants:
*
* Ignore framing errors and parity errors.
* (XSI) Map NL to CR-NL on output.
*/
terminalAttributes.c_iflag = IGNPAR |  ONLCR;

/*
* output modes: flag constants defined in POSIX.1
*
* Enable implementation-defined output processing.
*/

terminalAttributes.c_oflag = OPOST;

/*
* Canonical and noncanonical mode
*
* min time
* min bytes to read
*/

//terminalAttributes.c_lflag = ICANON;
terminalAttributes.c_cc[VTIME] = 0;
terminalAttributes.c_cc[VMIN] = 1;

/*
* http://linux.die.net/man/3/tcsetattr
* Set the port to our state
*
* the change occurs immediately
*/

tcsetattr(fileDescriptor, TCSANOW, &terminalAttributes);

/*
* http://linux.die.net/man/3/tcflush
*
* flushes data written but not transmitted.
* flushes data received but not read.
*/

tcflush(fileDescriptor, TCOFLUSH);
tcflush(fileDescriptor, TCIFLUSH);

return fileDescriptor;
}

void SerialPort::disconnect(void)
{
close(fileDescriptor);
printf("nPort 1 has been CLOSED and %d is the file descriptionn", fileDescriptor);
}

int SerialPort::sendArray(unsigned char *buffer, int len) {
int n=write(fileDescriptor, buffer, len);
return n;
}

int SerialPort::getArray (unsigned char *buffer, int len)
{
int n1=bytesToRead();
int n=read(fileDescriptor, buffer, len);
return n;
}

void SerialPort::clear()
{
tcflush(fileDescriptor, TCIFLUSH);
tcflush(fileDescriptor, TCOFLUSH);
}

int SerialPort::bytesToRead()
{
int bytes=0;
ioctl(fileDescriptor, FIONREAD, &bytes);

return bytes;
}
[/sourcecode]

jueves, 16 de febrero de 2012

Programming Lego Mindstorms NXT

Lego Mindstorms NXT is a great kit that allow you to build and program an almost unlimited variety of robots and automatisms.

NXT brick

Mindstorms NXT

The kit includes a "brick" that includes a programmable 32 bits microcontroller. Lego open sourced the software and the hardware of NXT, here you can find all the documents and source code.

You can program its microcontroller with the included visual programming tool, called NXT-G, that is very easy to use for small programs but probably you will find it too much limited, specially if you can program in other programming language. But don't worry, you can use standard and professional programming languages like Java, C or C++ among others. All them free as in beer and as in speech.

Just a few words about which, in my opinion, are the best options:

C like language: NXC

Apart from NXT-G the easiest way for programming NXT is NXC. It's a language similar to C, very easy to learn and you don't should change the NXT Lego firmware, so you can continue using NXT-G.

Java: Lejos

If you know or want to learn Java this is your tool. I think that is the best tool, more difficult that NXC but far more powerful.

C/C++: NXT OSEK

Do you want to learn C or C++? Real time programming? This is your tool!

martes, 7 de febrero de 2012

Choose hardware, firmware and language

There are a lot of possible combinations of hardware, firmware and languages for programming Bioloid. I think that the table below show the the main combinations.

You can choose from the easy but limited Robotis own tool (Roboplus Task) and only your CM-5 or CM-510 to a SBC or "embedded" PC like Roboard and any language which can manage a serial port connection, like C, C++, Java, Python,...

Linux C++ Dynamixel reading and writing example

C# Dynamixel reading and writing example

Practical C++ programming tutorial for Bioloid

[caption id="attachment_256" align="aligncenter" width="617"]Programming Bioloid: choose hardware, firmware and languages Programming Bioloid: choose hardware, firmware and languages[/caption]

Robotis officially supports the programming solutions with the blue background:

  • The dark blue, RoboPlus Tasks, is the only one in which you can create the motions with RoboPlus Motion and execute it in CM-5/CM-510 with the program create with RoboPlus Tasks, after downloading the generated executable into the CM-5/CM-510, of course.



With these programming solutions you can use the Zigbee SDK to send and receive data between the CM5-/CM-510 and any computer, using Zig-110A or the new bluetooth BT-110, the Zig2Serial and the USB2Dynamixel. You can download example in Visual Basic .Net, C# and Visual C++

But there are more options!

Using a PC, SBC (Single Board Computer), PDA, Mobile or other light and battery powered computer

Using a serial port connection with your more beloved programming language:

  • USB2Dynamixel


If you have any device with a USB host and a FTDI driver you can use USB2Dynamixel to command programatically your Dynamixel servos using the Dynamixel protocol. You only will need your CM-5 or CM-510 to connect your Dynamixel to the battery.

  • Serial port cable


Same as the previous option but instead of using the USB2Dynamixel you only will need the serial cable and the "Toss Mode" launched with the 't' command from the "Manage Mode"


  • Wireless control


Instead of only sending and receiving data, with the previous wireless connections you can command remotely your robot using the standard firmware and the "Toss Mode" launched with the 't' command from the "Manage Mode". You will need to command it using the Dynamixel protocol.

With these options and the CM-510 you will find a little problem... there is no way to read your sensor values! Well, you can use this firmware that offers a "Toss Mode" that supports reading CM-510 ports.

Start learning!

If you want to start learning how to program your CM-5 or CM-510 controller you will find interesting this post "Start programming  CM-5/CM-510 in C". But may be you prefer to control your robot from a PC, SBC or other computer in C++ or C#