Servomoteurs ROBOTIS Dynamixel

Servomoteurs ROBOTIS Dynamixel

La société coréenne ROBOTIS propose des servomoteurs ( ensemble Moteur CC + Hacheur + Contrôleur ) performants.

L’asservissement étant géré en interne, il suffit d’envoyer une consigne de vitesse ou de position via un bus ( TTL ou RS485 ).

L’information retour de couple est également disponible.


Références Testées

XL430-W250-T

  • Bus: TTL
  • Tension : 6.5 - 12V

XM430-W210-R

  • Bus: RS485
  • Tension : 6.5 - 12V

Protocole Dynamixel 2.0

Robotis Protocole 2.0

Analyse d’une trame :

LED ON : ( uC –> Dxl)

led_on.svg

Header

  • 0xFF 0xFF 0xFD 0x00

ID

  • 0x01 : Identifiant du moteur = 1

Length

  • 0x06 : Taille( Instruction + commande + Param + CRC ) = 6

Instruction

  • 0x03 : Write = 0x03 ( read = 0x02 )

Command

  • 0x41 : Command LED = 0x41 = 65

Parameter

  • 0x01 : Led ON ( Led Off = 0x00)

CRC

  • 0xCC 0xE6

Status Frame : ( Dxl –> uC)

led_status.svg

Header

  • 0xFF 0xFF 0xFD 0x00

ID

  • 0x01 : Identifiant du moteur = 1

Length

  • 0x04 : Taille( Instruction + commande + Param + CRC ) = 4

Instruction

  • 0x55 : Status

Error Code

  • 0x00 : Pas d’erreur

CRC

  • 0xA1 0x0C
AUTRES EXEMPLES DE TRAMES

Analyse de Trames

Torque ON

torque_on.svg

Torque OFF

torque_off.svg

Set Velocity Mode ON

set_vel_mode_on.svg

Set Goal Velocity

set_goal_vel.svg


Contrôle des Moteurs depuis un PC

DYNAMIXEL SDK


Contrôle des Moteurs par carte ST-NUCLEO

Robotis Dynamixel Shield

Robotis Dynamixel Shield

SOURCES DU PROJET :

WORKSPACE_F411_DXL_STM32CUBEIDE.zip

Architecture

montage.svg

Envoi d’une Trame

int dxl_sendPacket(int id, int instruction, int parameter_data_size, ...)
{
	uint8_t frame_to_write[50];
	uint16_t crc;
	uint32_t length=3+parameter_data_size;
	uint8_t arg;

	frame_to_write[0] = 0xFF;
	frame_to_write[1] = 0xFF;
	frame_to_write[2] = 0xFD;
	frame_to_write[3] = 0x00;	// RESERVED
	frame_to_write[4] = id;
	frame_to_write[5] = length&0xFF;		// length_LB
	frame_to_write[6] = (length>>8)&0xFF;		// length_HB
	frame_to_write[7] = instruction;		// Instruction : Write

    va_list args;
    va_start(args, parameter_data_size);
	for(int i=0 ; i < parameter_data_size ; i++ )
	{
	arg = va_arg(args, int);
	frame_to_write[8+i]= arg;
	}
	crc = dxl_updateCRC(0,frame_to_write,8+parameter_data_size);
	frame_to_write[8+parameter_data_size]= (uint8_t) ( crc & 0xFF );
	frame_to_write[9+parameter_data_size]= (uint8_t) ( (crc>>8) & 0xFF );
	va_end(args);

	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, 1);
	sendFrame(frame_to_write,parameter_data_size+2+8);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, 0);

	return 0;
}

Réception d’une Trame

Quand un octet est reçu sur UART6, cela déclenche une interruption.
La fonction de callback dxl_rcv_cb() met à jour dxl_rcvBuf .

void dxl_rcv_cb(uint8_t car)
{
		dxl_rcvBuf[(p_wr++)%BUF_SIZE] = car;
		size++;
}

receive_int.svg

	while(p_rd != p_wr)
	{
	tmp = dxl_rcvBuf[(p_rd++)%BUF_SIZE];

	switch(state)
	{
		case	STATE_START	: 		if(tmp == 0xFF) {state = STATE_HEADER_1;} 		break;
		case 	STATE_HEADER_1 : 	if( tmp == 0xFF) {state = STATE_HEADER_2;} 		break;
		case 	STATE_HEADER_2 : 	if( tmp == 0xFD) {state = STATE_HEADER_3;}		break;
		case 	STATE_HEADER_3 : 	if( tmp == 0x00) {state = STATE_ID;}			break;
		case 	STATE_ID : 			id = tmp ; state = STATE_LENGTH_LB; term_printf("id = %d | ",id); break;
		case 	STATE_LENGTH_LB : 	length = tmp ; state = STATE_LENGTH_HB;			break;
		case 	STATE_LENGTH_HB : 	length = (uint16_t)tmp << 8 | length ;
									state = STATE_INSTRUCTION;
									term_printf("length = %d | ",length);
									length = length - 2;
																					break;
		case	STATE_INSTRUCTION : instruction = tmp ;
									state = STATE_PARAM;
									length--;
									term_printf("instruction = 0x%x | ",instruction);
																					break;
		case 	STATE_PARAM : if( length > 0 ){
									param[i++] = tmp ;
									length-- ;
									term_printf("param %d = 0x%x | ",i,tmp);
									state = STATE_PARAM;
								}
								if (length == 0) {
									state = STATE_CRC1;
								}
																					break;
		case	STATE_CRC1 : state = STATE_CRC2; term_printf("CRC1 = 0x%x | ",tmp);	break;
		case 	STATE_CRC2 : state = STATE_FINAL; term_printf("CRC2 = 0x%x ",tmp);	break;
		case	STATE_FINAL : p_rd = p_wr; return 0; 								break;
	}
	}