舵机MX-64AR与MX-28AR驱动

背景:硬件采用485通信,在tb上采购的无需收发控制的串口转RS485模块(485通信为半双工,一般情况需要控制收发模式)。在使用该模块后,即可完全使用一个普通地串口来对485通信的舵机进行操作。

模块链接:https://item.taobao.com/item.htm?spm=a1z09.2.0.0.66dc2e8d3QIPTQ&id=541473495140&_u=j33333sl4f32

驱动代码:

平台:STM32F405RGT6

舵机:MX64AR —— 固件版本1.0

软件部分见另一篇博客。

舵机通信串口配置:

/* UART2 for MX64 */
void vUart2Config(void)
{
	USART_InitTypeDef usart2;
	GPIO_InitTypeDef  gpio;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);

	gpio.GPIO_Pin = GPIO_Pin_2;
	gpio.GPIO_Mode = GPIO_Mode_AF;
	gpio.GPIO_OType = GPIO_OType_PP;
	gpio.GPIO_Speed = GPIO_Speed_100MHz;
	gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&gpio);

	gpio.GPIO_Pin = GPIO_Pin_3;
	gpio.GPIO_Mode = GPIO_Mode_IN;
	gpio.GPIO_Speed = GPIO_Speed_100MHz;
	gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&gpio);

	usart2.USART_BaudRate = 115200;
	usart2.USART_WordLength = USART_WordLength_8b;
	usart2.USART_StopBits = USART_StopBits_1;
	usart2.USART_Parity = USART_Parity_No;
	usart2.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
	usart2.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(USART2,&usart2);

//	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
	USART_Cmd(USART2,ENABLE);
//	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);	
	
//	{
//		DMA_InitTypeDef	dma;
//		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
//		DMA_DeInit(DMA1_Stream6);
//		dma.DMA_Channel= DMA_Channel_4;
//		dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART2->DR);
//		dma.DMA_Memory0BaseAddr = (uint32_t)sbus_rx_buffer;
//		dma.DMA_DIR = DMA_DIR_MemoryToPeripheral;
//		dma.DMA_BufferSize = TX_USART2_BUFFER;
//		dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//		dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
//		dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//		dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
//		dma.DMA_Mode = DMA_Mode_Circular;
//		dma.DMA_Priority = DMA_Priority_VeryHigh;
//		dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
//		dma.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
//		dma.DMA_MemoryBurst = DMA_Mode_Normal;
//		dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
//		DMA_Init(DMA2_Stream5,&dma);
//		DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);
//		DMA_Cmd(DMA2_Stream5,ENABLE);
//	}
}

 

目前该品牌舵机有两个版本的通信协议(1.0和2.0)。2.0协议增加了很多新的控制模式和功能。

升级固件版本后舵机可以支持2.0通信协议,但是升级固件需要使用专用的编程器(有点对=贵),一般没有必要购买。手中的舵机是哪个版本的协议就用那个就好了。

以下分别总结两个版本的通信协议控制代码:

通信协议1.0:(详情见官网协议说明:http://emanual.robotis.com/docs/en/dxl/protocol1/#status-packet

舵机EEPROM及RAM地址:

舵机驱动函数:

这里由于仅需要使用舵机的最基本功能:单圈的位置模式,因此在此只实现了部分控制函数。如有其它需求,仿照一下函数即可。但是关于舵机的控制模式切换以及一些高级的设置,需要使用舵机的编程卡配合上位机配置。

/* Protocol 1.0 */
void send_MX64_action(void)
{
	uint8_t i = 0;
	uint8_t MX64_buffer[6];
	
	MX64_buffer[0]=0xFF;	
	MX64_buffer[1]=0xFF;	
	MX64_buffer[2]=0xFE;	
	MX64_buffer[3]=0x02;	
	MX64_buffer[4]=0x05;	//commend:action
	MX64_buffer[5]=0xFA;	//check sum
	
	for(i=0;i<=5;i++)
	{
		USART_SendData(USART2,MX64_buffer[i]);
		while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);
	}
}

/* MX64 position set commend */
void send_MX64_position(unsigned short Control_Angle)
{
	uint8_t j = 0;
	uint8_t MX64_buffer[15];
	
	MX64_buffer[0]=0xFF;	//header byte 
	MX64_buffer[1]=0xFF;	//header byte
	MX64_buffer[2]=0xFE;	//motor id
	MX64_buffer[3]=0x05;	//length
	MX64_buffer[4]=0x04;	//Reg Write:0x04 
	MX64_buffer[5]=0X1E;	//goal position reg address
	/* goal position */
	MX64_buffer[6]=(Control_Angle<<8)>>8;
	MX64_buffer[7]=Control_Angle>>8;
	/* check */
	MX64_buffer[8]=~(MX64_buffer[2]+MX64_buffer[3]+MX64_buffer[4]+MX64_buffer[5]+MX64_buffer[6]+MX64_buffer[7]);
	
	for(j=0;j<=8;j++)
	{
		USART_SendData(USART2,MX64_buffer[j]);
		while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);
	}
}

注意:在使用位置模式控制舵机时,需要先设置目标位置,目标位置设定成功后,舵机并不会动,而是还需要发送一条ACTION指令(即send_MX64_action()函数),舵机才会运动。每次设定一个新的目标位置都需要调用该函数,使舵机开始运动。

