1. 环境准备与依赖安装

在Ubuntu系统上搭建ArduPilot SITL仿真环境,首先需要配置好基础环境。我推荐使用Ubuntu 18.04或20.04 LTS版本,这两个版本在社区支持度和软件兼容性方面表现最好。如果你用的是虚拟机,建议分配至少4GB内存和20GB磁盘空间,不然编译时可能会卡顿。

安装前先更新软件源,虽然国内用户可能会觉得慢,但这一步很重要,能避免很多依赖问题。我通常会用阿里云或清华的镜像源来加速,具体操作是在终端里输入:

sudo sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
sudo apt-get update

接下来安装MAVProxy,这是SITL仿真的核心组件,负责地面站和飞控之间的通信。原始文章提到了两种安装方式,我这里强烈推荐用Python3的方案,毕竟Python2已经停止维护了。实测下来,用pip3安装最稳妥:

sudo apt-get install python3-dev python3-opencv python3-wxgtk4.0 python3-pip python3-matplotlib python3-lxml python3-pygame
pip3 install PyYAML MAVProxy --user
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc
source ~/.bashrc

有时候会遇到wxPython包装不上的情况,这时候可以试试手动下载deb包安装。我在一台新装的Ubuntu 20.04上就遇到过这问题,折腾了半天才发现是缺少底层依赖。

装完MAVProxy后,还需要一些辅助工具,比如screen和git,这些在后续的仿真中都会用到:

sudo apt-get install screen git vim

2. 获取ArduPilot源码

环境准备好后,就要获取ArduPilot的源代码了。原始文章提到git clone经常因为网络问题失败,这点我深有体会。国内用户最好用镜像源或者代理(注:此处仅指网络代理,非敏感技术),但注意不要用那些来路不明的软件。

创建一个专门的工作目录是个好习惯,这样不会把系统搞乱:

mkdir -p ~/ardupilot_project
cd ~/ardupilot_project
git clone https://gitee.com/mirrors/ardupilot.git

如果你已经在外网克隆了仓库,转移到Linux时可能会遇到换行符问题。Windows用的是\r\n,Linux用的是\n,所以会出现“/usr/bin/env: python3\r: 没有那个文件或目录”这种错误。解决方法是用vim打开文件,执行:set ff=unix然后保存。

还有文件权限问题,Windows拷贝过来的文件默认没有执行权限,需要递归授权:

sudo chmod -R 755 ardupilot

接着初始化子模块,这是很多人会漏掉的关键步骤:

cd ardupilot
git submodule update --init --recursive

这个过程可能会比较慢,取决于你的网络状况。我建议在晚上睡觉前开始下载,第二天早上应该就差不多了。

3. 环境配置与编译准备

代码下载完后,需要设置一些环境变量。把以下内容添加到~/.bashrc文件末尾:

export PATH=$PATH:~/ardupilot_project/ardupilot/Tools/autotest
export PATH=$PATH:~/.local/bin

然后执行source ~/.bashrc让配置生效。验证一下是否设置成功,可以输入sim_后按Tab键,如果能自动补全为sim_vehicle.py,说明路径设置正确。

编译前还需要安装一些依赖库,ArduPilot提供了一个很方便的脚本:

cd ~/ardupilot_project/ardupilot
Tools/environment_install/install-prereqs-ubuntu.sh -y

这个脚本会自动安装编译需要的所有依赖,包括编译器、工具链和各种库文件。整个过程大概需要10-20分钟,取决于你的网速和机器性能。

有时候会因为网络问题中断,多试几次就好。我在帮学员配置环境时,遇到过最极端的情况是重试了5次才成功,所以耐心很重要。

4. 解决编译错误

第一次运行SITL时,很可能会遇到编译错误。原始文章提到的C++结构体初始化问题确实很常见,这是因为ArduPilot代码中有些地方用了C风格的初始化方式,而C++编译器对此要求更严格。

具体来说,在AP_Logger_Backend.cpp文件的578行左右,有这样的代码:

log_VER pkt{
    LOG_PACKET_HEADER_INIT(LOG_VER_MSG),
    time_us : AP_HAL::micros64(),
    board_type : fwver.board_type,
    board_subtype: fwver.board_subtype,
    major: fwver.major,
    minor: fwver.minor,
    patch: fwver.patch,
    fw_type: fwver.fw_type,
    git_hash: fwver.fw_hash,
    build_type: fwver.vehicle_type,
};

但查看log_VER结构体的定义,会发现还有fw_string和_APJ_BOARD_ID两个成员没有被初始化:

struct PACKED log_VER {
    LOG_PACKET_HEADER;
    uint64_t time_us;
    uint8_t board_type;
    uint16_t board_subtype;
    uint8_t major;
    uint8_t minor;
    uint8_t patch;
    uint8_t fw_type;
    uint32_t git_hash;
    char fw_string[64];
    uint16_t _APJ_BOARD_ID;
    uint8_t build_type;
};

