Files
agv-control-slam/docs/curtis/CURTIS_INTEGRATION_GUIDE.md
2025-11-15 16:05:59 +08:00

752 lines
19 KiB
Markdown
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.

# Curtis 电机控制器集成指南
## 概述
本指南介绍如何在 AGV 路径跟踪项目中集成柯蒂斯Curtis1298+1220C 电机控制器的 CAN 通讯功能。
**协议版本:** V4.0
**波特率:** 125 kbps
**厂商:** 上海诺力智能科技有限公司
---
## 目录
1. [快速开始](#快速开始)
2. [文件结构](#文件结构)
3. [编译和运行](#编译和运行)
4. [API 参考](#api-参考)
5. [完整调用流程](#完整调用流程)
6. [示例程序说明](#示例程序说明)
7. [故障排查](#故障排查)
8. [最佳实践](#最佳实践)
---
## 快速开始
### 1. 最简示例5行代码
```cpp
#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. 基本控制循环
```cpp
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. 编译
```bash
cd build
cmake ..
make
```
**编译目标:**
- `curtis_demo` - 键盘控制演示
- `curtis_path_tracking_demo` - 路径跟踪演示
### 2. 运行示例
**键盘控制演示:**
```bash
./curtis_demo
```
**路径跟踪演示:**
```bash
./curtis_path_tracking_demo
```
### 3. 在您的项目中使用
**在 CMakeLists.txt 中添加:**
```cmake
add_executable(your_program your_main.cpp
src/can/CurtisMotorController.cpp
)
target_link_libraries(your_program
${CMAKE_SOURCE_DIR}/lib/ControlCAN.dll
)
```
**在代码中包含头文件:**
```cpp
#include "include/can/CurtisMotorController.h"
```
---
## API 参考
### 核心类CurtisMotorController
#### 构造函数
```cpp
CurtisMotorController(DWORD deviceType = VCI_USBCAN2,
DWORD deviceIndex = 0,
DWORD canChannel = 0);
```
**参数:**
- `deviceType`: CAN 设备类型(默认 VCI_USBCAN2 = 4
- `deviceIndex`: 设备索引(默认 0 = 第一个设备)
- `canChannel`: CAN 通道(默认 0 = CAN1
#### 连接管理
```cpp
bool Connect(); // 连接到 Curtis 控制器
void Disconnect(); // 断开连接
bool IsConnected() const; // 检查是否已连接
```
#### 命令发送
```cpp
bool SendCommand(const CurtisCommand& cmd); // 发送控制命令
bool SendStopCommand(); // 发送停止命令
void EmergencyStop(); // 紧急停车
```
**重要:** 必须以 ≤20ms 周期持续发送命令,否则控制器会超时保护。
#### 状态接收
```cpp
bool ReceiveStatus(); // 接收状态反馈
const CurtisStatus& GetStatus() const; // 获取当前状态
void PrintStatus() const; // 打印状态到控制台
```
#### 故障检测
```cpp
bool HasError() const; // 检查是否有故障
bool IsTimeout(uint32_t timeoutMs) const; // 检查通讯超时
std::string GetErrorString() const; // 获取故障描述
```
#### 工具函数(静态)
```cpp
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控制命令
```cpp
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状态反馈
```cpp
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创建对象
```cpp
// 使用默认参数(设备类型=VCI_USBCAN2, 索引=0, 通道=0
CurtisMotorController curtis;
// 或指定参数
CurtisMotorController curtis(VCI_USBCAN2, 0, 0);
```
#### 步骤2连接
```cpp
if (!curtis.Connect()) {
std::cerr << "连接失败!" << std::endl;
return -1;
}
```
**内部执行:**
1. `VCI_OpenDevice()` - 打开 USB-CAN 设备
2. `VCI_InitCAN()` - 配置 125kbps 波特率
3. `VCI_StartCAN()` - 启动 CAN 通道
4. `VCI_ClearBuffer()` - 清空接收缓冲区
#### 步骤3主循环
```cpp
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断开连接
```cpp
curtis.Disconnect();
```
**内部执行:**
1. 发送停止命令(所有速度归零)
2. 等待 50ms 确保命令发送
3. 调用 `VCI_CloseDevice()` 关闭设备
---
## 示例程序说明
### 示例1键盘控制curtis_demo.cpp
**功能:**
- 键盘控制 AGV 运动
- 实时状态监控
- 故障和急停检测
**控制键:**
- `W/S` - 前进/后退30%
- `A/D` - 左转/右转30度
- `Q/E` - 提升/下降50%
- `H` - 鸣喇叭
- `T` - 切换龟速模式
- `空格` - 全部停止
- `P` - 打印状态
- `ESC` - 退出
**运行:**
```bash
cd build
./curtis_demo
```
**核心代码:**
```cpp
// 主循环
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
**功能:**
- 矩形路径跟踪
- 圆形路径跟踪
- 实时位置控制
- 故障自动中止
**运行:**
```bash
cd build
./curtis_path_tracking_demo
```
**核心代码:**
```cpp
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
**诊断命令:**
```cpp
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
**诊断代码:**
```cpp
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 总线连接不稳定
- 控制器参数设置不正确
**解决方案:**
```cpp
// 检查发送周期
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
```
- 检查角度转换:
```cpp
float degrees = 30.0f;
int16_t canValue = CurtisMotorController::AngleDegreeToCAN(degrees);
cout << "30° → CAN值 = " << canValue << endl; // 应为 300
```
#### 5. 收到故障代码
**症状:** `HasError()` 返回 true
**诊断:**
```cpp
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. 命令发送频率
**推荐做法:**
```cpp
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. 故障处理
**推荐做法:**
```cpp
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. 数值范围检查
**推荐做法:**
```cpp
// 使用工具函数自动限制范围
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. 状态回调
**推荐做法:**
```cpp
curtis.SetStatusCallback([](const CurtisStatus& status) {
// 状态更新时自动调用
if (status.batteryLevel < 20) {
cout << "[警告] 电量低: " << (int)status.batteryLevel << "%" << endl;
}
});
```
### 5. 安全断开
**推荐做法:**
```cpp
// 程序退出前
cout << "正在安全停止..." << endl;
curtis.SendStopCommand();
Sleep(100); // 等待停止生效
curtis.Disconnect();
```
### 6. 异常处理
**推荐做法:**
```cpp
try {
CurtisMotorController curtis;
if (!curtis.Connect()) {
throw runtime_error("连接失败");
}
// 主循环...
} catch (const exception& e) {
cerr << "异常: " << e.what() << endl;
curtis.Disconnect();
return -1;
}
```
### 7. 日志记录
**推荐做法:**
```cpp
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. 控制位定义
**控制位0Byte0**
| Bit | 功能 | 0 | 1 |
|-----|------|---|---|
| 0 | 调速开关 | 有效 | 无效 |
| 1 | 紧急反向 | 无效 | 有效 |
| 2 | 龟速模式 | 无效 | 有效 |
| 3 | 喇叭 | 无效 | 有效 |
| 4 | 左提升 | 无效 | 有效 |
| 5 | 左下降 | 无效 | 有效 |
| 6 | 右提升 | 无效 | 有效 |
| 7 | 右下降 | 无效 | 有效 |
**控制位1Byte1 - 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** - 原始协议文档
---
## 技术支持
如有问题,请参考:
1. `.claude/skills/curtis-motor-protocol.md` - 完整协议说明
2. `.claude/skills/can-protocol.md` - CAN 接口库文档
3. 示例程序源码
**厂商技术支持:** 上海诺力智能科技有限公司
---
**文档版本:** 1.0
**最后更新:** 2024-11-15
**作者:** AGV 路径跟踪项目组