Files
2026-05-23 00:16:40 +08:00

304 lines
9.6 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef __MF4010V2__H__
#define __MF4010V2__H__
/**
* @file mf4010v2.h
* @brief MF4010V2 无刷电机驱动程序
* @note 改进版本:
* - 添加错误处理和返回值
* - 添加 CAN 超时机制
* - 使用安全的内联函数替代危险宏
* - 使用 HAL 层解耦硬件依赖
*
* 电机 CAN ID: 0x141 (默认)
* CAN 波特率1 Mbps
*/
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ============================================================================
* 状态码和错误定义
* ============================================================================ */
/**
* @brief MF4010V2 状态码
*/
typedef enum {
MF4010_OK = 0, /**< 成功 */
MF4010_ERR_TIMEOUT = -1, /**< CAN 通信超时 */
MF4010_ERR_INVALID_ID = -2, /**< 无效的 CAN ID */
MF4010_ERR_NO_RESPONSE = -3, /**< 无响应 */
MF4010_ERR_INVALID_PARAM = -4, /**< 无效参数 */
MF4010_ERR_BUS_OFF = -5, /**< CAN 总线关闭 */
MF4010_ERR_CRC = -6, /**< CRC 校验错误 */
MF4010_ERR_HARDWARE = -7, /**< 硬件错误 */
MF4010_ERR_CAN_SEND = -8, /**< CAN 发送失败 */
MF4010_ERR_CAN_RECV = -9, /**< CAN 接收失败 */
MF4010_ERR_BAD_RECV = -10
} mf4010_status_t;
/**
* @brief 电机状态标志
*/
typedef enum {
MF4010_FLAG_NONE = 0x00, /**< 无标志 */
MF4010_FLAG_RUNNING = 0x01, /**< 电机运行中 */
MF4010_FLAG_ENABLED = 0x02, /**< 电机已使能 */
MF4010_FLAG_FAULT = 0x04, /**< 故障状态 */
MF4010_FLAG_CONNECTED = 0x08 /**< 已连接 */
} mf4010_flag_t;
/* ============================================================================
* 电机结构体定义
* ============================================================================ */
/**
* @brief 电机结构体(优化版)
*/
typedef struct __mf4010v2_t {
int can_ch; /**< CAN 通道 (0 或 1) */
uint16_t id; /**< CAN ID (0x000-0x7FF) */
uint8_t last_response[8]; /**< 最后一次响应数据 */
uint32_t last_comm_time; /**< 最后通信时间戳 (ms) */
uint16_t error_count; /**< 通信错误计数 */
uint16_t success_count; /**< 成功通信计数 */
uint8_t flags; /**< 状态标志 (@ref mf4010_flag_t) */
int32_t target_angle; /**< 目标角度 (0.01 度) */
int32_t current_angle; /**< 当前角度 (0.01 度) - 从编码器读取 */
} mf4010v2_t;
typedef struct {
uint8_t angle_kp;
uint8_t angle_ki;
uint8_t speed_kp;
uint8_t speed_ki;
uint8_t iq_kp;
uint8_t iq_ki;
} pid_param;
/* ============================================================================
* 核心 API 函数
* ============================================================================ */
/**
* @brief 初始化电机结构体
* @param motor: 电机结构体指针
* @param id: 电机 CAN ID (范围 0x000-0x7FF如 0x141)
* @param can_ch: CAN 通道 (0=CAN1, 1=CAN2)
* @retval 成功返回 MF4010_OK失败返回错误码
*/
int mf4010v2_init(mf4010v2_t* motor, uint16_t id, int can_ch);
/**
* @brief 发送命令并接收响应(带超时)
* @param motor: 电机结构体指针
* @param command: 8 字节命令数据
* @retval 成功返回 MF4010_OK失败返回错误码
*/
int mf4010v2_send_command(mf4010v2_t* motor, const uint8_t command[8]);
void mf4010v2_run(mf4010v2_t* motor);
void mf4010v2_stop(mf4010v2_t* motor);
void mf4010v2_close(mf4010v2_t* motor);
int mf4010v2_set_speed(mf4010v2_t* motor, int32_t speed_0_01dps);
int mf4010v2_set_angle(mf4010v2_t* motor, int32_t angle_0_01deg);
int mf4010v2_read_pid_param(mf4010v2_t* motor, pid_param* pid);
int mf4010v2_get_motor_state(mf4010v2_t* motor, int8_t* tempture, int16_t* iq, int16_t* speed, int16_t* encoder);
/* Non-blocking variants — fire-and-forget, no CAN response polling */
int mf4010v2_set_speed_nb(mf4010v2_t* motor, int32_t speed_0_01dps);
int mf4010v2_close_nb(mf4010v2_t* motor);
/* ============================================================================
* 命令宏定义8 字节 CAN 命令帧)
* ============================================================================ */
/**
* @brief 电机关闭命令
* @note 命令字0x80
*/
#define COMMAND_MOTOR_CLOSE {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
/**
* @brief 电机运行命令
* @note 命令字0x88
*/
#define COMMAND_MOTOR_RUNNING {0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
/**
* @brief 电机停止命令
* @note 命令字0x81
*/
#define COMMAND_MOTOR_STOP {0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
/**
* @brief 读取 PID 参数命令
* @note 命令字0x30
*/
#define COMMAND_READ_PID_PARAMS {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
/* ============================================================================
* 安全命令生成函数(使用内联函数避免指针问题)
* ============================================================================ */
/**
* @brief 转矩闭环控制命令
* @param buf: 8 字节缓冲区(输出)
* @param iq: 转矩控制量 (-2048 ~ 2048)
* @note 分辨率1 LSB = 1 单位
*/
void cmd_torque_control(uint8_t* buf, int16_t iq);
/**
* @brief 速度闭环控制命令
* @param buf: 8 字节缓冲区(输出)
* @param speed: 速度控制量
* @note 分辨率0.01 DPS/LSB
* 范围:-204800 ~ +204800 (对应 -2048 ~ +2048 DPS)
* @example
* uint8_t cmd[8];
* cmd_speed_control(cmd, 10000); // 100 DPS
*/
void cmd_speed_control(uint8_t* buf, int32_t speed);
/**
* @brief 多圈位置闭环控制命令
* @param buf
* @param angleControl 0.01degree/LSB 36000表示360°
*/
void cmd_mult_ring_pos(uint8_t* buf, int32_t angleControl);
/**
* @brief 多圈位置闭环控制命令带速度限制
* @param buf
* @param maxSpeed 表示实际转速1dp/LSB 360表示360 dps
* @param angleControl 0.01degree/LSB 36000表示360°
*/
void cmd_mult_ring_pos_with_speed(uint8_t* buf, uint16_t maxSpeed, int32_t angleControl);
/**
* @brief 单圈位置闭环控制命令
* @param buf: 8 字节缓冲区(输出)
* @param direction: 旋转方向 (0x00=顺时针0x01=逆时针)
* @param angle: 目标角度 (单位0.01°, 如 36000=360°)
*/
void cmd_single_ring_pos(uint8_t* buf, uint8_t direction, uint32_t angle);
/**
* @brief 单圈位置闭环控制命令(带最大速度)
* @param buf: 8 字节缓冲区(输出)
* @param spinDirection: 旋转方向 (0x00=顺时针0x01=逆时针)
* @param maxSpeed: 最大速度 (单位DPS, 如 360=360 DPS)
* @param angleControl: 目标角度 (单位0.01°, 如 36000=360°)
*/
void cmd_single_ring_pos_with_speed(uint8_t* buf, uint8_t spinDirection,
uint16_t maxSpeed, uint32_t angleControl);
/**
* @brief 增量位置闭环控制命令
* @param buf: 8 字节缓冲区(输出)
* @param angle_increment: 角度增量 (单位0.01°, 如 36000=360°)
* @note 正值 = 逆时针,负值 = 顺时针
*/
void cmd_incr_pos(uint8_t* buf, int32_t angle_increment);
/**
* @brief 增量位置闭环控制命令(带最大速度)
* @param buf: 8 字节缓冲区(输出)
* @param max_speed 1dps/LSB
* @param angle_increment: 角度增量 (单位0.01°, 如 36000=360°)
* @note 正值 = 逆时针,负值 = 顺时针
*/
void cmd_incr_pos_with_speed(uint8_t* buf, uint16_t max_speed, int32_t angle_increment);
/**
* @brief PID 参数写入命令
* @param buf: 8 字节缓冲区(输出)
* @param location: 写入位置 (0x31=RAM, 0x32=ROM)
* @param angle_kp: 角度环 Kp (0-255)
* @param angle_ki: 角度环 Ki (0-255)
* @param speed_kp: 速度环 Kp (0-255)
* @param speed_ki: 速度环 Ki (0-255)
* @param iq_kp: 电流环 Kp (0-255)
* @param iq_ki: 电流环 Ki (0-255)
*/
void cmd_write_pid_params(uint8_t* buf, uint8_t location,
uint8_t angle_kp, uint8_t angle_ki,
uint8_t speed_kp, uint8_t speed_ki,
uint8_t iq_kp, uint8_t iq_ki);
/* ============================================================================
* 辅助函数和宏
* ============================================================================ */
/**
* @brief 检查电机是否在线
*/
bool mf4010v2_is_connected(mf4010v2_t* motor);
/**
* @brief 检查电机是否运行
*/
bool mf4010v2_is_running(mf4010v2_t* motor);
/**
* @brief 检查电机是否错误
*/
bool mf4010v2_is_fault(mf4010v2_t* motor);
/**
* @brief 获取电机错误计数
*/
uint16_t mf4010v2_get_error_count(mf4010v2_t* motor);
/**
* @brief 重置错误计数
*/
void mf4010v2_reset_errors(mf4010v2_t* motor);
/**
* @brief 获取响应中的命令字节
*/
#define MF4010_GET_RESPONSE_CMD(motor) ((motor)->last_response[0])
/**
* @brief 获取响应中的数据字节
*/
#define MF4010_GET_RESPONSE_DATA(motor, index) ((motor)->last_response[(index) + 1])
/**
* @brief 检查响应是否包含错误
* @note 如果响应字节 0 的最高位为 1表示有错误
*/
bool mf4010v2_response_has_error(mf4010v2_t* motor);
/**
* @brief 获取错误码(从响应中)
*/
uint8_t mf4010v2_get_error_code(mf4010v2_t* motor);
#ifdef __cplusplus
}
#endif
#endif /* __MF4010V2__H__ */