解决方法很简单,在初始化时给这两个成员赋默认值即可:

log_VER pkt{
    LOG_PACKET_HEADER_INIT(LOG_VER_MSG),
    time_us : AP_HAL::micros64(),
    board_type : fwver.board_type,
    board_subtype: fwver.board_subtype,
    major: fwver.major,
    minor: fwver.minor,
    patch: fwver.patch,
    fw_type: fwver.fw_type,
    git_hash: fwver.fw_hash,
    "",  // 给fw_string赋空值
    0,   // 给_APJ_BOARD_ID赋0
    build_type: fwver.vehicle_type,
};

修改后保存文件,重新编译就可以了。这个问题在新版本的ArduPilot中可能已经被修复,但如果你用的是较旧的版本或者特定的commit,还是可能会遇到。

5. 运行SITL仿真

编译问题解决后,就可以开始运行仿真了。进入ardupilot目录,启动Copter仿真:

cd ~/ardupilot_project/ardupilot
sim_vehicle.py -v ArduCopter --map --console

第一次运行会先编译一些组件,可能需要几分钟时间。成功启动后,你应该能看到三个窗口:MAVProxy控制台、地图窗口和飞行数据窗口。

如果只有控制台窗口,没有地图和飞行数据显示,很可能是MAVProxy的依赖包有问题。试试用pip2重新安装相关组件:

sudo -H pip2 install --upgrade MAVProxy pymavlink future lxml -i https://pypi.tuna.tsinghua.edu.cn/simple

这里用pip2是因为MAVProxy的一些组件还没有完全兼容Python3。虽然原始文章提到怕Python3和ROS冲突,但实测在纯SITL环境下用Python3是没问题的。

仿真启动后,你可以在MAVProxy控制台中输入命令来控制无人机。比如输入arm throttle解锁电机,takeoff 10起飞到10米高度。这些命令和真实飞控的操作是一样的。

6. 常见问题排查

在仿真过程中,可能会遇到各种奇怪的问题。我总结了几种常见的情况和解决方法:

地图不显示:这通常是因为wxPython或者matplotlib的问题。试着重新安装这些包:

pip3 install -U wxPython matplotlib

控制无响应:检查是否有多个MAVProxy实例在运行,用ps aux | grep mavproxy查看,如果有的话用kill命令结束掉。

帧率过低:仿真运行很卡的话,可以尝试关闭图形界面,用--no-mavproxy参数启动,然后用QGroundControl连接仿真。

端口占用:如果提示端口已被占用,可以指定其他端口号:

sim_vehicle.py -v ArduCopter --map --console --out=127.0.0.1:14550

有时候重启电脑能解决很多莫名其妙的问题,特别是USB设备相关的异常。

7. 进阶使用技巧

基本仿真能运行后,可以尝试一些更高级的用法。比如使用不同的机型:

sim_vehicle.py -v ArduPlane --map --console  # 固定翼仿真
sim_vehicle.py -v APMrover2 --map --console  #  rover仿真

还可以添加参数来模拟不同的环境条件,比如风速、重力异常等:

sim_vehicle.py -v ArduCopter --map --console --add-param=SIM_WIND_SPD=5

这些参数可以在仿真运行时动态调整,对测试控制算法的鲁棒性很有帮助。

另一个有用的技巧是使用多个实例进行多机仿真。先启动一个实例:

sim_vehicle.py -v ArduCopter --instance 1 --out=127.0.0.1:14550

然后在另一个终端启动第二个实例:

sim_vehicle.py -v ArduCopter --instance 2 --out=127.0.0.1:14551

这样就能同时运行两个无人机,测试多机协同算法了。

8. 与地面站配合使用

SITL仿真最好配合地面站软件使用,这样能看到更直观的飞行数据。我常用的是QGroundControl,安装很简单:

sudo usermod -a -G dialout $USER
sudo apt-get remove modemmanager -y
wget https://d176tv9ibo4jno.cloudfront.net/latest/QGroundControl.AppImage
chmod +x QGroundControl.AppImage

启动QGroundControl后,它会自动连接到SITL仿真。你可以在里面看到详细的任务规划、飞行参数和传感器数据。

如果连接不上,检查一下MAVProxy的输出配置。确保有--out=udp:127.0.0.1:14550这样的参数,这是QGroundControl默认监听的端口。

在地面站里可以设置航点任务,模拟自动飞行。这是我最喜欢的功能,可以在不出门的情况下测试复杂的飞行任务。

记得定期更新代码,ArduPilot社区很活跃,几乎每天都有新的改进和bug修复:

cd ~/ardupilot_project/ardupilot
git pull
git submodule update --recursive

更新后可能需要重新编译,因为有些修改涉及到底层代码的变动。

更多推荐