19 KiB
19 KiB
Curtis 电机控制器集成指南
概述
本指南介绍如何在 AGV 路径跟踪项目中集成柯蒂斯(Curtis)1298+1220C 电机控制器的 CAN 通讯功能。
协议版本: V4.0 波特率: 125 kbps 厂商: 上海诺力智能科技有限公司
目录
快速开始
1. 最简示例(5行代码)
#include "include/can/CurtisMotorController.h"
CurtisMotorController curtis;
curtis.Connect(); // 连接
CurtisCommand cmd;
cmd.driveSpeed = CurtisMotorController::SpeedPercentToCAN(30.0f); // 前进30%
curtis.SendCommand(cmd); // 发送命令
curtis.ReceiveStatus(); // 接收状态
curtis.PrintStatus(); // 打印状态
curtis.Disconnect(); // 断开
2. 基本控制循环
CurtisMotorController curtis;
curtis.Connect();
CurtisCommand cmd;
cmd.driveSpeed = CurtisMotorController::SpeedPercentToCAN(30.0f);
cmd.steerAngle = CurtisMotorController::AngleDegreeToCAN(15.0f);
while (running) {
curtis.ReceiveStatus(); // 接收状态
curtis.SendCommand(cmd); // 发送命令(≤20ms周期)
Sleep(15); // 15ms
}
curtis.Disconnect();
文件结构
核心文件
agv_path_tracking/
├── include/can/
│ └── CurtisMotorController.h # Curtis 控制器头文件
├── src/can/
│ └── CurtisMotorController.cpp # Curtis 控制器实现
├── examples/
│ ├── curtis_demo.cpp # 键盘控制示例
│ └── curtis_path_tracking_demo.cpp # 路径跟踪示例
├── lib/
│ ├── ControlCAN.h # CAN 接口库头文件
│ └── ControlCAN.dll # CAN 接口库
└── docs/curtis/
└── CURTIS_INTEGRATION_GUIDE.md # 本文档
技能文档
.claude/skills/
├── can-protocol.md # USB-CAN 接口函数库参考
└── curtis-motor-protocol.md # Curtis 协议详细说明
编译和运行
1. 编译
cd build
cmake ..
make
编译目标:
curtis_demo- 键盘控制演示curtis_path_tracking_demo- 路径跟踪演示
2. 运行示例
键盘控制演示:
./curtis_demo
路径跟踪演示:
./curtis_path_tracking_demo
3. 在您的项目中使用
在 CMakeLists.txt 中添加:
add_executable(your_program your_main.cpp
src/can/CurtisMotorController.cpp
)
target_link_libraries(your_program
${CMAKE_SOURCE_DIR}/lib/ControlCAN.dll
)
在代码中包含头文件:
#include "include/can/CurtisMotorController.h"
API 参考
核心类:CurtisMotorController
构造函数
CurtisMotorController(DWORD deviceType = VCI_USBCAN2,
DWORD deviceIndex = 0,
DWORD canChannel = 0);
参数:
deviceType: CAN 设备类型(默认 VCI_USBCAN2 = 4)deviceIndex: 设备索引(默认 0 = 第一个设备)canChannel: CAN 通道(默认 0 = CAN1)
连接管理
bool Connect(); // 连接到 Curtis 控制器
void Disconnect(); // 断开连接
bool IsConnected() const; // 检查是否已连接
命令发送
bool SendCommand(const CurtisCommand& cmd); // 发送控制命令
bool SendStopCommand(); // 发送停止命令
void EmergencyStop(); // 紧急停车
重要: 必须以 ≤20ms 周期持续发送命令,否则控制器会超时保护。
状态接收
bool ReceiveStatus(); // 接收状态反馈
const CurtisStatus& GetStatus() const; // 获取当前状态
void PrintStatus() const; // 打印状态到控制台
故障检测
bool HasError() const; // 检查是否有故障
bool IsTimeout(uint32_t timeoutMs) const; // 检查通讯超时
std::string GetErrorString() const; // 获取故障描述
工具函数(静态)
static int16_t SpeedPercentToCAN(float percent); // 速度百分比 → CAN值
static float SpeedCANToPercent(int16_t canValue); // CAN值 → 速度百分比
static int16_t AngleDegreeToCAN(float degrees); // 角度 → CAN值
static float AngleCANToDegree(int16_t canValue); // CAN值 → 角度
数据结构
CurtisCommand(控制命令)
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标识)
};
CurtisStatus(状态反馈)
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; // 最后更新时间戳
};
完整调用流程
流程图
┌─────────────────────────────────────────────┐
│ 1. 创建 CurtisMotorController 对象 │
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 2. Connect() │
│ ├─ VCI_OpenDevice() 打开CAN设备 │
│ ├─ VCI_InitCAN() 初始化(125kbps) │
│ ├─ VCI_StartCAN() 启动CAN通道 │
│ └─ VCI_ClearBuffer() 清空缓冲区 │
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 3. 主循环(≤15ms 周期) │
│ ┌──────────────────────────────────────┐ │
│ │ ① ReceiveStatus() │ │
│ │ └─ 接收并解析 0x260 状态帧 │ │
│ │ │ │
│ │ ② 检查故障和急停 │ │
│ │ ├─ HasError() │ │
│ │ ├─ IsTimeout() │ │
│ │ └─ 如有异常,执行 EmergencyStop() │ │
│ │ │ │
│ │ ③ 设置控制命令 │ │
│ │ ├─ SpeedPercentToCAN() │ │
│ │ └─ AngleDegreeToCAN() │ │
│ │ │ │
│ │ ④ SendCommand() │ │
│ │ ├─ 发送 0x1E5 行走/提升命令 │ │
│ │ └─ 发送 0x2E5 转向命令 │ │
│ │ │ │
│ │ ⑤ Sleep(15) │ │
│ └──────────────────────────────────────┘ │
└─────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 4. Disconnect() │
│ ├─ SendStopCommand() 发送停止命令 │
│ └─ VCI_CloseDevice() 关闭设备 │
└─────────────────────────────────────────────┘
详细步骤说明
步骤1:创建对象
// 使用默认参数(设备类型=VCI_USBCAN2, 索引=0, 通道=0)
CurtisMotorController curtis;
// 或指定参数
CurtisMotorController curtis(VCI_USBCAN2, 0, 0);
步骤2:连接
if (!curtis.Connect()) {
std::cerr << "连接失败!" << std::endl;
return -1;
}
内部执行:
VCI_OpenDevice()- 打开 USB-CAN 设备VCI_InitCAN()- 配置 125kbps 波特率VCI_StartCAN()- 启动 CAN 通道VCI_ClearBuffer()- 清空接收缓冲区
步骤3:主循环
CurtisCommand cmd;
DWORD lastTime = GetTickCount();
while (running) {
// 3.1 接收状态
curtis.ReceiveStatus();
const CurtisStatus& status = curtis.GetStatus();
// 3.2 检查故障
if (curtis.HasError()) {
std::cout << curtis.GetErrorString() << std::endl;
}
// 3.3 检查急停
if (status.isEmergencyStop) {
cmd.driveSpeed = 0;
cmd.steerAngle = 0;
}
// 3.4 设置命令
cmd.driveSpeed = CurtisMotorController::SpeedPercentToCAN(30.0f);
cmd.steerAngle = CurtisMotorController::AngleDegreeToCAN(15.0f);
// 3.5 发送命令(15ms周期)
if (GetTickCount() - lastTime >= 15) {
curtis.SendCommand(cmd);
lastTime = GetTickCount();
}
Sleep(5);
}
关键点:
- 命令周期: 必须 ≤20ms,推荐 10-15ms
- 状态接收: 每次循环都调用
ReceiveStatus() - 故障检测: 实时检查故障和急停状态
- 数值转换: 使用工具函数进行单位转换
步骤4:断开连接
curtis.Disconnect();
内部执行:
- 发送停止命令(所有速度归零)
- 等待 50ms 确保命令发送
- 调用
VCI_CloseDevice()关闭设备
示例程序说明
示例1:键盘控制(curtis_demo.cpp)
功能:
- 键盘控制 AGV 运动
- 实时状态监控
- 故障和急停检测
控制键:
W/S- 前进/后退(30%)A/D- 左转/右转(30度)Q/E- 提升/下降(50%)H- 鸣喇叭T- 切换龟速模式空格- 全部停止P- 打印状态ESC- 退出
运行:
cd build
./curtis_demo
核心代码:
// 主循环
while (running) {
curtis.ReceiveStatus(); // 接收状态
if (_kbhit()) {
char ch = _getch();
switch (ch) {
case 'w':
cmd.driveSpeed = SpeedPercentToCAN(30.0f);
break;
// ... 其他键处理
}
}
if (GetTickCount() - lastSendTime >= 15) {
curtis.SendCommand(cmd); // 15ms周期
lastSendTime = GetTickCount();
}
Sleep(5);
}
示例2:路径跟踪(curtis_path_tracking_demo.cpp)
功能:
- 矩形路径跟踪
- 圆形路径跟踪
- 实时位置控制
- 故障自动中止
运行:
cd build
./curtis_path_tracking_demo
核心代码:
for (size_t i = 0; i < path.size(); i++) {
double targetX = path[i].x;
double targetY = path[i].y;
while (true) {
curtis.ReceiveStatus();
// 计算距离和方向
double dx = targetX - currentX;
double dy = targetY - currentY;
double distance = sqrt(dx*dx + dy*dy);
if (distance < 0.1) break; // 到达
// 计算转向角度和速度
double targetAngle = atan2(dy, dx);
cmd.steerAngle = AngleDegreeToCAN(angleError);
cmd.driveSpeed = SpeedPercentToCAN(30.0f);
curtis.SendCommand(cmd);
Sleep(15);
}
}
故障排查
常见问题
1. 连接失败
症状: Connect() 返回 false
解决方案:
- 检查 USB-CAN 设备是否连接
- 检查驱动是否正确安装
- 确认
ControlCAN.dll在正确位置 - 检查设备索引是否正确(通常为 0)
诊断命令:
VCI_BOARD_INFO info;
if (VCI_ReadBoardInfo(VCI_USBCAN2, 0, &info) == 1) {
cout << "设备序列号: " << info.str_Serial_Num << endl;
}
2. 控制器无响应
症状: 发送命令后车辆不动
检查清单:
- AGV 标识位是否设置(Byte1 Bit0 = 1)
- 命令发送频率是否 ≤20ms
- 手动模式下 J9/SW_3 是否闭合
- 自动模式下 J24/SW_1 是否为 ON
- 波特率是否为 125kbps
诊断代码:
const CurtisCommand& lastCmd = curtis.GetLastCommand();
cout << "最后命令: " << endl;
cout << " driveSpeed = " << lastCmd.driveSpeed << endl;
cout << " steerAngle = " << lastCmd.steerAngle << endl;
cout << " controlBits1 = 0x" << hex << (int)lastCmd.controlBits1 << endl;
3. 频繁超时
症状: IsTimeout() 频繁返回 true
原因:
- 命令发送周期 > 20ms
- CAN 总线连接不稳定
- 控制器参数设置不正确
解决方案:
// 检查发送周期
DWORD lastTime = GetTickCount();
curtis.SendCommand(cmd);
DWORD elapsed = GetTickCount() - lastTime;
cout << "发送耗时: " << elapsed << "ms" << endl; // 应 < 20ms
4. 转向不准确
症状: 转向角度与预期不符
解决方案:
- 确认 1220C 参数配置:
can steer left stop to centre = -900 can steer right stop to centre = 900 - 检查角度转换:
float degrees = 30.0f; int16_t canValue = CurtisMotorController::AngleDegreeToCAN(degrees); cout << "30° → CAN值 = " << canValue << endl; // 应为 300
5. 收到故障代码
症状: HasError() 返回 true
诊断:
const CurtisStatus& status = curtis.GetStatus();
cout << "行走故障: 0x" << hex << (int)status.driveError << endl;
cout << "转向故障: 0x" << hex << (int)status.steerError << endl;
cout << curtis.GetErrorString() << endl;
处理:
- 查阅 Curtis 故障代码手册
- 检查电机连接和电源
- 检查控制器参数配置
最佳实践
1. 命令发送频率
推荐做法:
const int SEND_PERIOD_MS = 15; // 15ms周期
DWORD lastSendTime = GetTickCount();
while (running) {
if (GetTickCount() - lastSendTime >= SEND_PERIOD_MS) {
curtis.SendCommand(cmd);
lastSendTime = GetTickCount();
}
Sleep(5);
}
避免:
- ❌ 周期 > 20ms(会超时)
- ❌ 不规律的发送间隔
- ❌ 只发送一次就停止
2. 故障处理
推荐做法:
curtis.ReceiveStatus();
const CurtisStatus& status = curtis.GetStatus();
// 实时检查故障
if (curtis.HasError()) {
cout << "[故障] " << curtis.GetErrorString() << endl;
curtis.EmergencyStop();
// 记录日志
logError(status.driveError, status.steerError);
// 通知上层
notifyError();
}
// 检查急停
if (status.isEmergencyStop) {
cout << "[急停] 停止所有运动" << endl;
cmd.driveSpeed = 0;
cmd.steerAngle = 0;
curtis.SendCommand(cmd);
}
3. 数值范围检查
推荐做法:
// 使用工具函数自动限制范围
float speedPercent = 120.0f; // 超出范围
int16_t canSpeed = CurtisMotorController::SpeedPercentToCAN(speedPercent);
// 自动限制到 100% → 4095
// 或手动检查
cmd.driveSpeed = canSpeed;
if (cmd.driveSpeed > CURTIS_DRIVE_SPEED_MAX) {
cmd.driveSpeed = CURTIS_DRIVE_SPEED_MAX;
}
4. 状态回调
推荐做法:
curtis.SetStatusCallback([](const CurtisStatus& status) {
// 状态更新时自动调用
if (status.batteryLevel < 20) {
cout << "[警告] 电量低: " << (int)status.batteryLevel << "%" << endl;
}
});
5. 安全断开
推荐做法:
// 程序退出前
cout << "正在安全停止..." << endl;
curtis.SendStopCommand();
Sleep(100); // 等待停止生效
curtis.Disconnect();
6. 异常处理
推荐做法:
try {
CurtisMotorController curtis;
if (!curtis.Connect()) {
throw runtime_error("连接失败");
}
// 主循环...
} catch (const exception& e) {
cerr << "异常: " << e.what() << endl;
curtis.Disconnect();
return -1;
}
7. 日志记录
推荐做法:
void logStatus(const CurtisStatus& status) {
ofstream log("curtis_log.txt", ios::app);
log << GetTickCount() << ","
<< (int)status.driveError << ","
<< (int)status.steerError << ","
<< status.currentAngle << ","
<< status.motorSpeed << ","
<< (int)status.batteryLevel << endl;
}
// 定期调用
if (GetTickCount() - lastLogTime >= 1000) {
logStatus(curtis.GetStatus());
lastLogTime = GetTickCount();
}
附录
A. CAN ID 映射表
| CAN ID | 方向 | 描述 | 数据内容 |
|---|---|---|---|
| 0x1E5 | AGV → Curtis | 控制命令 | 行走速度、提升速度、控制位 |
| 0x2E5 | AGV → Curtis | 转向命令 | 转向角度 |
| 0x260 | Curtis → AGV | 状态反馈 | 故障、角度、转速、电量、状态 |
| 0x360 | Curtis → AGV | 保留 | 保留字段 |
B. 控制位定义
控制位0(Byte0):
| Bit | 功能 | 0 | 1 |
|---|---|---|---|
| 0 | 调速开关 | 有效 | 无效 |
| 1 | 紧急反向 | 无效 | 有效 |
| 2 | 龟速模式 | 无效 | 有效 |
| 3 | 喇叭 | 无效 | 有效 |
| 4 | 左提升 | 无效 | 有效 |
| 5 | 左下降 | 无效 | 有效 |
| 6 | 右提升 | 无效 | 有效 |
| 7 | 右下降 | 无效 | 有效 |
控制位1(Byte1 - AGV专用):
| Bit | 功能 | 0 | 1 |
|---|---|---|---|
| 0 | AGV标识 | 无效 | 连接(必须) |
| 1 | 紧急停车 | 无效 | 急停 |
| 2 | 找中完成 | - | 完成 |
| 3-7 | 保留 | - | - |
C. 数据范围表
| 参数 | 最小值 | 最大值 | 单位 | 说明 |
|---|---|---|---|---|
| 行走速度 | -4096 | 4095 | - | 负值=后退 |
| 提升速度 | -4096 | 4095 | - | 负值=下降 |
| 转向角度(命令) | -900 | 900 | 0.1° | -900=-90° |
| 转向角度(反馈) | -16383 | 16383 | 0.1° | -16383=-90° |
| 电量 | 0 | 100 | % | 百分比 |
D. 相关文档
- can-protocol.md - USB-CAN 接口函数库参考
- curtis-motor-protocol.md - Curtis 协议详细说明
- CAN_Protocol.pdf - CAN 通讯协议基础
- 柯蒂斯通信协议.pdf - 原始协议文档
技术支持
如有问题,请参考:
.claude/skills/curtis-motor-protocol.md- 完整协议说明.claude/skills/can-protocol.md- CAN 接口库文档- 示例程序源码
厂商技术支持: 上海诺力智能科技有限公司
文档版本: 1.0 最后更新: 2024-11-15 作者: AGV 路径跟踪项目组