黄工无刷电机学习
直播中

ytrwv

8年用户 878经验值
擅长:EMC/EMI设计
私信 关注
[问答]

拓达伺服TSDA-C21B如何使用单片机来控制电机转向角?

拓达伺服TSDA-C21B如何使用单片机来控制电机转向角?

回帖(1)

杨磊

2021-10-20 09:37:49
  前言

拓达TSDA-C21B伺服是我的研究生课题平衡车的项目,用来做电机转向控制用的驱动器,网上没有单片机控制的驱动程序可参考,咨询卖家也没有相关的程序提供,所以只有自己看官方的用户手册自己写控制转向的驱动程序。本文介绍拓达伺服TSDA-C21B使用单片机来控制电机转向角方案,以官方的手册为参考,从硬件的接线到软件的设计进行讲解。
  下面以STM32F4单片机为例,来介绍控制电机转向的方案。
你需要的材料有:24-80V直流电源、TSDA-C21B和配套的电机和配件、串口母头、STM32F4单片机模块、STM32F4数据手册、TSDA-C21B 伺服用户手册
驱动器的参数配置

关于驱动器参数的调试软件这里不多做介绍,官方的手册和客服都能帮忙处理。若通讯故障则为硬件接线问题。
这里 我们选的模式选择的参数后文中有解释。1、2参数是电机加减速的时间,3是比例增益增大它能使电机反应更灵敏。图中的参数值可供参考。配置好之后电机下载设置写入驱动器即可





一、硬件准备

1、驱动器的硬件的接线硬件的接线
此处参考官方手册的接线。注意:此处PB、RB可暂时不接




实物接线图 (控制接口可暂时不接,后面需要测速时可接到单片机用于测电机的转速)





2、网口线插入标有RS232的端口,另一端再接一个串口母头,引出的杜邦线接STM32的串口(注意RXT接单片机串口的TXD,TXD接单片机的RXD)





二、软件的设计

1.看官方的数据手册确定写软件的方案

(1)、控制模式、与控制来源的选择的选择

我们要设计的是控制电机转向。看官方数据手册的控制方式,有位置控制模式、速度控制模式、力矩控制模式。这里我们选择位置控制模式,由5.2知必须选择PC数字输入。所以在上文驱动器参数的配置里选择 位置调试模式-PC数字输入










(2)、通过官方手册上的说明来搞懂使用RS232发命令的方法和步骤

看下图(1)知道控制器接收数据命令的格式为 地址(A1) + 数据高八位(A2) + 数据低八位(A3) + 数据校验和(A1+A2+A3的低八位值)
看下图(4)并结合下下图中黄线标注的地方知道我们发送的是一个长度为32位的数据,发送时需要分解为高16位和低16位发送。发送高16位的数据地址(A1)为0x50,发送低16位的数据地址(A1)为0x05。校验和取(A1+A2+A3)前8位。其中16位数据也要分高8位和低八位进行发送(由下图1(1)知先发送高八位再发送低八位)。










我们通过上述对数据手册的分析来验证一下官方给的RS232通讯发命令的方法:
1、给定-10000转化为16进制为 0xFFFF FFFF FFFF D8F0,取32位数据即后32位 FFFF D8F0,高16位为FFFF,低16位为D8F0。其中高16位的高8位为FF,低8位为FF;低16位的高8位为D8,低8位为F0。
高16位校验和的计算方法为(0x50+0xFF+0xFF)&0xFF计算得0x4E,低16位校验和的计算方法为(0x05+0xD8+0xF0)&0xFF计算得0xCD。
2、按照上图1(1)知发送数据命令的格式为地址(A1) + 数据高八位(A2) + 数据低八位(A3) + 数据校验和 所以先在地址0x50发数据高16位,且要分高八位、低八位发送,最后发送校验和。在地址0x05发数据低16位,且要分高八位、低八位发送,最后发送校验和。
3、由上图1(1)知每帧数据指令之间要有5ms以上的等待,所以上面发送高16位和低16数据时需要有延时。
4、由上述的分析可得出 RS232发送的命令为:
0x50 0xFF 0xFF 0x4E 延时10ms 0x05 0xD8 0xF0 0xCD
为了安全在发送两帧数据之间延时10ms。与下图中官方给定的发送命令一致。





(3)、自己动手写串口发送数据的函数


1、发送数据函数的结构分析
根据上面所总结的发送数据的方法,我们知道发送数据一次发送32位,需要分不同地址发送它的高16位和低16位,并且高16位和低16位也是按高8位和低8位发送的。所以可以先写发16位数据命令的函数(其中要嵌套发送A1、A2、A3、校验和后8位),然后再在发32位数据函数中嵌套调用发16位数据命令的函数。
2、发送16位数据命令函数的写法分析
根据上面的总结,我们可以将发送命令函数的参数定为 地址和8位数据,类似这种伪代码


void SendCmd(u8 addr, u16 val)
{
        发送 addr(A1);
        发送val的高8位(A2);
        发送val的低8位(A3);
        发送校验和的后8位((A1+A2+A3)&0xFF);
}


3、发送32位数据函数写法分析
根据上面的总结与分析,发送数据函数的参数定为一个32位的数据值,伪代码类似于这种


void SendData(u32 data)
{
        调用SendCmd函数在0x50处发送data的高16位;
        delay_10ms();       
        调用SendCmd函数在0x05处发送data的低16位;
}


