历史上的今天
返回首页

历史上的今天

今天是:2024年09月30日(星期一)

正在发生

2019年09月30日 | stm32与伺服驱动器进行can通信

2019-09-30

实验室师兄之前用stm32之间进行can通信,其中一个作为主机,另外作为从机,从机负责电机运转,并取出电机的速度,然后通过can通信发送给主机,然后主机通过串口与上位机进行通信。这一部分操作可以参照以下链接:https://www.ncnynl.com/archives/201703/1414.html


现在我们选择用伺服驱动器与一个stm32进行can通信,从而实现对电机的控制,目前我们实现的是对电机的速度输入,启动电机,(并进行速度反馈,进行OLED输出,从而进行电机的PID调节)。

首先我们选择了以下图示伺服驱动器,驱动器这块选择淘宝搜索可进行can通信的编码器应该可以找到类似产品

在这里插入图片描述

然后按照手册,我们将电机的编码器信号线CN2,与电机相连,同时将电机三根动力线与电机相连,然后将RS232/CAN端口连出,由于我们首先测试的是商家给的PC端软件与伺服驱动器进行RS232通信,所以这里我们通过RS232与PC端相连,给伺服驱动器供电。效果图如下:

在这里插入图片描述

然后我们通过上位机软件给电机写入速度参数,加速度参数等,可以启动电机并有电流,位置,速度的实时反馈,初始如图:

在这里插入图片描述

上面进行了电机的初步测试,通过电机空载反馈回来的电流,我们初步判断电机是否工作正常,这里我们刚开始就出现电流在空载且速度较小的情况下,出现了电流输出过大的情况,于是在相关技术人员的帮助下随与商家联系更换了电机。

在这里插入图片描述

接下来就进入can通信的正题,can通信这一块我们最好通过实验板跑一下例程,然后结合程序去分析一下can通信的具体实现原理,及其各个寄存器的作用是什么,卡门一下stm32的技术文档(这里面时一些关于can通信的技术文档链接:https://pan.baidu.com/s/1LJJOMAxTTGgzYFfVnVGx5Q

提取码:agzo )。


想深入了解can通信,这里我推荐以下链接:

https://blog.csdn.net/qq_36355662/article/details/80607453

https://pan.baidu.com/s/1iy5z9g03Z4ZYn5gJYoN5WA?errno=0&errmsg=Auth Login Sucess&&bduss=&ssnerror=0&traceid=#list/path=%2F

(这是洋桃电子的资料,里面老师讲的很好很细,有助于对can通信理解)


首先在完成对can通信的理解后,我们会发现can通信的连线非常简单,只需要把can_h,can_l与其他can_h,can_l对应连接即可,其中两端需要串入120欧电阻,其作用是匹配总线阻抗,提高数据通信的抗干扰性及可靠行。(这里在设备较少时可以不接,但最好接上,消除干扰,本身stm32板内部已经串入120欧电阻,而且驱动器本身也有拨动按键来配置120欧电阻)

下一步我们需要按照手册编写can通信协议,通过stm32发送指令给伺服驱动器,从而实现电机的控制。这里特别提醒一下,这里需要用到can分析仪来分析到底哪里出了问题,这里我们走了弯路,问了技术人员后才发现这里离不开can分析仪对指令进行分析,can分析仪网上200元左右可以买到,如下:

在这里插入图片描述

接下来结合程序和手册分析一下到底如何编写指令,下面来自手册

在这里插入图片描述
在这里插入图片描述

通过这一块我们可以发现想要点对点的给伺服驱动器进行写数据操作的指令,这里伺服驱动器的ID号和组号可以通过之前的PC软件通过串口RS232写入。下一步就是需要用那些寄存器,并怎么给寄存器赋数据,这里从bite0-bite8的顺序我们可以发现指令写入的顺序。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过 这一部分寄存器,我们实现给伺服驱动器发送速度模式,并设定速度,最后启动电机的指令。然后通过自动报告的方式可以获取到反馈回来的速度,电流,位置。

下面是在stm32上的部分程序:


//can通信发送指令

//motor_init.c的写入数据代码

void Motor_Init(void)

