【电机驱动】使用STM32H723开发GIM8018-9电机
关于GIM8018-9
GIM8018-9是伺泰威公司推出了一款行星减速电机,基于MIT协议。本文所使用的是24V的,额定扭矩为8.78Nm。
使用上位机进行电机调试
伺泰威官方开发了上位机,能够用于更改电机参数,例如ID、Kp、Kd,手动调节参数发送到电机上执行,便于进行电机调试。电机有几个控制模式:
Motor Mode:选择电机模式后,电机会开始接收上位机的命令,并根据所给定的参数运行。Reset Mode:选择复位模式后,电机会退出电机模式,在该模式下,电机不会接收任何上位机发送的控制参数。ZeroPosition:用于设置电机的机械零位置。MotorTest:用于运行设置好的测试,执行逻辑为:电机的机械位置置零,发送控制参数:Position=6.28,Velocity=0.0,Kp=15.0,Kd=0.2,Torque=0.0,结果是让电机外转子转一圈。
除此之外,上位机右下角还有命令转换工具,可以直观地看到所设定的控制参数如何转换为8位的数据包,再通过CAN通信发送到电机的。
使用上位机进行调试需要使用伺泰威的USB转CAN,否则无法检测出固件库,无法调试,tb链接:
https://item.taobao.com/item.htm?ft=t&id=901423286567
使用STM32H723进行开发
这部分官方提供的资料比较少,主要是一个基于STM32F0的测试例程以及《USB2CAN使用说明文档》。本文使用的是达妙科技推出的基于STM32H7的电机开发板DM-MC02进行开发(开发板麻雀虽小五脏俱全,使用过后爱不释手)。
关于开发板的基本配置以及FDCAN配置这里就不赘述了,不太清楚的同学可以学习大佬的文章,FDCAN的各种配置、消息的发送和接收等等都讲得非常详细:
https://zhuanlan.zhihu.com/p/714301640
由于需要使用两个电机,我这里使能了FDCAN1和FDCAN2两路CAN,都配置成1Mbps,记得一定要开启接收中断。
配置完开发板后,将官方提供的测试例程中的can_comm.c以及对应的头文件移植到工程下。这个BSP主要有两个关键函数,一个用于设定电机的控制模式,另一个用于设定电机的参数。
void Can1Comm_ControlCmd(uint8_t cmd)
{
uint8_t buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
switch(cmd)
{
case CMD_MOTOR_MODE:
buf[7] = 0xFC;
break;
case CMD_RESET_MODE:
buf[7] = 0xFD;
break;
case CMD_ZERO_POSITION:
buf[7] = 0xFE;
break;
default:
return; /* 直接退出函数 */
}
FDCAN1_Send_Msg(buf, CAN_SLAVE_ID);
}
- 该函数主要是用于设定电机的控制模式。根据上文可知,电机需要先进入
Motor Mode才能接收控制参数。因此在发送控制参数之前,需要先对电机进行使能(一般都需要使能)。
/**
* @brief Can总线发送控制参数
* @param
* @retval
*/
void Can1Comm_SendControlPara(float f_p, float f_v, float f_kp, float f_kd, float f_t)
{
uint16_t p, v, kp, kd, t;
uint8_t buf[8];
/* 限制输入的参数在定义的范围内 */
LIMIT_MIN_MAX(f_p, P_MIN, P_MAX);
LIMIT_MIN_MAX(f_v, V_MIN, V_MAX);
LIMIT_MIN_MAX(f_kp, KP_MIN, KP_MAX);
LIMIT_MIN_MAX(f_kd, KD_MIN, KD_MAX);
LIMIT_MIN_MAX(f_t, T_MIN, T_MAX);
/* 根据协议,对float参数进行转换 */
p = float_to_uint(f_p, P_MIN, P_MAX, 16);
v = float_to_uint(f_v, V_MIN, V_MAX, 12);
kp = float_to_uint(f_kp, KP_MIN, KP_MAX, 12);
kd = float_to_uint(f_kd, KD_MIN, KD_MAX, 12);
t = float_to_uint(f_t, T_MIN, T_MAX, 12);
/* 根据传输协议,把数据转换为CAN命令数据字段 */
buf[0] = p>>8;
buf[1] = p&0xFF;
buf[2] = v>>4;
buf[3] = ((v&0xF)<<4)|(kp>>8);
buf[4] = kp&0xFF;
buf[5] = kd>>4;
buf[6] = ((kd&0xF)<<4)|(t>>8);
buf[7] = t&0xff;
/* 通过CAN接口把buf中的内容发送出去 */
FDCAN1_Send_Msg(buf, CAN_SLAVE_ID);
}
- 该函数主要是将控制参数发送到电机驱动板上。主要流程就是将函数输入参数进行限幅,随后对
float类型的参数转换为uint类型,随后对数据进行打包,最后通过CAN发送函数发送给电机(从这段官方给出的代码中可以知道发送的数据包是如何定义的)。
在can_comm.c中还定义了CAN接收中断的回调函数:
/**
* @brief CAN接口接收数据
* @param
* @retval
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint16_t tmp_value;
CAN_RxHeaderTypeDef RxHead; /**!< can通信协议头 */
uint8_t data[8];
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHead, data);
if(data[0] == CAN_SLAVE_ID)
{
tmp_value = (data[3]<<4)|(data[4]>>4);
CurVelocity = uint_to_float(tmp_value, V_MIN, V_MAX, 12);
}
}
- 逻辑就是通过中断接收电机的反馈数据,随后对反馈数据进行解码。在这里速度反馈是通过一个12位的无符号整数进行存储的,是从两个字节中提取一个中间跨字节的12位(高位+低位)数据,这在通信协议的自定义压缩格式中很常见。为了便于理解,这里对这一过程进行分解:
假设:
data[3] = 0b10101010; // 高8位
data[4] = 0b11001100; // 用高4位 = 1100
(data[3] << 4)
= 0b10101010 << 4
= 0b101010100000 // 高8位向左移4位,占据高12位的前8位
(data[4] >> 4)
= 0b11001100 >> 4
= 0b00001100 // 提取低4位,补齐
组合:
tmp_value = 0b101010100000 | 0b00001100
= 0b101010101100 // 总共12位
但是这个函数只含有Velocity,没有其他数据的获取。在看官方提供的资料时并没有找到该数据包的格式,而我这里又需要电机的Torque,从而实现力矩控制。中间是通过反复的调试,完善了其他反馈数据的获取方式。
- 整个接收数据包是由一个8个字节的数组存储的,每个字节有8位。
- 第一个字节用来存储电机ID。
- 第二、三字节用来存储电机的
Position,因此位置信息是通过一个16位的无符号整数进行存储的。 - 第四字节和第五字节的高4位用来存储电机的
Velocity,对应上文的代码。 - 第五字节的低4位置和第六字节用来存储电机的
Torque,也是通过一个12位的无符号整数进行存储的。 - 第七和第八字节分别用来存储
Kp、Kd,通过一个8位的无符号整数进行存储的。
参照以上定义,就可以通过CAN接收中断进行电机数据接收并解码数据包得到电机Torque了:
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
if (hfdcan == &hfdcan1)
{
uint16_t tmp_value;
FDCAN1_Receive_Msg((uint8_t *)data);
if(data[0] == CAN_SLAVE_ID)
{
// tmp_value = (data[3]<<4)|(data[4]>>4);
// Can1MotorCurVelocity = uint_to_float(tmp_value, V_MIN, V_MAX, 12);
tmp_value = ((data[4] & 0x0F) << 8) | data[5];
Can1MotorCurTorque = uint_to_float(tmp_value, T_MIN, T_MAX, 12);
}
}
if (hfdcan == &hfdcan2)
{
uint16_t tmp_value;
FDCAN2_Receive_Msg((uint8_t *)data);
if(data[0] == CAN_SLAVE_ID)
{
tmp_value = (data[3]<<4)|(data[4]>>4);
Can2MotorCurVelocity = uint_to_float(tmp_value, V_MIN, V_MAX, 12);
}
}
}
完整的工程我已经上传到Github,链接在下面。希望能够帮助到使用同款电机的同学。除此之外,工程还包含十轴IMU的数据获取(JY901B,含有气压计),以及LCD屏幕的初始化,便于通过屏幕进行调试。
https://github.com/Xianhl25/GIM8018-9_DM02_DoubleFDCAN.git
更改电机ID
之前一直分别使用两路CAN控制两个电机,但是之后需要使用一路CAN同时接收两个电机的数据,因此需要对其中一个电机更改ID,这里补充一下电机ID更改的步骤,也感谢商家客服的及时解答。
为了修改电机ID,需要使用一个MX1.25 3P的连接线与电机驱动板的串口连接:

接下来通过TTL转串口向电机驱动板的串口发送命令。首先将TTL转串口连接到电脑上,配置波特率为921600,然后先打开串口,再给电机上电。这时候就会收到以下信息:

鼠标点击上位机上方空白区域,键盘输入s,进入设置:

同样,鼠标点击上位机上方空白区域,键盘依次输入i、2以及Enter,就能够将电机的ID改为2:

至此,电机的ID修改成功。
参考
https://www.steadywin.cn/pd.jsp?id=15&fromColId=0#_pp=0_643_3
《USB2CAN使用说明文档》
更多推荐

所有评论(0)