298 lines
9.1 KiB
C++
298 lines
9.1 KiB
C++
/**
|
||
* @file CurtisMotorController.h
|
||
* @brief 柯蒂斯(Curtis)1298+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; ///< 控制位1(AGV专用)
|
||
|
||
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. 初始化 CAN(125kbps)
|
||
* 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
|