{

CommandData[0]=Group_Motors; 

CommandData[1]=FCW_One2One; 

CommandData[2]=Register_SpeedSet; //速度设定寄存器

CommandData[3]=0x02; 

CommandData[4]=0xFE;

CommandData[5]=Register_Moter; //启动电机

CommandData[6]=0x00; 

CommandData[7]=0x00;

CAN_SendMsg(ID_MASTER, CommandData);

   CommandData[0]=Group_Motors; 

CommandData[1]=FCW_One2One; 

CommandData[2]=Resister_ReportTime; //自动报告时间设置成1s

CommandData[3]=0x07; 

CommandData[4]=0xd0;

CommandData[5]=Resister_AutoReportMode; //位置反馈 ,电流,速度

CommandData[6]=0x00; 

CommandData[7]=0x00;

  CAN_SendMsg(ID_LeftMotor, CommandData);

}



float Get_SpeedActual(uint32_t ID, float actual_speed)

{

int speed = 0;

actual_speed = 0;

CommandData[0]=Group_Motors; 

CommandData[1]=FCR_One2One; 

CommandData[2]=Resister_RSpeed; //读取的输出转速

CommandData[3]=0x00; 

CommandData[4]=0x00;

CommandData[5]=0xFF; //设置为无效寄存器

CommandData[6]=0x00; 

CommandData[7]=0x00;

Clear_canBuffer();

  CAN_SendMsg(ID, CommandData);


OLED_ShowString(0, 2,"Lspeed:",16);

while(Check_canRX()) ;

if((RxMessage.StdId) == 0x05 && RxMessage.Data[2]==Resister_RSpeed ) //设置为无效寄存器)//是否收到八位字节,且为输出转速寄存器

{

//将得到的数组合并成原始数

speed = RxMessage.Data[3] << 8 | RxMessage.Data[4];

// speed = RxMessage.Data[6] << 8 | RxMessage.Data[7];

//*actual_speed = RPM2Speed(speed/3000.0 * 8192.0);

actual_speed = RPM2Speed(speed/8192.0 * 3000.0); //实际电机转速转换成m/s

// OLED_ShowNumber(54, 2, actual_speed);

OLED_ShowNumber(12, 4, actual_speed);


//OLED_ShowString(12, 3,"stm32_master",16);

return 1;

}

return 0;

}


在motor.h文件下,我们对寄存器进行了宏定义例如:


#ifndef __MOTOR_H

#define __MOTOR_H


//FunctionCodeWrite,点对点的写数据操作功能码

#define FCW_One2One  0x1A  //发送指令,指令码,写数据,但不保存数据

#define FCW_One2One_Ri 0x1B //接收正确后返回指令

#define FCW_One2One_E  0x1C //接收错误后返回指令


//FunctionCodeRead,点对点的读数据操作功能码

#define FCR_One2One 0x2A // 指令的功能码,表示读数据,从机接收到指令后,把地址相应的数据内容上传

#define FCR_One2One_Ri 0x2B //接收正确后返回指令

#define FCR_One2One_E 0x2C //接收错误后返回指令


//FunctionCodeWrite,一对多的写数据操作功能码,主机发送数据指令,接收正确后,从机返回相应数据指令

#define FCW_One2Many  0x8A  //发送指令,写数据,但不保存数据

#define FCW_One2Many_Ri 0x8B //接收正确后返回指令

#define FCW_One2Many_E  0x8C //接收错误后返回指令


//FunctionCodeRead,一对多的读数据操作功能码

#define FCR_One2Many 0x9A //发送指令

#define FCR_One2Many_E 0x9C //接收错误后返回指令


//相关寄存器地址

#define Register_Moter 0x00  //电机寄存器   功能:写入数据不同,电机的启动和停止

#define Register_Mode 0x02  //电机输入模式选择,功能:写入数据不同,模式不同

#define Resister_SiteMode 0x51 //位置模式寄存器

#define Register_SpeedSet 0x06  //PC模式-速度给定

#define Resister_GroupNum 0x0b //设置从机CAN组号

#define Resister_IDNum 0x0d //设置从机CAN-ID号

#define Resister_ReportTime 0x0c //设置从机CAN报告时间