由于MX-28AR、64AR舵机的初始通信波特率均为57600,我之前一直没有注意,用115200的波特率调试了很久也没有成功(因为之前买过的一个二手的舵机买来的时候就被设置好了115200的波特率,就用那套代码在调)

因此又添加了设定波特率的一个简单功能(统一设定为115200):

/* MX64 position set commend */
void set_MX64_baudrate(void)
{
    uint8_t j = 0;
	uint8_t MX64_buffer[15];
	
	MX64_buffer[0]=0xFF;	//header byte 
	MX64_buffer[1]=0xFF;	//header byte
	MX64_buffer[2]=0xFE;	//motor id
	
	MX64_buffer[3]=0x04;	//length
	MX64_buffer[4]=0x03;	//Write:0x03 
	
	MX64_buffer[5]=0X04;	//baudrate reg address
	/* goal baudrate : 115200 = 2000000/(16+1) */
	MX64_buffer[6]=0x10;
	/* check */
	MX64_buffer[7]=~(MX64_buffer[2]+MX64_buffer[3]+MX64_buffer[4]+MX64_buffer[5]+MX64_buffer[6]);
	
	for(j=0;j<=7;j++)
	{
		USART_SendData(USART2,MX64_buffer[j]);
		while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);
	}
}

 

通信协议2.0:(详情见:http://emanual.robotis.com/docs/en/dxl/mx/mx-64-2/#control-table

寄存器地址见上一行网址(官网协议说明)

控制代码:

/* Protocol 2.0 */
/* MX64 action commend */
void send_MX64_action(void)
{
	uint8_t i = 0;
	uint8_t MX64_buffer[10];
	uint16_t CRC_result;

	MX64_buffer[0] = 0xFF;	//header byte 
	MX64_buffer[1] = 0xFF;	//header byte
	MX64_buffer[2] = 0xFD;	//header byte 
	MX64_buffer[3] = 0x00;	//reserve byte
	
	MX64_buffer[4] = 0xFE;	//motor id(broadcast)
	MX64_buffer[5] = 0x03;	//length(Low ) = parameter length + 3 
	MX64_buffer[6] = 0x00;	//length(High) = parameter length + 3 
	MX64_buffer[7] = 0x05;	//commend (0x05: action)
	
	/* CRC calculate */
	CRC_result = update_crc(0,MX64_buffer,8);
	MX64_buffer[8] = CRC_result & (0xFF);	//Low
	MX64_buffer[9] = (CRC_result>>8) & (0xFF);	
	
	for(i=0;i<=9;i++)
	{
		USART_SendData(USART2,MX64_buffer[i]);
		while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);
	}
}

/* MX64 position set commend */
void send_MX64_position(unsigned short Control_Angle)
{
	uint8_t j = 0;
	uint8_t MX64_buffer[16];
	uint16_t CRC_result;
	
	/* head */
	MX64_buffer[0] = 0xFF;	//header byte 
	MX64_buffer[1] = 0xFF;	//header byte
	MX64_buffer[2] = 0xFD;	//header byte 
	MX64_buffer[3] = 0x00;	//reserve byte
	
	MX64_buffer[4] = 0xFE;	//motor id(broadcast)
	MX64_buffer[5] = 0x09;	//length(Low ) = parameter length + 3 
	MX64_buffer[6] = 0x00;	//length(High) = parameter length + 3 
	MX64_buffer[7] = 0x04;	//commend (0x04: reg write)
	
	/* reg address */
	MX64_buffer[8] = 0x74;	//Low
	MX64_buffer[9] = 0x00;	
	
	/* goal position(4 bytes) */
	MX64_buffer[10] = (Control_Angle<<8)>>8;	//Low
	MX64_buffer[11] = Control_Angle>>8;				
	MX64_buffer[12] = 0x00;
	MX64_buffer[13] = 0x00;		//High
	
	/* CRC calculate */
	CRC_result = update_crc(0,MX64_buffer,14);
	MX64_buffer[14] = CRC_result & (0xFF);	//Low
	MX64_buffer[15] = (CRC_result>>8) & (0xFF);	
	
	for(j=0;j<=15;j++)
	{
		USART_SendData(USART2,MX64_buffer[j]);
		while( USART_GetFlagStatus(USART2,USART_FLAG_TC)!= SET);
	}
}

其中2.0版本的协议校验方式改为CRC16校验(1.0版本为简单的和校验),CRC校验函数实现如下(官网也有):

/* MX28 Servo CRC16 function (for Protocol 2.0)*/
static unsigned short update_crc(unsigned short crc_accum, unsigned char *data_blk_ptr, unsigned short data_blk_size)
{
	unsigned short i, j;

	unsigned short crc_table[256] = {
		0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
		0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
		0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
		0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
		0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
		0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
		0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
		0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
		0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
		0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
		0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
		0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
		0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
		0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
		0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
		0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
		0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
		0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
		0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
		0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
		0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
		0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
		0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
		0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
		0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
		0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
		0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
		0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
		0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
		0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
		0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
		0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
	};

	for(j = 0; j < data_blk_size; j++)
	{
		i = ((unsigned short)(crc_accum >> 8) ^ data_blk_ptr[j]) & 0xFF;
		crc_accum = (crc_accum << 8) ^ crc_table[i];
	}

	return crc_accum;
}

 

 ——cloud over sky

——2020/1/18

 

posted @ 2020-01-19 05:01  Yu_tiann  阅读(930)  评论(0编辑  收藏  举报