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

12 KiB
Raw Blame History

开发指南

本文档提供 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: 检查:

  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