#define Resister_AutoReportMode 0x2e //设置自动报告内容选择



//10代表0到3000RPM 所用时间是 100ms

#define Resister_AccTimeInSpeed 0x0A //速度模式下,加减速时间设定,

#define Resister_AccTimeInSite 0x09 //位置模式下,加减速时间设定

//设定的数字量 8192 对应实际转速 3000RPM

#define Resister_SpeedLimit 0x1D //位置模式下,速度限幅值


//读参数地址列表

#define Resister_RLocation  0x55 //定位是否完成

#define Resister_RCircuit   0xE2//输出电流

#define Resister_RSpeed 0xE4//输出转速

#define Resister_ROdomH 0xE8//位置反馈高16位

#define Resister_ROdomL 0xE9//位置反馈低16位

#define Resister_RError 0xE3


//电机的组号,以及ID号

#define Group_Motors 0x00

#define ID_MASTER          0x00     //定义主机ID

#define ID_LeftMotor 0x05      //定义左伺服ID

#define ID_RightMotor 0x06      //定义右伺服ID


#define PI 3.1415926

#define Diameter 25 //轮子直径

#define PlusePerRound  2000 //脉冲数每转


#include "sys.h" 

#include "usart.h"

#include "delay.h"

#include "led.h" 

#include "oled.h"

#include "string.h"

#include "can.h"


//下面的速度单位是RPM,表示转每分钟(round per minute) 

void Motor_Init(void);

void Set_SpeedLimit(uint32_t ID, float limit_speed);

void Set_SpeedTarget(uint32_t ID, float target_speed);

//int Get_SpeedActual(uint32_t ID, float* actual_speed);

float Get_SpeedActual(uint32_t ID, float actual_speed);

int Get_Odometry(uint32_t ID, float* odom);

int Speed2RPM(float speed);

float RPM2Speed(int rpm);


#endif

写好指令后,首先用can分析仪给电机驱动器发消息,控制电机旋转,这样可以派出伺服驱动器是否有问题

如下

在这里插入图片描述

波特率的设置:1M,can通道用的2

在这里插入图片描述

首先看到接受到的数据是来自于伺服驱动器的心跳返回,

然后发送指令,发送正确后可以返回指令,可以看到can通讯成功了

在这里插入图片描述

其他指令是伺服驱动器的“心跳”,里面会包含我们自动报告的位置,速度等


然后我们用stm32与伺服驱动器进行通信

写入上述程序可以运行程序:

can分析仪:

在这里插入图片描述

然后发送指令,停止电机运转

在这里插入图片描述

can分析仪:

在这里插入图片描述

发现我们可以控制电机的运转和停止,并通过”心跳“可以取出返回的速度,这里目前只取出了一个速度并用OLED显示,希望显示实时速度,进行PID调试,后续还需要补充。

推荐阅读

史海拾趣

General Transistor Corp公司的发展小趣事

面对日益激烈的市场竞争,GTC及时调整市场策略,加强品牌建设。公司注重提升产品质量和服务水平,积极参与国内外各类电子产品展会和论坛,提高品牌知名度和影响力。同时,GTC还建立了完善的销售网络和售后服务体系,为客户提供更加便捷、高效的服务。这些举措有力地推动了公司业务的快速增长和市场份额的扩大。

DRS Technologies公司的发展小趣事

进入80年代,DRS开始拓展其业务范围。在1981年上市后,DRS于1984年收购了其第一家公司,迈出了其市场扩张的第一步。随后,DRS不断投入研发,致力于提高其在电子和信息技术领域的核心竞争力。特别是在C4ISR(指挥、控制、通信、计算机、情报、监视和侦察)系统领域,DRS取得了显著的成果,为其在全球市场上赢得了广泛的认可。

Don Connex Electronics Co Ltd公司的发展小趣事

Don Connex Electronics始终将研发创新作为公司的核心竞争力。公司每年将大量资金投入到新技术、新产品的研发中,不断推出具有市场竞争力的产品。同时,公司还积极与高校、科研机构合作,引进高端人才,加强技术研发力量。这些举措使Don Connex Electronics在激烈的市场竞争中始终保持领先地位。

Eska公司的发展小趣事

