Category: Featured

CM-510 firmware for using as multiple sensor item updated

CM-510 firmware and post updated

 

 

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

This entry is part 2 of 5 in the series (ES) Programación de CM-510

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):

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);
}

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

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);
   }
 }
}

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

int main(void)
{
  init();

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

  puts("The End");

  return 0;
}

Aquí te puedes descargar el ejemplo completo

Taller de programacion Bioloid: Primeros pasos en C

This entry is part 1 of 5 in the series (ES) Programación de CM-510

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:

// 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
}

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)

#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");
}

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:

01_Hola_Mundo_Salida_RoboPlus_Terminal

01_Hola_Mundo_Salida_RoboPlus_Terminal

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).

dx_series_goal

dx_series_goal

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)”?

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!

CM-510 as a multiple sensor dynamixel item (updated 21/03/2014)

This entry is part 3 of 3 in the series Programming Robotis Bioloid hardware

[UPDTATE 21/03/2014] TossModeJCA v6.5. More information and examples at (I) Reading sensors connected to Robotis CM-510. Here you have the source files.

New functions added:

#define F_GET_BATTERY_MILLIVOLTS 6
Get the current battery voltage

#define F_SET_BATTERY_LOW_LEVEL_THRESHOLD 20
Set low battery warning (two red led will be on, PLAY and AUX)

#define F_SET_BATTERY_VERY_LOW_LEVEL_THRESHOLD 21
Set VERY low battery warning, all leds on

Apart from toss commands to Dynamixel devices, All the functions CM-510 could perform are:

#define F_NO_FUNCTION  0
No function, only to initialize values

#define F_GET_SENSOR_VALUE_RAW  1
Read sensor value

#define F_GET_TWO_DMS_SENSOR_VALUES 2
[Experimental] Read 2 sensor values in one query and one answer

#define F_GET_MULTIPLE_SENSOR_VALUE 3
[Experimental] Read several sensor values in one query and one answer

#define F_GET_SENSOR_VALUE_FILTERED  4
Read sensor value, avoiding maximum and minimum values

#define F_SET_SENSOR_VALUES_TO_FILTER 5
Number of readings that will be filtered

#define F_GET_BATTERY_MILLIVOLTS 6
Get the current battery voltage

#define F_SET_BATTERY_LOW_LEVEL_THRESHOLD 20
Set low battery warning (two red led will be on, PLAY and AUX)

#define F_SET_BATTERY_VERY_LOW_LEVEL_THRESHOLD 21
Set VERY low battery warning, all leds on

#define F_BEEP 8
If there is a buzzewr it beep, if no buffer it blinks

#define F_DO_SENSOR_SCAN 9
[Experimental!!!] Using servo ID 13 runds from 300 to 700 reading and return servo por where max value read

#define F_SET_VALUE_DMS1Port 11
Set the port for the first sensor

#define F_SET_VALUE_DMS2Port 12
Set the port for the second sensor

[UPDATE 7/11/13: CM_510 TossModeJCA updated to v5.8. Several parameters error fix and somewhat faster]

My main Bioloid project is to build a robot that will have some interesting (non easily predictable but reasonable) behaviours. AntOne 3.6 is the last version:

AntOne 3.6 is based on a PDA that has the software for the behaviour and a CM-510 (ATMega 2561) that control the hardware (servos and sensors). But I discovered that standard CM-510 firmware has no command to get sensor values, so I programmed another with that function. But then I thought that it would be interesting to embed some perception functions in the CM-510.

This is a general diagrama:

Single controller

Single controller

Updated 23/2/2013

The new hex file v4.3 (the old CM-510 firmware)

Now it supports new functions, as:

– Toss Mode (up) now can read from Dynamixel and write to serial and, as the previous version, read from serial and write to Dynamixel, it allows to….
– receive from zigbee and send the data to the Dynamixel bus
– read raw sensor values
– averaged sensor values when F_SET_SENSOR_VALUES_TO_FILTER is set < 5, not including the min and the max when >= 5
– CM-510 beep
– sensor scan (still in development)

#define F_NO_FUNCTION 0
#define F_GET_SENSOR_VALUE_RAW 1
#define F_GET_TWO_DMS_SENSOR_VALUES 2
#define F_GET_MULTIPLE_SENSOR_VALUE 3
#define F_GET_SENSOR_VALUE_FILTERED 4
#define F_SET_SENSOR_VALUES_TO_FILTER 5

#define F_BEEP 8
#define F_DO_SENSOR_SCAN 9
#define F_SET_VALUE_DMS1 11
#define F_SET_VALUE_DMS2 12

C# example os use:

       private void B_ReadPort_Click(object sender, EventArgs e)
        {
            byte function = (byte)NUD_Function.Value;
            byte portId = (byte)NUD_Port.Value;

            if (portId &amp;lt; 0 || portId &amp;gt; 6)
                portId = 1;

            string strPortId=portId.ToString();

            if (function == 1 || function == 4)
            {
                short portValue = cm510.getSensorValue(function, portId);
                string str = portValue.ToString();

                TB_PortValue.Text = str;
            }
            else
            {
                if (function == 2)
                {
                    byte[] parameters = new byte[3];
                    parameters[0] = function;
                    parameters[1] = Convert.ToByte(TB_DMS1_ID.Text);
                    parameters[2] = Convert.ToByte(TB_DMS2_ID.Text);

                    short[] values = new short[3];
                    cm510.getMultipleSensorValue(parameters, values);
                    //cm510.getTwoSensorValue(function, Convert.ToByte(TB_DMS1_ID.Text), Convert.ToByte(TB_DMS2_ID.Text), values);

                    if (values.Length &amp;gt;= 2)
                    {
                        TB_DMS1_PortValue.Text = values[1].ToString();
                        TB_DMS2_PortValue.Text = values[2].ToString();
                    }
                }
                else
                {
                    if (function == 3)
                    {
                        byte[] parameters = new byte[3];
                        parameters[0] = function;
                        parameters[1] = Convert.ToByte(TB_DMS1_ID.Text);
                        parameters[2] = Convert.ToByte(TB_DMS2_ID.Text);

                        short[] values = new short[3];
                        cm510.getMultipleSensorValue(parameters, values);

                        if (values.Length &amp;gt;= 2)
                        {
                            TB_DMS1_PortValue.Text = values[1].ToString();
                            TB_DMS2_PortValue.Text = values[2].ToString();
                        }
                    }
                    else
                    {
                        if (function == 11)
                        {
                            TB_DMS1_ID.Text = strPortId;
                        }
                        else
                        {
                            if (function == 12)
                            {
                                TB_DMS2_ID.Text = strPortId;
                            }
                        }
                    }
                }
            }
        }

%d bloggers like this: