Files
RCS-3000/docs/DEVELOPMENT.md
CaiXiang 7b6c956b6a initial
2025-11-27 15:20:21 +08:00

615 lines
12 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.

# 开发指南
本文档提供 AGV 路径跟踪与控制系统的开发指南,包括代码结构、开发流程和最佳实践。
## 目录
- [开发环境设置](#开发环境设置)
- [代码结构](#代码结构)
- [开发流程](#开发流程)
- [编码规范](#编码规范)
- [测试指南](#测试指南)
- [调试技巧](#调试技巧)
---
## 开发环境设置
### Windows 开发环境(推荐)
#### 1. 安装 MSYS2
从 [msys2.org](https://www.msys2.org/) 下载并安装 MSYS2。
#### 2. 安装开发工具
```bash
# 打开 MSYS2 MinGW 64-bit 终端
pacman -Syu # 更新包数据库
# 安装基础开发工具
pacman -S mingw-w64-x86_64-gcc
pacman -S mingw-w64-x86_64-cmake
pacman -S mingw-w64-x86_64-make
# 安装 Qt6
pacman -S mingw-w64-x86_64-qt6-base
pacman -S mingw-w64-x86_64-qt6-tools
```
#### 3. 配置 PATH
```bash
export PATH="/c/Qt/Tools/mingw1310_64/bin:$PATH"
export PATH="/c/Qt/6.10.1/mingw_64/bin:$PATH"
```
### Linux 开发环境
#### Ubuntu/Debian
```bash
sudo apt-get update
sudo apt-get install build-essential cmake
sudo apt-get install qt6-base-dev qt6-tools-dev
sudo apt-get install python3 python3-matplotlib
```
#### Fedora/RHEL
```bash
sudo dnf install gcc gcc-c++ cmake
sudo dnf install qt6-qtbase-devel
sudo dnf install python3 python3-matplotlib
```
### IDE 推荐
- **Visual Studio Code**: 轻量级,插件丰富
- C/C++ 插件
- CMake Tools 插件
- Qt tools 插件
- **Qt Creator**: Qt 开发首选
- **CLion**: 强大的 C++ IDE
---
## 代码结构
### 目录组织
```
agv-control-slam/
├── include/ # 公共头文件
│ ├── agv_model.h
│ ├── path_curve.h
│ ├── path_tracker.h
│ ├── control_generator.h
│ └── can/
│ ├── CANController.h
│ └── CurtisMotorController.h
├── src/ # 源文件实现
│ └── control/
│ ├── agv_model.cpp
│ ├── path_curve.cpp
│ ├── path_curve_custom.cpp
│ ├── path_tracker.cpp
│ ├── control_generator.cpp
│ └── can/
│ ├── CANController.cpp
│ └── CurtisMotorController.cpp
├── examples/ # 示例程序
│ ├── demo.cpp
│ ├── qt_gui_demo.cpp
│ ├── curtis_demo.cpp
│ └── ...
├── lib/ # 第三方库
│ ├── ControlCAN.dll
│ └── ControlCAN.lib
├── scripts/ # 工具脚本
├── docs/ # 文档
└── CMakeLists.txt # CMake 配置
```
### 模块划分
#### 1. 核心模块 (`agv_model`, `path_curve`)
负责基础的运动学模型和路径表示。
- **职责**:提供 AGV 运动学仿真和路径数据结构
- **依赖**C++ 标准库
- **接口**:清晰的类接口,便于单元测试
#### 2. 控制模块 (`control_generator`, `path_tracker`)
实现路径跟踪算法。
- **职责**Pure Pursuit、Stanley 等算法实现
- **依赖**:核心模块
- **接口**:算法参数可配置
#### 3. CAN 通信模块 (`can/`)
处理硬件通信。
- **职责**CAN 设备初始化、数据收发
- **依赖**ControlCAN 库
- **接口**:硬件抽象层
#### 4. 界面模块 (`examples/qt_gui_demo.cpp`)
提供可视化界面。
- **职责**:路径显示、参数调整、数据导出
- **依赖**Qt6、核心模块、控制模块
- **接口**:用户友好的 GUI
---
## 开发流程
### 1. 功能开发流程
```
需求分析 → 设计 → 实现 → 测试 → 文档 → 代码审查
```
#### 需求分析
- 明确功能需求和性能要求
- 确定接口设计
- 评估技术可行性
#### 设计
- 设计类结构和接口
- 确定数据结构
- 规划测试用例
#### 实现
- 遵循编码规范
- 编写清晰的注释
- 逐步实现功能
#### 测试
- 单元测试
- 集成测试
- 性能测试
#### 文档
- 更新 API 文档
- 编写使用示例
- 更新 README
### 2. 添加新算法
假设要添加一个新的路径跟踪算法 "LQR"
#### Step 1: 在 `control_generator.h` 中声明
```cpp
class ControlGenerator {
public:
// 现有算法...
/**
* @brief LQR 算法
* @param state 当前状态
* @param path 参考路径
* @param Q 状态权重矩阵
* @param R 控制权重
* @return 转向角
*/
static double lqr(
const AGVModel::State& state,
const PathCurve& path,
const Eigen::Matrix2d& Q,
double R
);
};
```
#### Step 2: 在 `control_generator.cpp` 中实现
```cpp
double ControlGenerator::lqr(
const AGVModel::State& state,
const PathCurve& path,
const Eigen::Matrix2d& Q,
double R
) {
// 实现 LQR 算法
// ...
return steering_angle;
}
```
#### Step 3: 在 `path_tracker.cpp` 中集成
```cpp
bool PathTracker::generateControlSequence(..., const std::string& algorithm) {
// ...
if (algorithm == "lqr") {
delta = ControlGenerator::lqr(current_state, path_, Q, R);
}
// ...
}
```
#### Step 4: 编写测试
```cpp
// examples/test_lqr.cpp
#include "path_tracker.h"
int main() {
AGVModel model(2.0, 1.0);
PathTracker tracker(model);
PathCurve path = PathCurve::generateCircularPath(5.0, 100);
tracker.setReferencePath(path);
tracker.generateControlSequence("lqr", 0.1, 10.0, 1.0);
// 验证结果...
}
```
### 3. 添加新的硬件接口
假设要添加对新电机控制器的支持:
#### Step 1: 创建新的控制器类
```cpp
// include/can/NewMotorController.h
class NewMotorController {
public:
bool initialize(...);
void setSpeed(double speed);
void setSteering(double angle);
// ...
};
```
#### Step 2: 实现接口
```cpp
// src/control/can/NewMotorController.cpp
#include "can/NewMotorController.h"
bool NewMotorController::initialize(...) {
// 初始化硬件
}
void NewMotorController::setSpeed(double speed) {
// 发送速度命令
}
```
#### Step 3: 创建示例程序
```cpp
// examples/new_motor_demo.cpp
#include "can/NewMotorController.h"
int main() {
NewMotorController controller;
controller.initialize(...);
controller.setSpeed(1.0);
// ...
}
```
---
## 编码规范
### 命名约定
- **类名**大驼峰PascalCase
```cpp
class PathTracker { };
```
- **函数名**小驼峰camelCase
```cpp
void setReferencePath(...);
```
- **变量名**下划线分隔snake_case
```cpp
double lookahead_distance;
```
- **常量**:全大写加下划线
```cpp
const double MAX_SPEED = 10.0;
```
- **成员变量**:后缀下划线
```cpp
class MyClass {
private:
int value_;
};
```
### 注释规范
#### 头文件注释
```cpp
/**
* @file path_tracker.h
* @brief 路径跟踪器类定义
* @author Your Name
* @date 2025-11-27
*/
```
#### 类注释
```cpp
/**
* @brief 路径跟踪器
*
* 整合 AGV 模型、路径和控制算法,提供完整的路径跟踪功能。
* 支持多种算法Pure Pursuit、Stanley 等。
*/
class PathTracker {
// ...
};
```
#### 函数注释
```cpp
/**
* @brief 生成控制序列
* @param algorithm 算法类型("pure_pursuit" 或 "stanley"
* @param dt 时间步长(秒)
* @param horizon 时域(秒)
* @param desired_velocity 期望速度m/s
* @return 成功返回 true失败返回 false
*/
bool generateControlSequence(
const std::string& algorithm,
double dt,
double horizon,
double desired_velocity
);
```
### 代码风格
#### 缩进和空格
- 使用 4 个空格缩进
- 运算符两侧加空格
- 逗号后加空格
```cpp
// 好的风格
int result = a + b * c;
function(arg1, arg2, arg3);
// 不好的风格
int result=a+b*c;
function(arg1,arg2,arg3);
```
#### 大括号
```cpp
// 推荐K&R 风格
if (condition) {
// code
} else {
// code
}
// 或 Allman 风格(保持一致即可)
if (condition)
{
// code
}
else
{
// code
}
```
---
## 测试指南
### 单元测试
创建测试文件 `src/control/tests/test_path_tracker.cpp`:
```cpp
#include "path_tracker.h"
#include <cassert>
#include <iostream>
void test_circular_path_tracking() {
AGVModel model(2.0, 1.0);
PathTracker tracker(model);
PathCurve path = PathCurve::generateCircularPath(5.0, 100);
tracker.setReferencePath(path);
AGVModel::State initial(0, -5, M_PI/2, 0);
tracker.setInitialState(initial);
bool success = tracker.generateControlSequence("pure_pursuit", 0.1, 10.0, 1.0);
assert(success && "Failed to generate control sequence");
const auto& sequence = tracker.getControlSequence();
assert(!sequence.predicted_states.empty() && "Empty control sequence");
std::cout << "✓ Circular path tracking test passed" << std::endl;
}
int main() {
test_circular_path_tracking();
// 更多测试...
return 0;
}
```
### 集成测试
测试完整的系统流程:
```cpp
void test_full_system() {
// 1. 创建模型
AGVModel model(2.0, 1.0);
PathTracker tracker(model);
// 2. 加载路径
PathCurve path = PathCurve::loadFromCSV("test_path.csv");
tracker.setReferencePath(path);
// 3. 生成控制
tracker.generateControlSequence("stanley", 0.1, 10.0, 1.0);
// 4. 导出结果
tracker.exportToCSV("test_output.csv");
// 5. 验证结果
// ...
}
```
---
## 调试技巧
### 1. 日志输出
在关键位置添加日志:
```cpp
#include <iostream>
#include <iomanip>
void PathTracker::generateControlSequence(...) {
std::cout << "[DEBUG] Starting control generation" << std::endl;
std::cout << " Algorithm: " << algorithm << std::endl;
std::cout << " dt: " << dt << ", horizon: " << horizon << std::endl;
// ...
std::cout << "[DEBUG] Generated " << steps << " control steps" << std::endl;
}
```
### 2. 数据可视化
使用 Python 脚本可视化结果:
```python
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('output.csv')
plt.figure(figsize=(10, 10))
plt.plot(data['ref_x'], data['ref_y'], 'b-', label='Reference')
plt.plot(data['x'], data['y'], 'r--', label='Trajectory')
plt.legend()
plt.axis('equal')
plt.savefig('debug_plot.png')
```
### 3. GDB 调试
```bash
# 编译时添加调试符号
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
# 使用 GDB
gdb ./agv_demo
(gdb) break path_tracker.cpp:50
(gdb) run
(gdb) print current_state
```
### 4. Valgrind 内存检查Linux
```bash
valgrind --leak-check=full ./agv_demo
```
---
## 性能优化
### 1. 编译优化
```cmake
# CMakeLists.txt
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native")
```
### 2. 代码优化
- 避免不必要的拷贝,使用引用
- 预分配内存
- 使用合适的数据结构
```cpp
// 好的实践
void processPath(const PathCurve& path) { // 使用引用
std::vector<double> results;
results.reserve(path.size()); // 预分配
// ...
}
```
---
## 常见问题
### Q: 编译时找不到 Qt
**A**: 设置 CMAKE_PREFIX_PATH
```bash
cmake -DCMAKE_PREFIX_PATH=/path/to/Qt/6.10.1/mingw_64 ..
```
### Q: CAN 通信失败
**A**: 检查:
1. ControlCAN.dll 是否在 PATH 中
2. 硬件是否正确连接
3. 波特率是否匹配
### Q: 路径跟踪精度不够
**A**: 尝试:
1. 减小时间步长 dt
2. 调整算法参数lookahead_distance、k 等)
3. 增加路径点密度
---
## 贡献指南
1. Fork 项目
2. 创建功能分支 (`git checkout -b feature/new-feature`)
3. 提交更改 (`git commit -am 'Add new feature'`)
4. 推送到分支 (`git push origin feature/new-feature`)
5. 创建 Pull Request
---
**最后更新**: 2025-11-27