背景:硬件采用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. Spring中资源的加载原来是这么一回事啊!

    1. 简介 在JDK中 java.net.URL 适用于加载资源的类,但是 URL 的实现类都是访问网络资源的,并没有可以从类路径或者相对路径获取文件及 ServletContext , 虽然可以通过 ...

  2. I - Coins dp

    http://acm.hdu.edu.cn/showproblem.php?pid=2844 这个题目是一个多重背包转化成01背包 题意: Whuacmers拥有bi个面值为ai的硬币,现在他要用这些 ...

  3. 【HBase】底层原理

    目录 系统架构 表数据模型 物理存储 系统架构 在文章[HBase]基本介绍和基础架构中已经有简单介绍 Client -- 包含访问hbase的接口,client维护着一些cache来加快对hbase ...

  4. Jekyll 解决Jekyll server本地预览文章not found的问题

    layout: post tags: [Jekyll] comments: true 执行Jekyll本地浏览器预览指令 bundle exec jekyll serve 进入浏览器输入127.0.0 ...

  5. Linux内核驱动学习(八)GPIO驱动模拟输出PWM

    文章目录 前言 原理图 IO模拟输出PWM 设备树 驱动端 调试信息 实验结果 附录 前言 上一篇的学习中介绍了如何在用户空间直接操作GPIO,并写了一个脚本可以产生PWM.本篇的学习会将写一个驱动操 ...

  6. Js 事件基础

    一:js中常见得事件 (1) : 鼠标事件         click :点击事件         dblclick :双击事件         contextmenu : 右键单击事件        ...

  7. Git、Github习笔记01——Git本地仓库

    作者:Eventi 出处:http://www.cnblogs.com/Eventi 欢迎转载,也请保留这段声明.谢谢! git简介 版本控制软件,由Linus(linux开发者)开发,最初用来对li ...

  8. 一文带你了解Spring核心接口Ordered的实现及应用

    前言 最近在看框架的时候,发现了这个接口,在此进行总结,希望能够给大家帮助,同时提升自己. order接口的大体介绍 Spring框架中有这个一个接口,名字叫Ordered,联想我们在数据库中应用的O ...

  9. 08JAVA基础关键字(final、static)以及抽象类和接口

    一.关键字 1.final 修饰类 修饰变量 修饰成员方法 该类为最终类,不能被继承 该变量为常量 该成员方法不能被重写 2.static (1).生命周期 随着类的加载而加载 (2).特点 被本类所 ...

  10. 03JAVA循环结构

    和JS\Python语句判断逻辑基本一致,不需要记录详细,只需要记录格式 一.for循环 for (初始化数据;判断语句:控制语句){ 循环体语句; } 二.while循环 初始化数据; while ...