首先,安装H7的pack包:
在这个网站中下载例如这个版本的pack包:

下载完成后,双击pack文件进行安装,会自动安装到keil的安装路径中,再电机Next:

安装完成,点击Finish:

接下来就可以开发基于STM32H7的工程了,基于达妙官方开源的stm32例程【dm_ctrl(h7 fdcan)v1.1 裸机】进行研究:
官方文档:2. 达妙电机上手流程(二)-使用开发板控制电机 - 飞书云文档
查看文档中的MIT模式控制,注意motor[Motor1].id我的设置为了0x03:
cpp
/* 在 dm_motor_ctrl.c 文件中 */
void dm_motor_init(void)
{
memset(&motor[Motor1], 0, sizeof(motor[Motor1])); // 初始化Motor1电机结构体
// 设置Motor1的电机信息
motor[Motor1].id = 0x03;
motor[Motor1].mst_id = 0x00; // 实际没有用上,只做标识作用
motor[Motor1].tmp.read_flag = 1;
motor[Motor1].ctrl.mode = mit_mode; // 选择 MIT 模式
motor[Motor1].ctrl.vel_set = 1.0f; // 设置速度为 1
motor[Motor1].ctrl.pos_set = 0.0f;
motor[Motor1].ctrl.tor_set = 0.0f;
motor[Motor1].ctrl.cur_set = 0.0f;
motor[Motor1].ctrl.kp_set = 0.0f;
motor[Motor1].ctrl.kd_set = 1.0f; // 设置 Kd 为 1
// DM4310的 PMAX VMAX TMAX
motor[Motor1].tmp.PMAX = 12.5f;
motor[Motor1].tmp.VMAX = 30.0f;
motor[Motor1].tmp.TMAX = 10.0f;
}
/* 在 main.c 文件中*/
int main(void)
{
/* 截取添加的代码如下 */
power(1); // 打开开发板的可控电源接口
HAL_Delay(1000); // 等待电机上电自检通过
bsp_fdcan_set_baud(&hfdcan1, CAN_CLASS, CAN_BR_1M); // 设置CAN为经典模式 波特率为1M
bsp_can_init();
dm_motor_init();
HAL_Delay(10);
/* 往电机的寄存器里面写入MIT模式 */
write_motor_data(motor[Motor1].id, 10, mit_mode, 0, 0, 0); // 修改电机为MIT模式
HAL_Delay(100);
save_motor_data(motor[Motor1].id, 10); // 保存电机参数
HAL_Delay(100);
dm_motor_enable(&hfdcan1, &motor[Motor1]); // 使能电机
HAL_Delay(1000);
HAL_TIM_Base_Start_IT(&htim3); // 开启1ms定时器中断用于发送can命令
while (1)
{
}
}
// 1ms 定时器中断函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3) {
dm_motor_ctrl_send(&hfdcan1, &motor[Motor1]);
}
}
/* 在 dm_motor_ctrl.c 文件中 */
// 接收中断回调 处理电机回传的信息,默认master id为0,所以这里 rec_id = 0
void fdcan1_rx_callback(void)
{
uint16_t rec_id;
uint8_t rx_data[8] = {0};
fdcanx_receive(&hfdcan1, &rec_id, rx_data);
switch (rec_id)
{
case 0x00: dm_motor_fbdata(&motor[Motor1], rx_data); receive_motor_data(&motor[Motor1], rx_data); break;
}
}
将上面代码下载入单片机,可以观察到电机匀速旋转
接下来,我们再来基于MIT 模式来使电机按照指定轨迹运动:
电机 MIT模式的控制框图:


给出MIT 模式用法说明:
-
当 kp=0 ,kd≠0 时,给定 v_des 即可实现匀速转动。匀速转动过程中存在静差,另外 kd 不宜过大,kd 过大时会引起震荡。
-
当 kp=0 ,kd=0 时,给定 t_ff 即可实现给定扭矩输出。在该情况下,电机会持续输出一个恒定力矩。但是当电机空转或负载较小时,如果给定 t_ff 较大,电机会持续加速,直到加速到最大速度,这时也仍然达不到目标力矩 t_ff。
-
当 kp≠0,kd=0 时,会引起震荡。即对位置进行控制时,kd不能赋0,否则会造成电机震荡,甚至失控。
-
当 kp≠0,kd≠0 时,有多种情况,这里下面简单介绍两种情况。
-
当期望位置 p_des 为常量,期望速度 v_des 为0时,可实现定点控制,在这个过程中,实际位置趋近于p_des ,实际速度 dθm 趋近于0。
-
当p_des 是随时间变化的连续可导函数时,同时 v_des 是 p_des 的导数,可实现位置跟踪和速度跟踪,即按照期望速度旋转期望角度。
以下是基于达妙H7开发板的一个简单例子:
cpp
// mit 模式控制函数
void mit_ctrl(hcan_t* hcan, motor_t *motor, uint16_t motor_id, float pos, float vel,float kp, float kd, float tor)
{
uint8_t data[8];
uint16_t pos_tmp,vel_tmp,kp_tmp,kd_tmp,tor_tmp;
uint16_t id = motor_id + MIT_MODE;
pos_tmp = float_to_uint(pos, -motor->tmp.PMAX, motor->tmp.PMAX, 16);
vel_tmp = float_to_uint(vel, -motor->tmp.VMAX, motor->tmp.VMAX, 12);
tor_tmp = float_to_uint(tor, -motor->tmp.TMAX, motor->tmp.TMAX, 12);
kp_tmp = float_to_uint(kp, KP_MIN, KP_MAX, 12);
kd_tmp = float_to_uint(kd, KD_MIN, KD_MAX, 12);
data[0] = (pos_tmp >> 8);
data[1] = pos_tmp;
data[2] = (vel_tmp >> 4);
data[3] = ((vel_tmp&0xF)<<4)|(kp_tmp>>8);
data[4] = kp_tmp;
data[5] = (kd_tmp >> 4);
data[6] = ((kd_tmp&0xF)<<4)|(tor_tmp>>8);
data[7] = tor_tmp;
fdcanx_send_data(hcan, id, data, 8);
}
基于这个mit_ctrl,我们来修改原先的main函数,补充如下代码:
cpp
// 电机控制变量
static float time = 0.0f; // 时间累积
static float kp = 1.0f; // 比例增益
static float kd = 1.0f; // 微分增益
static float tor_set = 0.0f; // 力矩设定值
static float pos_set = 0.0f; // 位置设定值
static float vel_set = 0.0f; // 速度设定值
// 轨迹生成参数
const float amplitude = 1.0f; // 正弦波幅度
const float frequency = 1.0f; // 正弦波频率(Hz)
const float PI = 3.1415926f; // π值
// 1ms 定时器中断函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
// if (htim->Instance == TIM3) {
//
// read_all_motor_data(&motor[Motor1]);
//
// if(motor[Motor1].tmp.read_flag == 0)
// dm_motor_ctrl_send(&hfdcan1, &motor[Motor1]);
// }
if (htim->Instance == TIM3) {
time=time+0.001f;
kp=1.0f;
kd=1.0f;
tor_set=0.0f;
pos_set=sin(2*3.1415926f*1.0f*time);
vel_set=2*3.1415926f*1.0f*cos(2*3.1415926f*1.0f*time);
mit_ctrl(&hfdcan1, &motor[Motor1], 3, pos_set, vel_set, kp, kd,tor_set); //MIT模式发送力矩; // 电机ID: 3
}
}
将该代码下载入H7单片机,可以观察到电机按照指定轨迹运转!