1. robomaster电机介绍
- 都是无刷直流电机
- 都可以CAN通信,能收能发,单片机控制电机所发送的报文以及电机反馈给单片机的报文格式类似
- 一圈(不考虑减速箱只考虑电机本身)刻度都是8192
a. M2006
-
- 需C610电调,电流控制
- 小巧玲珑
- 自带可拆卸减速箱,减速比为36
- 减速后扭矩仍然比较小
- 相对位置编码,上电时是0位
- 用于步兵子弹拨盘
b. M3508
-
- 需C620电调,电流控制
- 体积中等
- 自带可拆卸减速箱,减速比为3591/187(约等于19)
- 减速后扭矩较大,可以掰断碳纤维打印件
- 相对位置编码,上电时是0位
- 底盘轮组驱动,拆掉减速箱可以作为摩擦轮电机
c. GM6020
-
- 自带驱动板(无需电调),电压控制
- 体积中空,较大,看起来憨憨的
- 无减速箱
- 扭矩比减速后的2006大一点
- 绝对位置编码,掉电仍然有绝对刻度
- 用于舵轮底盘的舵向电机、云台航向角(yaw)以及俯仰角(pitch)电机
电机扭矩大小排序(减速后):M3508>GM6020>M2006
2. M3508电机控制方式(其它类比)
a. 接线方式如图所示
- 三相线传电流,其中有控制无刷电机的原理(不断切换磁极)
- 7pin先传输数据(电机反馈给电调的数据、单片机通过电调传给电机的数据)
- 24V电源线供电流
- CAN线连接CAN总线
b. 电调
i.指示灯描述
绿灯每隔 1 秒闪 N 次 当前电调的 ID 为 N,电调 ID 范围为 1 到 8
ii. SET按键操作
1. 独立设置 ID
用户对单个电调进行 ID(支持范围 1-8)设置,具体操作如下:
a. 电调正常工作状态下,短按 1 次 SET 按键,进入独立设置 ID 模式,此时指示灯熄灭。同一总线上不能出现 ID 重复的情况,否则ID冲突的电调将提示警告、关闭输出。
b. 若 3 秒未对 SET 按键进行操作,电调将自动保存当前设置 ID 号。设置完 ID 的电调需要重新上电才能进入正常工作状态。
c. 在独立设置 ID 模式下,短按 SET 按键的次数(不超过 8 次)即为设置的 ID 号。每次有效短按,指示灯将橙灯闪烁 1 次。
2. 快速设置ID
用户对总线上的所有C620电调(不超过8个进行快速编号,具体操作如下:
a. 正常工作状态下,对总线上任意 1 个 C620 电调的 SET 按键进行 1 次短按,进入独立 ID 设置模式后,再长按 SET 按键,此时总线上的所有电调将进入快速设置 ID 模式,所有电调指示灯为橙灯常亮。
b. 按照预设 ID 依次手动转动 C620 电调对应的M3508 直流无刷减速电机的转子(任意方向至少旋转半圈以上),电调会按照转动顺序自动从 1 依次开始编号,编号完成的电调需重新上电才能进入正常工作状态。
- 该模式下未设置 ID 的电机(未转动转子重新上电后会保持原有 ID)。
3. 电机校准
更换电机或电调后,为获得更好的电机适配参数,可运行电机校准程序。电调电机连接并接通电源后,用户通过对电机的位置传感器参数进行校准,以发挥电调的最佳性能,具体操作如下
a. 长按 SET 按键,直至指示灯变为绿灯快闪,释放 SET 按键。
b. 电机进入自动校准模式,待校准完成后自动退出校准模式。
- 电机校准时会转动,切勿触碰,建议在空载下进行该操作。若多次校准失败,请更换电机。
c. CAN通信报文
- 3508电机需要借助C620电调来控制电流,进而实现转动
- CAN通信为1Mbps
- CAN总线上可以允许有多个电调
- 单片机的CAN通信控制电调进而控制电机通过标准数据帧进行
- 帧的CAN ID为0x200或0x1ff,与电调的CAN ID有关
- 帧的数据长度为8字节
- 每个电调的CAN ID是不一样的,需要在硬件上进行配置
- 不同的CAN ID决定了电调获取了单片机发出控制信号对应的数据帧之后,对数据段哪几字节进行处理,并转化为电调需要给电机提供的电流
- 不同的CAN ID决定了电调反馈给单片机的反馈信号 对应 的数据帧的CAN ID,以便单片机对不同电机运动状态的掌握,以及进一步控制(反馈相关内容在PID应用时讲述)
- 电调的CAN ID不可以相同,否则会有冲突
i. CAN通信向电调发送报文
- 电调接收报文格式
用于向电调发送控制指令控制电调的电流输 出, 两个标识符(0x200 和 0x1FF) 各 自对 应 控 制 4 个 ID 的 电 调。 控 制 电 流 值 范 围-16384~0~16384,对应电调输出的转矩电流范围-20~0~20A(线性映射过来)
如果要发送数据给 1 号到 4 号电调,控制电机的输出电流,从而控制电机转速时,需要按照表中的内容,将发送的 CAN 数据帧的 ID 设置为 0x200,数据域中的 8Byte 数据按照电调 1 到 4 的高八位和第八位的顺序装填,帧格式和 DLC 也按照表中内容进行设置,最后进行数据的发送(用HAL库函数发送到CAN总线上)
ii.电调发送报文格式(电调向总线上发送的反馈数据)
首先根据接收到的 ID 判断究竟接收到的是哪个电调发送来的数据,手册中规定 1 号电调 ID为 0x201,2 号为 0x202,3 号为 0x203,4 号为 0x204。判断完数据来源之后,就可以按照手册中的数据格式进行解码,通过高八位和第八位拼接的方式,得到电机的转子机械角度,转子转速,转矩电流,电机温度等数据。
d. CAN 在 cubeMX 中的配置
1.首先在 cubeMX 中将 CAN1 开启,打开 Connectivity 下的 CAN1,进行 CAN1 的配置。
2. 在 Mode 中,将 Master Mode 选中打勾。
在Configuration界面中,需要进行CAN的波特率的配置,设置完分频系数 (Prescaler) 后,cubeMX 会自动完成 Time Quantum(简写为 tq)的计算,将 tq 乘以 tBS1 (Time Quanta inBit Segment 1),tBS2 (Time Quanta in Bit Segment 1),RJW (ReSynchronization JumpWidth) 之和刚好为 1 微秒,对应波特率为 1M,这是 CAN 总线支持的最高通讯速率。71.42857142857143𝑛𝑠(分频后一个时间片占的时间) ∗ (10 + 3 + 1) = 1000𝑛𝑠 = 1𝑢𝑠
3.CAN2 的配置和计算和 CAN1 类似。
e. CAN_receive.c中函数介绍
robomaster开发板c型官方例程中函数
i. CAN 的 发 送 函 数
CAN_cmd_chassis
- 用于向底盘电机发送 CAN 信号,控制电机运动。
- CAN_cmd_chassis 函数的输入为电机 1 到电机 4 的驱动电流期望值 motor1 到 motor4,函数会将期望值拆分成高八位和第八位,放入 8Byte 的 CAN 的数据域中,然后添加 ID(CAN_CHASSIS_ALL_ID 0x200),帧格式,数据长度等信息,形成一个完整的 CAN 数据帧,发送给各个电调。
void CAN_cmd_chassis(int16_t motor1, int16_t motor2, int16_t motor3, int16_t motor4)
{
uint32_t send_mail_box;
chassis_tx_message.StdId = CAN_CHASSIS_ALL_ID;
chassis_tx_message.IDE = CAN_ID_STD;
chassis_tx_message.RTR = CAN_RTR_DATA;
chassis_tx_message.DLC = 0x08;
chassis_can_send_data[0] = motor1 >> 8;
chassis_can_send_data[1] = motor1;
chassis_can_send_data[2] = motor2 >> 8;
chassis_can_send_data[3] = motor2;
chassis_can_send_data[4] = motor3 >> 8;
chassis_can_send_data[5] = motor3;
chassis_can_send_data[6] = motor4 >> 8;
chassis_can_send_data[7] = motor4;
HAL_CAN_AddTxMessage(&CHASSIS_CAN, &chassis_tx_message,
chassis_can_send_data, &send_mail_box);
}
HAL 库提供了实现 CAN 发送的函数 HAL_CAN_AddTXMessage
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan,
CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox)
函数名 | HAL_CAN_AddTXMessage |
函数功能 | 将一段数据通过 CAN 总线发送 |
返回值 | HAL_StatusTypeDef,HAL 库定义的几种状态,如果本次 CAN 发送成功,则返回 HAL_OK |
参数1 | CAN_HandleTypeDef *hcan,即 can 的句柄指针,如果是 can1 就输入&hcan1,can2 就输入&hcan2 |
参数2 | CAN_TxHeaderTypeDef *pHeader,待发送的 CAN 数据帧信息的结构体指针,包含了 CAN 的 ID,格式等重要信息 |
参数3 | uint8_t aData[],装载了待发送的数据的数组名称 |
参数4 | uint32_t *pTxMailbox,用于存储 CAN 发送所使用的邮箱号 |
在使用HAL_CAN_AddTXMessage前,需要把 帧格式、长度 通过对结构体赋值确定好,在作为该函数的参数(发送报文的作用)
CAN_cmd_gimbal
- 用于向云台电机发送 CAN 信号,控制电机运动。
- 输入参数为yaw 轴电机,pitch 轴电机,发射机构电机的驱动电流期望值 yaw,pitch,shoot(rev 为保留值),函数会将期望值拆分成高八位和第八位,放入 8Byte 的 CAN 的数据域中,然后添加 ID(CAN_GIMBAL_ALL_ID 0x1FF),帧格式,数据长度等信息,形成一个完整的 CAN数据帧,发送给各个电调。
void CAN_cmd_gimbal(int16_t yaw, int16_t pitch, int16_t shoot, int16_t rev)
{
uint32_t send_mail_box;
gimbal_tx_message.StdId = CAN_GIMBAL_ALL_ID;
gimbal_tx_message.IDE = CAN_ID_STD;
gimbal_tx_message.RTR = CAN_RTR_DATA;
gimbal_tx_message.DLC = 0x08;
gimbal_can_send_data[0] = (yaw >> 8);
gimbal_can_send_data[1] = yaw;
gimbal_can_send_data[2] = (pitch >> 8);
gimbal_can_send_data[3] = pitch;
gimbal_can_send_data[4] = (shoot >> 8);
gimbal_can_send_data[5] = shoot;
gimbal_can_send_data[6] = (rev >> 8);
gimbal_can_send_data[7] = rev;
HAL_CAN_AddTxMessage(&GIMBAL_CAN, &gimbal_tx_message,
gimbal_can_send_data, &send_mail_box);
}
ii. CAN 接收中断回调函数介绍
- STM32自带CAN控制器,箭头表示收发关系,直线表示我们自行接到外部的总线
- 发送方式:把发送的数据加到CAN收发器中,由它自主控制发送,换句话说放进去就不用管了
- 接收方式:从接收队列(FIFO队列)选择接收(一旦收到数据,会产生中断,从FIFO0和FIFO1选择一个来接收)接收是FIFO先接收到的,然后产生接收中断
- 每当FIFO完成一帧数据的接收时,就会触发一次 CAN 接收中断处理函数,接收中断函数完成一些寄存器的处理之后会调用 CAN 接收中断回调函数。
- HAL 库提供了 CAN 的接收中断回调函数HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_RxHeaderTypeDef rx_header;
uint8_t rx_data[8];
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);
switch (rx_header.StdId)
{
case CAN_3508_M1_ID:
case CAN_3508_M2_ID:
case CAN_3508_M3_ID:
case CAN_3508_M4_ID:
case CAN_YAW_MOTOR_ID:
case CAN_PIT_MOTOR_ID:
case CAN_TRIGGER_MOTOR_ID:
{
static uint8_t i = 0;
//get motor id
i = rx_header.StdId - CAN_3508_M1_ID;
get_motor_measure(&motor_chassis[i], rx_data);//进行解码
break;
}
default:
{
break;
}
}
}
在本次的程序中,在中断回调函数中首先判断接收对象的 ID,是否是需要的接收的电调发来的数据。完成判断之后,进行解码,将对应的电机的数据装入电机信息数组 motor_chassis各个对应的位中。
-
- 接收时调用了 HAL 库提供的接收函数 HAL_CAN_GetRxMessage
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo,
CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])
函数名 | HAL_CAN_GetRxMessage |
函数功能 | 接收 CAN 总线上发送来的数据 |
返回值 | HAL_StatusTypeDef,HAL 库定义的几种状态,如果本次CAN 接收成功,则返回 HAL_OK |
参数 1 | CAN_HandleTypeDef *hcan,即 can 的句柄指针,如果是 can1 就输入&hcan1,can2 就输入&hcan2 |
参数 2 | uint32_t RxFifo,接收时使用的 CAN 接收 FIFO 号,一般为 CAN_RX_FIFO0 |
参数 3 | CAN_RxHeaderTypeDef *pHeader,存储接收到的 CAN 数据帧信息的结构体指针,包含了 CAN 的 ID,格式等重要信息 |
参数4 | uint8_t aData[],存储接收到的数据的数组名称 |
-
- motor_chassis 为 motor_measure_t 类型的数组,其中装有电机转子角度,电机转子转速,
控制电流,温度等信息。
typedef struct
{
uint16_t ecd;
int16_t speed_rpm;
int16_t given_current;
uint8_t temperate;
int16_t last_ecd;
} motor_measure_t;
-
- 解码功能实际上完成的工作是将接收到的数据按照高八位和第八位的方式进行拼接,从而得
到电机的各个参数。
#define get_motor_measure(ptr, data) \
{ \
(ptr)->last_ecd = (ptr)->ecd; \
(ptr)->ecd = (uint16_t)((data)[0] << 8 | (data)[1]); \
(ptr)->speed_rpm = (uint16_t)((data)[2] << 8 | (data)[3]); \
(ptr)->given_current = (uint16_t)((data)[4] << 8 | (data)[5]); \
(ptr)->temperate = (data)[6]; \
}
f. bsp_can.c中函数介绍
void can_filter_init(void)
{
CAN_FilterTypeDef can_filter_st;
can_filter_st.FilterActivation = ENABLE;
can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK;
can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT;
can_filter_st.FilterIdHigh = 0x0000;
can_filter_st.FilterIdLow = 0x0000;
can_filter_st.FilterMaskIdHigh = 0x0000;
can_filter_st.FilterMaskIdLow = 0x0000;
can_filter_st.FilterBank = 0;
can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0;
HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);
HAL_CAN_Start(&hcan1);
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
can_filter_st.SlaveStartFilterBank = 14;
can_filter_st.FilterBank = 14;
HAL_CAN_ConfigFilter(&hcan2, &can_filter_st);
HAL_CAN_Start(&hcan2);
HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING);
}
- 滤波器代码(包括CAN的打开,FIFO中断的使能,FIFO的选择,掩码ID的设置),具体介绍见CAN通信软件配置工程