背景:硬件采用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

舵机MX-64AR与MX-28AR驱动的更多相关文章

  1. The prefix "mx" for element "mx:WindowedApplication" is not bound.

    <mx:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"  > ......出现了错误The p ...

  2. 盘点飞思卡尔i.MX多媒体处理器前世今生 (转)

    现如今,移动处理器领域,大家关注最多的是德州仪器.高通.展讯.MTK,甚至包括Intel,但是请别忘记飞思卡尔,他的i.MX处理器已经发展到第六代. 那么我们今天就来盘点下i.MX的前世今生吧. i. ...

  3. 域名的MX设置及校验方法

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  4. 常用域名记录解释:A记录、MX记录、CNAME记录、TXT记录、AAAA记录、NS记录

    A记录 A记录是用来创建到IP地址的记录. A记录设置技巧 1.如果想创建不带www的记录,即ezloo.com,在主机记录中填写@或者留空,不同的注册商可能不一样. 2.创建多个域名到同一个IP,比 ...

  5. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU特性介绍(1)- 概览

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的基本特性. ARM Cortex-M微控制器芯片厂商向来竞争激烈,具体可参看我的另一篇文章<第一 ...

  6. [UOJ86]mx的组合数——NTT+数位DP+原根与指标+卢卡斯定理

    题目链接: [UOJ86]mx的组合数 题目大意:给出四个数$p,n,l,r$,对于$\forall 0\le a\le p-1$,求$l\le x\le r,C_{x}^{n}\%p=a$的$x$的 ...

  7. UOJ.87.mx的仙人掌(圆方树 虚树)(未AC)

    题目链接 本代码10分(感觉速度还行..). 建圆方树,预处理一些东西.对询问建虚树. 对于虚树上的圆点直接做:对于方点特判,枚举其所有儿子,如果子节点不在该方点代表的环中,跳到那个点并更新其val, ...

  8. Flex里的fx s mx

    笔记是从其他地方整合的,仅供参考 原来flex build 4有三个命名空间fx,mx,s,分别对应一下三个: •xmlns:fx="http://ns.adobe.com/mxml/200 ...

  9. Flex学习总结

    Flex SDK Flex框架类库.Flex编译环境.调式器.MXML.ActionScript编程语言以及其它工具组成,Flash Builder是其开发环境,   Flash Player的工作模 ...

  10. 十个提升你Emacs生产力的高招

    转载 十个提升你Emacs生产力的高招   Emacs是世界上最好的编辑器(真的有很多人这么认为).不要以为emacs只是在编写程序时很牛X,其实只要你真正精通了emacs,会发现她几乎在所有用到打字 ...

随机推荐

  1. Linux下使用Rsync进行文件同步

    数据备份方案 1.需要备份的文件目录有(原则上,只要运维人员写入或更改的数据都需要备份)./data,/etc/rc.local,/var/spool/cron/root等,根据不同都服务器做不同的调 ...

  2. matlab基础知识总结

  3. Spring官网阅读(四)BeanDefinition(上)

    前面几篇文章已经学习了官网中的1.2,1.3,1.4三小结,主要是容器,Bean的实例化及Bean之间的依赖关系等.这篇文章,我们继续官网的学习,主要是BeanDefinition的相关知识,这是Sp ...

  4. Programmatically add an application to Windows Firewall

    Programmatically add an application to Windows Firewall 回答1   Not sure if this is the best way, but ...

  5. 在windows环境里,用Docker搭建Redis开发环境(新书第一个章节)

    大家都知道高并发分布式组件的重要性,而且如果要进大厂,这些技术不可或缺.但这些技术的学习难点在于,大多数项目里的分布式组件,都是搭建在Linux系统上,在自己的windows机器上很难搭建开发环境,如 ...

  6. 【HBase】HBase与MapReduce的集成案例

    目录 需求 步骤 一.创建maven工程,导入jar包 二.开发MapReduce程序 三.运行结果 HBase与MapReducer集成官方帮助文档:http://archive.cloudera. ...

  7. 【Hadoop离线基础总结】通过Java代码执行Shell命令

    通过Java代码执行Shell命令 需求 在实际工作中,总会有些时候需要我们通过java代码通过远程连接去linux服务器上面执行一些shell命令,包括一些集群的状态管理,执行任务,集群的可视化界面 ...

  8. Java语言简介、基础组成、封装、继承、多态、抽象类、内部类、接口

    目录 Java简介 Java语言基础组成 面向对象 对象 封装 构造函数 this关键字 static(静态关键字) 主函数 静态什么时候用呢? 面向对象(数组工具对象建立) 设计模式 继承 成员变量 ...

  9. Android广播机制(1)

    目录 简介 发送广播和接收广播方式 广播类型 接收系统广播 动态注册监听网络变化 步骤 优化 静态注册实现开机启动 步骤 注意 简介 就是因为安卓中的每个应用程序都可以对自己感兴趣的广播进行注册,这样 ...

  10. xml(3)

    xml的解析方式:dom解析和sax解析 DOM解析 使用jaxp进行增删改查 1.创建DocumentBuilderFactory工厂 2.通过DocumentBuilderFactory工厂创建D ...