关于GIM8018-9

GIM8018-9是伺泰威公司推出了一款行星减速电机,基于MIT协议。本文所使用的是24V的,额定扭矩为8.78Nm

使用上位机进行电机调试

伺泰威官方开发了上位机,能够用于更改电机参数,例如IDKpKd,手动调节参数发送到电机上执行,便于进行电机调试。电机有几个控制模式:

  • Motor Mode:选择电机模式后,电机会开始接收上位机的命令,并根据所给定的参数运行。
  • Reset Mode:选择复位模式后,电机会退出电机模式,在该模式下,电机不会接收任何上位机发送的控制参数。
  • ZeroPosition:用于设置电机的机械零位置。
  • MotorTest:用于运行设置好的测试,执行逻辑为:电机的机械位置置零,发送控制参数:Position=6.28,Velocity=0.0,Kp=15.0,Kd=0.2,Torque=0.0,结果是让电机外转子转一圈。

除此之外,上位机右下角还有命令转换工具,可以直观地看到所设定的控制参数如何转换为8位的数据包,再通过CAN通信发送到电机的。
空载条件下设定0.5Nm
使用上位机进行调试需要使用伺泰威的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位的无符号整数进行存储的。
  • 第七和第八字节分别用来存储KpKd,通过一个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,进入设置:

在这里插入图片描述

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

在这里插入图片描述

至此,电机的ID修改成功。

参考

https://www.steadywin.cn/pd.jsp?id=15&fromColId=0#_pp=0_643_3
《USB2CAN使用说明文档》
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