背景:硬件采用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. 剑指offer--(根据前序遍历和中序遍历)重建二叉树

    题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...

  2. ActiveMQ 持久订阅者,执行结果与初衷相违背,验证离线订阅者无效,问题解决

    导读 最新在接触ActiveMQ,里面有个持久订阅者模块,功能是怎么样也演示不出来效果.配置参数比较简单(配置没几个参数),消费者第一次运行时,需要指定ClientID(此时Broker已经记录离线订 ...

  3. Algorithms - Quicksort - 快速排序算法

    相关概念 快速排序法 Quicksort 也是一个分治思想的算法. 对一个子数组 A[p: r] 进行快速排序的三步分治过程: 1, 分解. 将数组 A[p : r] 被划分为两个子数组(可能为空) ...

  4. 初探Redis-基础类型Hash

    Redis存在五种基础类型:字符串(String).队列(List).哈希(Hash).集合(Set).有序集合(Sorted Set).本次列举出Hash的常用操作. Redis官网:https:/ ...

  5. [ACdream 1212 New Year Bonus Grant]贪心

    题意:员工之间形成一棵树,上级可以给下级发奖金,任何一个人最多可以给一个下级发,并且发了奖金后就不能接受奖金.求总共最多可以产生多少的奖金流动 思路:每次选择没有下级并且有上级的员工a,令它的上级为b ...

  6. 浅析微软的网关项目 -- ReverseProxy

    浅析微软的网关项目 ReverseProxy Intro 最近微软新开了一个项目 ReverseProxy ,也叫做 YARP(A Reverse Proxy) 官方介绍如下: YARP is a r ...

  7. 学习docker的一点记录

    0x00 docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化 ...

  8. 容器技术之LXC WEB管理工具LXC WEB Panel

    前一篇博文中主要说了下,lxc容器在Linux上的简单管理,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/12901493.html:今天我们来介绍下lxc的图 ...

  9. day_02~day_09的Python语法基础

    Python基础学习 day_02 使用方法修改字符串的大小写 将字符串首字母变成大写 >>> name = "ada lovelace" >>> ...

  10. HTML标签和属性三

    八.列表 1.列表的作用 让数据有条理的显示,在数据之前添加标识 但是现在页面布局,经常会使用到无序列表 2.列表的组成 ①有序列表 <ol> <li></li> ...