Eska公司成立于荷兰北部,自创立之初就专注于造纸业务。公司引进了先进的造纸技术和设备,建立了两座灰板纸厂,配备了3台技术领先的纸板机和2台造纸机。凭借高效的生产能力和优质的产品质量,Eska迅速在造纸行业中崭露头角。Eska的灰板纸以“Eska(青蛙)”品牌销售,因其优良且稳定的质量而享誉全球。

Corporation Soneet公司的发展小趣事

随着Soneet在技术领域取得的成功,公司开始积极拓展市场。Soneet与多家知名电子设备制造商建立了战略合作关系,共同开发新产品。通过与这些合作伙伴的紧密合作,Soneet的产品得以迅速进入全球市场,进一步提升了公司的知名度和影响力。

BALLUFF公司的发展小趣事

BALLUFF公司的历史可以追溯到1921年,由格布哈德·巴鲁夫(Gebhard Balluff)创建的一家机械修理厂开始。这家修理厂起初规模较小,但巴鲁夫凭借其对机械技术的精湛理解和不懈追求,逐渐将业务发展壮大。他通过不断的技术创新和产品升级,使得修理厂逐渐转型为一家专注于生产精密部件、车件和铣件的企业。这一转变不仅奠定了BALLUFF公司的工业基础,也为其日后在传感器领域的崛起打下了坚实基础。

问答坊 | AI 解惑

运算放大器稳定性

  作者:Tim Green,德州仪器 Burr-Brown 产品线线性应用工程经理   在写“保持容性负载稳定的六种方法”部分时发生了一件有趣的事情。我们选择了具有“轨至轨”输出的 CMOS 运算放大器并测量了 ROUT,但在高频区域没有环路增益,因而无 ...…

查看全部问答>

向阳1号油耗GPS和普通GPS的区别在哪里

北京向阳天科技有限公司(www.xiangyangtian.com) 是一家专业从事数据传输及全球卫星定位产品(GPS)研发、 应用的专业公司。其产品在全国车辆GPS定位市场上占有一席地位。 公司产品包括车载GPS定位仪、车载GPS导航仪、车辆油耗型GPS定位仪、 ...…

查看全部问答>

关于,电源、地的问题?

是不是LM3SXXXX的电源、地引脚是否必须连接到一起,并在每对上加上旁路电容??可不可以只有部分连接电源,而其它的不连接电源呢??会不会供电不足啊?PS:顺便问下由LM3S1138移植其它型号,要改些什么?工程模板可以直接用1138的吗?…

查看全部问答>

android的g-sensor驱动

请问谁有Freescale MMA7455的android驱动啊,挂在I2C上。有的请发我邮箱tigerhily@163.com 谢谢了…

查看全部问答>

c# 关于rfid读取的问题

我的rfid是能读出RFID卡内的序列号并通过PS/2输出至电脑,相当于自动键盘输号。 我用C#怎么才能实现读取阿? 产品说可用常用的《WORD》、《记事本》等软件记录卡号,为什么读不出来?? …

查看全部问答>

请教各位兄弟,南京福特的工程研究中心怎么样?

如题, 网上看到FORD正在搞SYNC系统,主要是体现更好的的人机交互,包含语音识别,TTS语音合成,触摸等多种交互形式。 周五去要面试一下…

查看全部问答>

STM32F103VBT6也有Y版么?

                                 问了国内某代理商,销售到技术都不清楚这个,真是晕!我要最新的Z版,可是他们却不清楚这些,我发现很多代理商对ST ...…

查看全部问答>

TI例程enet_io用到的CGI函数有谁能介绍吗

以太网中网页控制,enet-io这个例程里用到了SSI和CGI的结合,但是有些函数跟本不是一下子就能理解的,参数调来调去不好理解,有谁能给解释吗?  …

查看全部问答>

LPC800 开发板 I2C 的使能问题。

我把周立功的LPC800例子里面的I2C中的I2C_EEPROM的程序改了一下,还是无法运行,请帮忙看一下。 void I2CInit (void) {     //原始程序用的最适宜做I2C的口,小板上没有        //LPC_IOCON->PIO0_10   ...…

查看全部问答>