使用STM32H723VGT6芯片驱动达妙电机

首先,安装H7的pack包:

Arm Keil | Keil STM32H7xx_DFP

在这个网站中下载例如这个版本的pack包:

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

安装完成,点击Finish:


接下来就可以开发基于STM32H7的工程了,基于达妙官方开源的stm32例程【dm_ctrl(h7 fdcan)v1.1 裸机】进行研究:

官方文档:‍​​‌​​⁠‌‍​​‌‌‌‌‌‍​​⁠⁠​​​​⁠⁠​‌‌​‍‌​‍​‌2. 达妙电机上手流程(二)-使用开发板控制电机 - 飞书云文档

查看文档中的MIT模式控制,注意motorMotor1.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 模式用法说明:

  1. 当 kp=0 ,kd≠0 时,给定 v_des 即可实现匀速转动。匀速转动过程中存在静差,另外 kd 不宜过大,kd 过大时会引起震荡。

  2. 当 kp=0 ,kd=0 时,给定 t_ff 即可实现给定扭矩输出。在该情况下,电机会持续输出一个恒定力矩。但是当电机空转或负载较小时,如果给定 t_ff 较大,电机会持续加速,直到加速到最大速度,这时也仍然达不到目标力矩 t_ff。

  3. 当 kp≠0,kd=0 时,会引起震荡。即对位置进行控制时,kd不能赋0,否则会造成电机震荡,甚至失控。

  4. 当 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单片机,可以观察到电机按照指定轨迹运转!

相关推荐
元器件BOM超人17 小时前
STM32F103R8T6 中密度Cortex-M3 MCU 解析
stm32·单片机·嵌入式硬件
服务器硬件项目经理17 小时前
《超节点修仙录》· 第一卷·炼气期【第02话】 超节点的「身体构造」——CPU、GPU、内存、网卡都是干啥的
服务器·嵌入式硬件·gru·硬件工程·硬件
萌动的小火苗17 小时前
PCB设计中线宽、线距与过孔的基本概念
嵌入式硬件·pcb工艺
少卿.55517 小时前
wokwi搭建仿真超声波雷达测距判断(保姆级教学)
单片机·嵌入式硬件·arduino
C++ 老炮儿的技术栈18 小时前
机器人的坐标,像 XYZ 的坐标值,是用单精度浮点还是用双精度浮点?
c语言·c++·人工智能·单片机·c
深圳老胡18 小时前
STM32C562RET6 外部中断详解:从 EXTI 原理到 GPIO 外部中断实战
笔记·stm32·单片机·代码规范·1024程序员节
威嵌神州18 小时前
一台加固平板,能替掉几台现场设备?
嵌入式硬件·fpga开发·电脑·平板
编码追梦人19 小时前
ESP-IDF 实战:用 ESP32-C3 打造超低功耗 LoRa 无线传感器节点(深度睡眠 + OTA 全解析)
嵌入式硬件·lora·设计规范·esp-idf·esp32-c3·低功耗设计
编码追梦人19 小时前
基于 ESP32-S3 的便携式多参数环境监护仪设计:从硬件选型到 FreeRTOS 多任务落地
数据库·单片机·嵌入式硬件·mongodb·esp32·freertos·低功耗设计
wuyk5551 天前
防逆向基础:在量产固件中关闭调试接口并设置读保护(RDP)的正确姿势
stm32·单片机·嵌入式硬件·性能优化·重构