第三章:Linux基础与Shell编程
说实话,很多做自动驾驶的朋友,代码写得飞起,但一进Linux终端就发怵。我当年刚入行时也是这样,总觉得有IDE就够了。直到有一次,我在调试一个传感器数据流的问题,IDE死活连不上,最后靠着一行grep加awk,五分钟定位了问题。嗯,从那以后,我再也不敢小看Shell了。
这一章,我们就来聊聊自动驾驶软件栈里,那些你绕不开的Linux基础。说白了,就是让你能在终端里「活下来」,并且活得挺滋润。
3.1 Linux文件系统:你得知道东西放哪了
Linux的文件系统,和Windows不一样。它没有C盘D盘,而是一棵树。根目录是/,所有东西都挂在这棵树上。
我建议你重点记住这几个目录:
/bin和/usr/bin:放的是常用命令,比如ls、cp。你想想看,没有这些命令,你连文件都看不到。/etc:系统配置文件。我在项目中遇到过,传感器驱动死活装不上,最后发现是/etc/udev/rules.d里的权限规则没写对。/var/log:日志文件。调试时第一站就是这里。自动驾驶系统跑着跑着出问题了,先看/var/log/syslog。/proc:虚拟文件系统,存的是内核和进程信息。比如/proc/cpuinfo能看CPU型号。/dev:设备文件。你的激光雷达、摄像头,挂载后都会在这里出现。
tree -L 2 / 快速看目录结构。别死记硬背,多用几次就熟了。
3.2 常用命令:grep、awk、sed 三剑客
这三个命令,是Linux文本处理的「倚天剑屠龙刀」。你写自动驾驶代码,天天要和日志、配置文件打交道,不会它们,效率至少低一半。
3.2.1 grep:大海捞针
grep 就是用来在文件里找字符串的。比如你怀疑某个传感器报错了:
grep -rn "ERROR" /var/log/autonomous_drive.log
-r 是递归,-n 是显示行号。我曾经在调试一个路径规划模块时,日志文件有几十万行,全靠grep一把梭。
更高级的用法,是用正则表达式。比如你想找所有以lidar开头的行:
grep "^lidar" sensor_config.yaml
3.2.2 awk:列处理神器
awk 默认把一行按空格或Tab切分成多列。比如你有一个CSV文件,想提取第二列:
awk '{print $2}' data.csv
我在项目中遇到过,需要从传感器时间戳日志里,提取出所有超过100毫秒的延迟记录:
awk '$3 > 100 {print $1, $2, $3}' latency.log
这里$3是第三列,如果大于100,就打印前三列。你看,一行命令搞定。
3.2.3 sed:流式编辑器
sed 用来做文本替换。比如你想把配置文件里所有的debug=false改成debug=true:
sed -i 's/debug=false/debug=true/g' config.yaml
-i 是直接修改文件,s 是替换命令,g 是全局替换。注意,-i 很危险,我建议你先不加-i跑一遍,看看输出对不对。
sed -i 把整个配置文件清空了。嗯,从那以后,我每次用 sed -i 之前,都会先 cp 备份一下。
3.3 Shell脚本编写:把重复劳动自动化
你每天要启动传感器、录制数据、编译代码……这些事,写个脚本一键搞定,不香吗?
一个典型的自动驾驶数据采集脚本,大概长这样:
#!/bin/bash
# 数据采集脚本
LOG_DIR="/data/logs/$(date +%Y%m%d_%H%M%S)"
mkdir -p $LOG_DIR
echo "启动激光雷达..."
roslaunch lidar_driver lidar.launch &
LIDAR_PID=$!
echo "启动摄像头..."
roslaunch camera_driver camera.launch &
CAM_PID=$!
echo "开始录制..."
rosbag record -O $LOG_DIR/recording.bag /lidar_points /camera_image
# 录制结束后,清理进程
kill $LIDAR_PID $CAM_PID
echo "采集完成,数据保存在 $LOG_DIR"
这里有几个要点:
#!/bin/bash是脚本的「身份证」,告诉系统用哪个解释器。$(date +%Y%m%d_%H%M%S)是命令替换,生成时间戳文件夹。&让进程后台运行,$!获取它的PID,方便后面杀掉。
我个人习惯,脚本里一定要加set -e。这样一旦某条命令失败,脚本就立即退出,不会继续执行造成更大的混乱。
3.4 进程管理与调试工具
自动驾驶系统跑起来,进程少说几十个。怎么管?
3.4.1 ps 和 top:看看谁在跑
ps aux 列出所有进程。你想找某个进程,比如rosmaster:
ps aux | grep rosmaster
top 是动态的,实时显示CPU和内存占用。我调试性能问题时,经常开着top,看看哪个进程在偷吃资源。
3.4.2 kill:该停就停
进程卡死了?kill -9 PID 是终极手段。但注意,-9 是强制杀死,进程没有机会做清理工作。我建议先用kill -15,给进程一个优雅退出的机会。
3.4.3 strace 和 gdb:调试利器
strace 跟踪系统调用。比如你的程序读文件很慢,可以用strace -p PID看看它在干嘛。
gdb 是调试器。程序崩溃了,生成core dump文件,然后用gdb ./program core,就能看到崩溃时的调用栈。我在项目中遇到过,一个内存越界问题,查了两天没头绪,最后靠gdb定位到了。
好了,这一章的内容就到这里。记住,Shell脚本是你自动驾驶开发路上的「瑞士军刀」,别嫌它丑,用起来真香。