2. 开发环境搭建:Ubuntu系统配置、ROS/ROS2安装与工作空间创建、Eigen3与Ceres Solver库编译、VSCode调试环境配置

说实话,环境搭建这件事,很多新手觉得就是“装软件”,没什么技术含量。但我在项目里踩过的坑,十有八九都跟环境配置有关。库版本不对、编译器不兼容、路径写死——这些问题一旦出现,排查起来比写代码还痛苦。

这一章,我会带你从头搭一套能真正用于导航开发的系统环境。不是那种“装完能跑Hello World就行”的玩具环境,而是能支撑你后续做EKF融合、图优化、路径规划的生产环境。

2.1 Ubuntu系统基础配置

我个人习惯用Ubuntu 20.04 LTS,搭配ROS Noetic。如果你用22.04,那就走ROS2 Humble路线。两条路都能走通,但别混着来——我见过有人Ubuntu 20.04硬装ROS2 Galactic,结果依赖冲突到怀疑人生。

2.1.1 换源与基础工具链

装完系统第一件事,换源。别用官方源,国内速度太慢。

# 备份原源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

# 替换为清华源(Ubuntu 20.04)
sudo sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list
sudo sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list

sudo apt update && sudo apt upgrade -y

然后装基础工具链。这些是后面编译各种库的基石:

sudo apt install -y build-essential cmake git wget curl \
    python3-pip python3-dev python3-vcstool \
    libeigen3-dev libgoogle-glog-dev libgflags-dev \
    libatlas-base-dev libsuitesparse-dev
我的习惯:装完系统后,我会先装一个htop和neofetch。前者看资源占用,后者确认系统版本。调试时一眼就能知道是不是环境问题。

2.1.2 显卡驱动与CUDA(可选但推荐)

如果你要用到Ceres Solver的自动求导加速,或者跑一些视觉导航算法,NVIDIA显卡驱动和CUDA是必须的。我建议用ubuntu-drivers自动安装:

sudo ubuntu-drivers autoinstall
sudo reboot

# 验证
nvidia-smi

CUDA我一般装11.8,兼容性最好。别追最新版,很多库还没适配。

2.2 ROS/ROS2安装与工作空间创建

ROS是导航开发的骨架。消息通信、TF变换、可视化——全得靠它。我建议你两个都装,但日常开发只用其中一个。我自己是ROS Noetic为主,ROS2 Humble为辅做测试。

2.2.1 ROS Noetic(Ubuntu 20.04)

# 添加ROS源
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

sudo apt update
sudo apt install -y ros-noetic-desktop-full

# 初始化rosdep
sudo rosdep init
rosdep update

# 环境变量
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

2.2.2 ROS2 Humble(Ubuntu 22.04)

# 添加ROS2源
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

sudo apt update
sudo apt install -y ros-humble-desktop

# 环境变量
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc
注意:ROS1和ROS2的setup.bash不能同时source。我见过有人两个都写进.bashrc,结果rosrun命令都找不到。建议用别名切换,或者写个脚本按需加载。

2.2.3 创建工作空间

工作空间是ROS项目的容器。我习惯用catkin_tools(ROS1)或colcon(ROS2)来管理。

# ROS1 - catkin_tools
sudo apt install -y python3-catkin-tools
mkdir -p ~/nav_ws/src
cd ~/nav_ws
catkin init
catkin build

# ROS2 - colcon
mkdir -p ~/nav2_ws/src
cd ~/nav2_ws
colcon build

# 别忘了source
echo "source ~/nav_ws/devel/setup.bash" >> ~/.bashrc

为什么要用catkin_tools而不是catkin_make?因为前者支持并行编译、增量编译,还能单独编译某个包。我在项目里编译整个导航栈时,catkin_tools能省一半时间。

2.3 Eigen3与Ceres Solver库编译

这两个库是导航算法的数学引擎。Eigen3做矩阵运算,Ceres Solver做非线性优化。别用apt直接装——版本太老,而且缺少一些关键模块。

2.3.1 编译Eigen3

Eigen3是头文件库,但为了后续Ceres能找到它,我建议还是走一遍cmake流程:

cd ~
git clone https://gitlab.com/libeigen/eigen.git
cd eigen
mkdir build && cd build
cmake ..
sudo make install

# 验证
pkg-config --modversion eigen3
关键点:Eigen3默认安装到/usr/local/include/eigen3。如果Ceres编译时找不到,可以手动设置-DEIGEN3_INCLUDE_DIR。

2.3.2 编译Ceres Solver

Ceres的依赖比较多,尤其是SuiteSparse和glog。我之前在服务器上编译,缺了libcxsparse,结果Ceres的稀疏矩阵求解器直接罢工。