2、具体总的代码具体实现如下
// 通过串口4给驱动器发送16位数据命令函数
void SendCmd(u8 addr,u16 val)                                                // 函数参数为 数据地址和 16位值
{
        u8 gao,di,chk;                                                                        // 定义8位数据gao、di、chk用于存储16位数据的高8位、低8位、和校验和的低8位
        gao=(val>>8)&0xff;                                                            // 得到实参val的高8位
        di=val&0xff;                                                                        // 得到实参val的低8位
        chk=(addr+gao+di)&0xff;                                                // 得到校验和的低8位
        while((UART4->SR&0X40)==0);                                 //  等待数据发送完成,完成时跳出while,执行下一条语句
        UART4->DR =addr;                                                                 // 向串口发送数据地址(A1)
        while((UART4->SR&0X40)==0);                                     //  等待数据发送完成,完成时跳出while,执行下一条语句
        UART4->DR =gao;                                                                  // 向串口发送数据的高8位
        while((UART4->SR&0X40)==0);                                         // 等待数据发送完成,完成时跳出while,执行下一条语句
        UART4->DR =di;                                                                  // 向串口发送数据的低8位
        while((UART4->SR&0X40)==0);                                         // 等待数据发送完成,完成时跳出while,执行下一条语句
        UART4->DR =chk;                                                                  // 向串口发送校验和低8位
}


// 通过串口4给驱动器发送32位数据函数
void SendData(u32 data)
{
        u16 gao,di;                                                // 定义16位数据gao和di,用于存储函数参数的高16位和低16位
        if(data<0){                                                // 如果要发送的数据data是小于0的值,则需要将data变为补码的形式(因为负数在内存中是以补码的形式存储的)
                data=data*(-1);                                // 负数的补码的计算方法为:其相应正数的反码加1。此行是求它相应的正数
                data=~data+1;                                // 此行是取反加1, 得到计算机中 “真正意义的” 负数
        }
        gao=(data>>16)&0xffff;                        // 得到实参data的高16位
        di=data&0xffff;                                        // 得到实参data的低16位
        SendCmd(0x50,gao);                                // 调用SendCmd函数将高16位值从相应的地址(0x50)处发送
        delay_ms(15);                                        // 每帧数据指令要延时5ms以上,避免出错
        SendCmd(0x05,di);                                // 调用SendCmd函数将低16位值从相应的地址(0x05)处发送
}


基础知识补充:
(1)、>> 操作符即将数据的2进制右移,每移动一位左边最高位都补0,(val>>8)&0xff,此句命令即将val的高位移到低8位,&0xff即得到低8位(0xxxxxx&0xff = 0xxx)。
(2)、正数在内存中以源码的形式存储的,负数则以补码的形式存储的,要将负数写入UART->DR,则要写入其补码。
(3)、如果你不懂上述串口的操作,你可以打开STM32F4的数据手册。
1.搜索USART_SR到如下图所示的页面





看红框框柱的地方为USART的第6位为TC寄存器(可读可清零,可以通过写‘0’来清零)。该位默认值为1,看下面的红线部分知道,为0表示传送未完成 ,1表示传送已完成。读取USART_SR,然后写入USART_DR会将此位软件清零。
所以在传输数据前需要等待上次的传输完成,利用while内的 UART4->SR&0X40==0 用于判断UART寄存器的第6位TC是否等于0,即判断上次数据是否已发送完成。如果完成则执行下一行语句,如果未完成则一直执行空语句等待。
2.搜索USART_DR到如下图所示页面





可以看到USART的DR寄存器的描述,为8位,能读能写。
所以我们能像 UART4->DR =gao; 这样对它进行写操作。
3、main函数调用SendData()函数实现角度转向

这里我们在电机上接了一个64:1的减速器。

............
int main(void)
{
                                SendData(20000);                // 以启动时刻为机械零点,电机往正方向转4圈,减速器64:1,即向正方向转22.5°,到+22.5°位置
                                delay_ms(2000);                        // 延时2000ms
                                SendData(-20000);                // 以启动时刻为机械零点,电机往反方向转8圈,即转45°,到相对机械零点-22.5°位置
                                delay_ms(2000);                        // 延时2000ms
}

我们的编码器是1250线的,所以 5000脉冲,转1圈。 发送 200000脉冲即转4圈。用了64:1的减速器乘以减速比1/64再乘1/360即可求出转向角为22.5°。由于是位置模式的绝对位置,所以发送-20000时转到 -22.5°的位置。










三、总结

以上便是用STM32控制TSDA-C21B驱动器控制位置转向过程,这个方案我们用过。优点是使用串口操作相对比较简单,缺点是每发一帧命令都需要延时10ms,而单片机执行指令是微秒级的,而且驱动器还需要对发送的数据进行响应需要一定的时间,所以在每次给驱动器发数据时都需要延时等待几十毫秒的时间,在某些实时性比较高的场合,比如平衡车需要实时读取IMU数据并实时控制车辆转向时,这个延迟相对于IMU的中断间隔就很大了,导致不能实时的控制车辆的转向。该方案存在缺陷。
四、后记

咨询过拓达的工程师后得知CAN控制和RS485速度会快一些,进一步咨询之后知道CAN线的响应为5ms以内,而且看数据手册知道每帧数据之间不需要像数据串口那样延时5ms以上。所以每次发CAN命令之间只需要 间隔5ms 就可以了。这相对于IMU获取姿态的中断来说可以满足需求。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分