12 KiB
12 KiB
开发指南
本文档提供 AGV 路径跟踪与控制系统的开发指南,包括代码结构、开发流程和最佳实践。
目录
开发环境设置
Windows 开发环境(推荐)
1. 安装 MSYS2
从 msys2.org 下载并安装 MSYS2。
2. 安装开发工具
# 打开 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
export PATH="/c/Qt/Tools/mingw1310_64/bin:$PATH"
export PATH="/c/Qt/6.10.1/mingw_64/bin:$PATH"
Linux 开发环境
Ubuntu/Debian
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
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 中声明
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 中实现
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 中集成
bool PathTracker::generateControlSequence(..., const std::string& algorithm) {
// ...
if (algorithm == "lqr") {
delta = ControlGenerator::lqr(current_state, path_, Q, R);
}
// ...
}
Step 4: 编写测试
// 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: 创建新的控制器类
// include/can/NewMotorController.h
class NewMotorController {
public:
bool initialize(...);
void setSpeed(double speed);
void setSteering(double angle);
// ...
};
Step 2: 实现接口
// src/control/can/NewMotorController.cpp
#include "can/NewMotorController.h"
bool NewMotorController::initialize(...) {
// 初始化硬件
}
void NewMotorController::setSpeed(double speed) {
// 发送速度命令
}
Step 3: 创建示例程序
// examples/new_motor_demo.cpp
#include "can/NewMotorController.h"
int main() {
NewMotorController controller;
controller.initialize(...);
controller.setSpeed(1.0);
// ...
}
编码规范
命名约定
-
类名:大驼峰(PascalCase)
class PathTracker { }; -
函数名:小驼峰(camelCase)
void setReferencePath(...); -
变量名:下划线分隔(snake_case)
double lookahead_distance; -
常量:全大写加下划线
const double MAX_SPEED = 10.0; -
成员变量:后缀下划线
class MyClass { private: int value_; };
注释规范
头文件注释
/**
* @file path_tracker.h
* @brief 路径跟踪器类定义
* @author Your Name
* @date 2025-11-27
*/
类注释
/**
* @brief 路径跟踪器
*
* 整合 AGV 模型、路径和控制算法,提供完整的路径跟踪功能。
* 支持多种算法:Pure Pursuit、Stanley 等。
*/
class PathTracker {
// ...
};
函数注释
/**
* @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 个空格缩进
- 运算符两侧加空格
- 逗号后加空格
// 好的风格
int result = a + b * c;
function(arg1, arg2, arg3);
// 不好的风格
int result=a+b*c;
function(arg1,arg2,arg3);
大括号
// 推荐:K&R 风格
if (condition) {
// code
} else {
// code
}
// 或 Allman 风格(保持一致即可)
if (condition)
{
// code
}
else
{
// code
}
测试指南
单元测试
创建测试文件 src/control/tests/test_path_tracker.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;
}
集成测试
测试完整的系统流程:
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. 日志输出
在关键位置添加日志:
#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 脚本可视化结果:
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 调试
# 编译时添加调试符号
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)
valgrind --leak-check=full ./agv_demo
性能优化
1. 编译优化
# CMakeLists.txt
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native")
2. 代码优化
- 避免不必要的拷贝,使用引用
- 预分配内存
- 使用合适的数据结构
// 好的实践
void processPath(const PathCurve& path) { // 使用引用
std::vector<double> results;
results.reserve(path.size()); // 预分配
// ...
}
常见问题
Q: 编译时找不到 Qt
A: 设置 CMAKE_PREFIX_PATH:
cmake -DCMAKE_PREFIX_PATH=/path/to/Qt/6.10.1/mingw_64 ..
Q: CAN 通信失败
A: 检查:
- ControlCAN.dll 是否在 PATH 中
- 硬件是否正确连接
- 波特率是否匹配
Q: 路径跟踪精度不够
A: 尝试:
- 减小时间步长 dt
- 调整算法参数(lookahead_distance、k 等)
- 增加路径点密度
贡献指南
- Fork 项目
- 创建功能分支 (
git checkout -b feature/new-feature) - 提交更改 (
git commit -am 'Add new feature') - 推送到分支 (
git push origin feature/new-feature) - 创建 Pull Request
最后更新: 2025-11-27