# 确保依赖齐全
sudo apt install -y libgoogle-glog-dev libgflags-dev \
    libatlas-base-dev libsuitesparse-dev

cd ~
git clone https://ceres-solver.googlesource.com/ceres-solver
cd ceres-solver
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
         -DEIGEN3_INCLUDE_DIR=/usr/local/include/eigen3 \
         -DCXSPARSE=ON \
         -DGFLAGS=ON \
         -DGLOG=ON
make -j$(nproc)
sudo make install

# 验证
ceres_version=$(pkg-config --modversion ceres)
echo "Ceres version: $ceres_version"

编译完成后,可以用Ceres自带的示例测试:

./bin/simple_bundle_adjuster ../data/problem-16-22106-pre.txt

如果看到优化迭代输出,说明安装成功。

避坑指南:我曾经在ARM架构的板子上编译Ceres,发现SuiteSparse的BLAS库不兼容。后来改用-DSUITESPARSE=OFF,用Eigen的稀疏求解器替代,才跑通。如果你在嵌入式平台上编译,可以试试这个方案。

2.4 VSCode调试环境配置

写导航算法,调试是家常便饭。VSCode配合CMake和GDB,能让你在代码里打断点、看变量、甚至可视化矩阵数据。

2.4.1 安装插件

我必装的几个插件:

插件名 用途
C/C++ (ms-vscode.cpptools) 语法高亮、智能提示、调试
CMake Tools (ms-vscode.cmake-tools) CMake项目一键配置与编译
ROS (ms-iot.vscode-ros) ROS消息、节点、launch文件支持
Python Python调试与代码补全

2.4.2 配置launch.json

调试ROS节点时,launch.json是关键。我一般这样配:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "ROS: Launch Node",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/devel/lib/${input:packageName}/${input:nodeName}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ],
    "inputs": [
        {
            "id": "packageName",
            "type": "promptString",
            "description": "Enter the package name"
        },
        {
            "id": "nodeName",
            "type": "promptString",
            "description": "Enter the node executable name"
        }
    ]
}

这样每次调试时,只需要输入包名和节点名,VSCode会自动编译并启动GDB。

2.4.3 调试Eigen矩阵

调试导航算法时,经常要看Eigen矩阵的值。GDB默认显示不了,需要装eigen-gdb-pretty-printer:

# 下载pretty-printer
git clone https://gitlab.com/libeigen/eigen.git
cp -r eigen/eigen/debug/gdb/pretty_printer ~/.gdbinit.d/

# 在~/.gdbinit中添加
echo "source ~/.gdbinit.d/pretty_printer/eigen.py" >> ~/.gdbinit
echo "eigen::register_eigen_pretty_printers()" >> ~/.gdbinit

配置好后,在调试时输入print my_matrix,就能看到矩阵的完整内容,而不是一堆地址。

注意:如果你用ROS2,调试时记得先source ROS2的环境变量。我习惯在VSCode的tasks.json里加上"options": {"env": {"ROS_DISTRO": "humble"}},避免每次手动设置。

2.5 环境验证与常见问题

环境搭完了,怎么确认没问题?我一般跑一个最小测试:

# 测试Eigen3
cat > test_eigen.cpp << EOF
#include 
#include 
int main() {
    Eigen::Matrix3d m;
    m << 1, 2, 3, 4, 5, 6, 7, 8, 9;
    std::cout << "Eigen works!\n" << m << std::endl;
    return 0;
}
EOF
g++ -I/usr/local/include/eigen3 test_eigen.cpp -o test_eigen
./test_eigen

# 测试Ceres
cat > test_ceres.cpp << EOF
#include 
int main() {
    ceres::Problem problem;
    std::cout << "Ceres works!" << std::endl;
    return 0;
}
EOF
g++ test_ceres.cpp -o test_ceres -lceres -lglog -lgflags
./test_ceres

如果都能正常输出,恭喜你,环境搭好了。

常见问题速查:
  • 找不到ros.h:检查source了没有,或者工作空间有没有编译。
  • Ceres编译报错undefined reference to 'cholmod_l_*':缺libcholmod,装libsuitesparse-dev。
  • VSCode调试时断点不生效:检查CMakeLists.txt里有没有加-g -O0编译选项。

嗯,环境搭建这部分就到这里。别嫌麻烦——一个干净、可复现的环境,能让你在后续的算法调试中少走很多弯路。我每次换新机器,都会按这个流程走一遍,确保所有库的版本一致。这样出了问题,至少能确定不是环境的问题。

开发环境搭建知识体系 Ubuntu 系统层 ROS / ROS2 工作空间 Eigen3 Ceres Solver VSCode 调试 从系统层到工具层,每一层都依赖下一层正确配置。建议按顺序搭建,不要跳步。 换源 → 装ROS → 编译Eigen3/Ceres → 配置VSCode调试