概述
实验室师兄之前用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%20Login%20Sucess&&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调试,后续还需要补充。
代码分享:
链接:https://pan.baidu.com/s/1ct7v_hC6gEpfyGtFw2fvkQ
提取码:w18w
最后
以上就是魁梧硬币为你收集整理的stm32与伺服驱动器进行can通信的全部内容,希望文章能够帮你解决stm32与伺服驱动器进行can通信所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复