Files
agv-control-slam/include/can/CurtisMotorController.h
2025-11-15 16:05:59 +08:00

298 lines
9.1 KiB
C++
Raw 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.

/**
* @file CurtisMotorController.h
* @brief 柯蒂斯Curtis1298+1220C 电机控制器 CAN 通讯接口
* @details 封装柯蒂斯电机控制器的 CAN 通讯协议,提供易用的控制接口
*
* 协议版本: V4.0
* 波特率: 125 kbps
* CAN ID:
* - 0x1E5: AGV → Curtis 控制命令(行走、提升)
* - 0x2E5: AGV → Curtis 转向命令
* - 0x260: Curtis → AGV 状态反馈
* - 0x360: Curtis → AGV 保留
*/
#ifndef CURTIS_MOTOR_CONTROLLER_H
#define CURTIS_MOTOR_CONTROLLER_H
#include "../../lib/ControlCAN.h"
#include <stdint.h>
#include <string>
#include <functional>
// ==================== CAN ID 定义 ====================
#define CURTIS_ID_DRIVE_CMD 0x1E5 ///< 行走/提升命令
#define CURTIS_ID_STEER_CMD 0x2E5 ///< 转向命令
#define CURTIS_ID_STATUS 0x260 ///< 状态反馈
#define CURTIS_ID_RESERVED 0x360 ///< 保留
// ==================== 数据范围定义 ====================
#define CURTIS_DRIVE_SPEED_MIN -4096
#define CURTIS_DRIVE_SPEED_MAX 4095
#define CURTIS_LIFT_SPEED_MIN -4096
#define CURTIS_LIFT_SPEED_MAX 4095
#define CURTIS_STEER_ANGLE_MIN -900 ///< -90度
#define CURTIS_STEER_ANGLE_MAX 900 ///< +90度
// ==================== 控制位掩码定义Byte0====================
#define CURTIS_CTRL_SPEED_SWITCH 0x01 ///< 调速开关0=有效)
#define CURTIS_CTRL_EMERGENCY_REVERSE 0x02 ///< 紧急反向
#define CURTIS_CTRL_TURTLE_MODE 0x04 ///< 龟速开关
#define CURTIS_CTRL_HORN 0x08 ///< 喇叭
#define CURTIS_CTRL_LIFT_LEFT_UP 0x10 ///< 左侧提升
#define CURTIS_CTRL_LIFT_LEFT_DOWN 0x20 ///< 左侧下降
#define CURTIS_CTRL_LIFT_RIGHT_UP 0x40 ///< 右侧提升
#define CURTIS_CTRL_LIFT_RIGHT_DOWN 0x80 ///< 右侧下降
// ==================== 控制位掩码定义Byte1 - AGV专用====================
#define CURTIS_CTRL_AGV_CONNECTED 0x01 ///< AGV连接标识必须设置
#define CURTIS_CTRL_EMERGENCY_STOP 0x02 ///< 紧急停车
#define CURTIS_CTRL_CENTERING_DONE 0x04 ///< 找中完成
// ==================== 状态位掩码定义Byte7====================
#define CURTIS_STATUS_AUTO_MODE 0x01 ///< 0=手动, 1=自动
#define CURTIS_STATUS_EMERGENCY_STOP 0x02 ///< 0=无急停, 1=急停
/**
* @brief Curtis 控制器状态结构
*/
struct CurtisStatus {
uint8_t driveError; ///< 行走故障代码
uint8_t steerError; ///< 转向故障代码
float currentAngle; ///< 当前转向角度(度)
int16_t motorSpeed; ///< 电机转速
uint8_t batteryLevel; ///< 电量百分比 0-100
bool isAutoMode; ///< 是否自动模式
bool isEmergencyStop; ///< 是否急停状态
uint32_t lastUpdateTime; ///< 最后更新时间戳(毫秒)
CurtisStatus() : driveError(0), steerError(0), currentAngle(0.0f),
motorSpeed(0), batteryLevel(0), isAutoMode(false),
isEmergencyStop(false), lastUpdateTime(0) {}
};
/**
* @brief Curtis 控制命令结构
*/
struct CurtisCommand {
int16_t driveSpeed; ///< 行走速度 -4096~4095
int16_t liftSpeedLeft; ///< 左侧提升速度 -4096~4095
int16_t liftSpeedRight; ///< 右侧提升速度 -4096~4095
int16_t steerAngle; ///< 转向角度 -900~900
uint8_t controlBits0; ///< 控制位0
uint8_t controlBits1; ///< 控制位1AGV专用
CurtisCommand() : driveSpeed(0), liftSpeedLeft(0), liftSpeedRight(0),
steerAngle(0), controlBits0(0), controlBits1(CURTIS_CTRL_AGV_CONNECTED) {}
};
/**
* @brief 柯蒂斯电机控制器类
*
* 提供完整的柯蒂斯 1298+1220C 电机控制器 CAN 通讯功能
*
* 使用流程:
* 1. 创建对象
* 2. 调用 Connect() 连接设备
* 3. 在主循环中以 ≤20ms 周期调用 SendCommand() 和 ReceiveStatus()
* 4. 结束时调用 Disconnect()
*
* @code
* CurtisMotorController curtis;
* curtis.Connect();
*
* while (running) {
* CurtisCommand cmd;
* cmd.driveSpeed = SpeedPercentToCAN(30.0f);
* curtis.SendCommand(cmd);
* curtis.ReceiveStatus();
* Sleep(15); // 15ms周期
* }
*
* curtis.Disconnect();
* @endcode
*/
class CurtisMotorController {
public:
/**
* @brief 状态回调函数类型
* @param status 更新后的状态
*/
using StatusCallback = std::function<void(const CurtisStatus&)>;
/**
* @brief 构造函数
* @param deviceType CAN 设备类型VCI_USBCAN2 = 4
* @param deviceIndex 设备索引第几个设备从0开始
* @param canChannel CAN 通道0 = CAN1, 1 = CAN2
*/
CurtisMotorController(DWORD deviceType = VCI_USBCAN2,
DWORD deviceIndex = 0,
DWORD canChannel = 0);
/**
* @brief 析构函数,自动断开连接
*/
~CurtisMotorController();
// ==================== 连接管理 ====================
/**
* @brief 连接到 Curtis 控制器
* @details 执行完整的连接流程:
* 1. 打开 CAN 设备
* 2. 初始化 CAN125kbps
* 3. 启动 CAN 通道
* 4. 清空缓冲区
* @return true=成功, false=失败
*/
bool Connect();
/**
* @brief 断开与 Curtis 控制器的连接
* @details 执行安全断开流程:
* 1. 发送停止命令
* 2. 关闭 CAN 设备
*/
void Disconnect();
/**
* @brief 检查是否已连接
* @return true=已连接, false=未连接
*/
bool IsConnected() const { return m_isConnected; }
// ==================== 命令发送 ====================
/**
* @brief 发送控制命令到 Curtis 控制器
* @details 发送两个 CAN 帧:
* - 0x1E5: 行走和提升命令
* - 0x2E5: 转向命令
* @param cmd 控制命令
* @return true=成功, false=失败
* @note 必须以 ≤20ms 周期持续发送,否则控制器会超时保护
*/
bool SendCommand(const CurtisCommand& cmd);
/**
* @brief 发送停止命令
* @details 所有速度和角度设为0
* @return true=成功, false=失败
*/
bool SendStopCommand();
/**
* @brief 紧急停车
* @details 连续发送3次急停命令确保接收
*/
void EmergencyStop();
// ==================== 状态接收 ====================
/**
* @brief 接收 Curtis 控制器状态反馈
* @details 接收并解析 0x260 状态帧,更新内部状态
* @return true=接收到新状态, false=没有新数据
*/
bool ReceiveStatus();
/**
* @brief 获取当前状态
* @return 状态结构的引用
*/
const CurtisStatus& GetStatus() const { return m_status; }
/**
* @brief 获取上次发送的命令
* @return 命令结构的引用
*/
const CurtisCommand& GetLastCommand() const { return m_lastCommand; }
/**
* @brief 设置状态更新回调函数
* @param callback 状态更新时调用的函数
*/
void SetStatusCallback(StatusCallback callback) {
m_statusCallback = callback;
}
// ==================== 故障和超时检测 ====================
/**
* @brief 检查是否有故障
* @return true=有故障, false=无故障
*/
bool HasError() const {
return m_status.driveError != 0 || m_status.steerError != 0;
}
/**
* @brief 检查通讯是否超时
* @param timeoutMs 超时时间(毫秒)
* @return true=超时, false=正常
*/
bool IsTimeout(uint32_t timeoutMs = 100) const;
/**
* @brief 获取故障信息字符串
* @return 故障描述
*/
std::string GetErrorString() const;
// ==================== 工具函数 ====================
/**
* @brief 速度百分比转 CAN 值
* @param percent 速度百分比 -100% ~ +100%
* @return CAN 值 -4096 ~ +4095
*/
static int16_t SpeedPercentToCAN(float percent);
/**
* @brief CAN 值转速度百分比
* @param canValue CAN 值 -4096 ~ +4095
* @return 速度百分比 -100% ~ +100%
*/
static float SpeedCANToPercent(int16_t canValue);
/**
* @brief 角度转 CAN 值(转向命令)
* @param degrees 角度 -90° ~ +90°
* @return CAN 值 -900 ~ +900
*/
static int16_t AngleDegreeToCAN(float degrees);
/**
* @brief CAN 值转角度(状态反馈)
* @param canValue CAN 值 -16383 ~ +16383
* @return 角度 -90° ~ +90°
*/
static float AngleCANToDegree(int16_t canValue);
/**
* @brief 打印当前状态到控制台
*/
void PrintStatus() const;
private:
// 设备参数
DWORD m_deviceType;
DWORD m_deviceIndex;
DWORD m_canChannel;
bool m_isConnected;
// 状态和命令
CurtisStatus m_status;
CurtisCommand m_lastCommand;
// 回调函数
StatusCallback m_statusCallback;
// 内部辅助函数
bool SendFrame(UINT canId, const BYTE* data, BYTE len);
void ParseStatusFrame(const VCI_CAN_OBJ& frame);
};
#endif // CURTIS_MOTOR_CONTROLLER_H