操作系统基础
概述
操作系统(OS)是机器人软件栈的基础层,负责管理硬件资源、调度任务和提供编程接口。在机器人领域,Linux是主控平台的首选操作系统,而实时扩展则是满足控制需求的关键。
进程与线程
进程(Process)
进程是操作系统资源分配的基本单位:
| 属性 | 说明 |
|---|---|
| 地址空间 | 独立的虚拟地址空间 |
| 资源 | 拥有独立的文件描述符、内存映射等 |
| 隔离性 | 进程间相互隔离,一个崩溃不影响其他 |
| 开销 | 创建和切换开销较大 |
| 通信 | 需要IPC(管道、共享内存、套接字等) |
线程(Thread)
线程是CPU调度的基本单位:
| 属性 | 说明 |
|---|---|
| 地址空间 | 共享所属进程的地址空间 |
| 资源 | 共享进程资源(文件、内存) |
| 独立 | 拥有独立的栈、寄存器、程序计数器 |
| 开销 | 创建和切换开销较小 |
| 通信 | 可直接读写共享变量(需同步) |
在ROS2中的体现
ROS2 节点模型:
├── 节点(Node) = 进程(默认)或线程(组件模式)
├── 进程模式: 每个节点独立进程,隔离性好
│ $ ros2 run perception camera_node
│ $ ros2 run navigation planner_node
└── 组件模式: 多个节点共享一个进程,通信开销低
$ ros2 run rclcpp_components component_container
ROS2最佳实践
- 使用组件(Component)模式减少节点间通信开销
- 在同一进程内的节点可以使用零拷贝(intra-process communication)
- 计算密集型节点放在独立进程中,避免影响其他节点
调度算法
Linux调度器
Linux使用CFS(Completely Fair Scheduler)作为默认调度器:
| 调度类 | 策略 | 优先级 | 用途 |
|---|---|---|---|
| SCHED_DEADLINE | EDF(最早截止期限优先) | 最高 | 硬实时任务 |
| SCHED_FIFO | 先进先出实时调度 | 高(1-99) | 实时任务 |
| SCHED_RR | 时间片轮转实时调度 | 高(1-99) | 实时任务 |
| SCHED_OTHER | CFS公平调度 | 普通(nice值) | 普通任务 |
| SCHED_IDLE | 空闲时才运行 | 最低 | 后台任务 |
实时调度设置
# 查看进程的调度策略和优先级
chrt -p <pid>
# 设置进程为SCHED_FIFO,优先级80
sudo chrt -f -p 80 <pid>
# 启动时指定调度策略
sudo chrt -f 80 ./motor_control_node
# 设置CPU亲和性(绑定到特定核心)
taskset -c 3 ./motor_control_node
# Python中设置线程优先级
import os
import ctypes
# 设置实时调度
SCHED_FIFO = 1
param = ctypes.c_int(80)
libc = ctypes.CDLL('libc.so.6')
class sched_param(ctypes.Structure):
_fields_ = [('sched_priority', ctypes.c_int)]
sp = sched_param(80)
libc.sched_setscheduler(0, SCHED_FIFO, ctypes.byref(sp))
调度延迟
\[
t_{\text{response}} = t_{\text{interrupt}} + t_{\text{schedule}} + t_{\text{context\_switch}} + t_{\text{execution}}
\]
| 系统 | 典型调度延迟 | 最坏情况 |
|---|---|---|
| 标准Linux | ~100μs | ~10ms |
| PREEMPT_RT Linux | ~10μs | ~100μs |
| FreeRTOS | <1μs | ~10μs |
| 裸机 | <100ns | ~1μs |
Linux内核架构
内核子系统
graph TB
subgraph 用户空间
APP[应用程序<br>ROS2节点]
LIB[C库 glibc]
end
subgraph 内核空间
SCI[系统调用接口<br>System Call Interface]
subgraph 核心子系统
PM[进程管理<br>Process Management]
MM[内存管理<br>Memory Management]
VFS[虚拟文件系统<br>VFS]
NET[网络子系统<br>Network Stack]
IPC_K[进程间通信<br>IPC]
end
DD[设备驱动<br>Device Drivers]
HAL_K[硬件抽象层<br>HAL]
end
APP --> LIB
LIB --> SCI
SCI --> PM
SCI --> MM
SCI --> VFS
SCI --> NET
SCI --> IPC_K
PM --> DD
MM --> DD
VFS --> DD
DD --> HAL_K
内核模块
Linux内核是模块化的,驱动可以动态加载:
# 查看已加载的内核模块
lsmod
# 加载模块
sudo modprobe v4l2_common # V4L2视频驱动
sudo modprobe can_raw # CAN总线原始套接字
# 卸载模块
sudo rmmod can_raw
# 查看模块信息
modinfo nvidia # NVIDIA GPU驱动信息
设备驱动
设备类型
| 类型 | 接口 | 示例 | 访问方式 |
|---|---|---|---|
| 字符设备 | 流式读写 | 串口、IMU、GPIO | /dev/ttyUSB0 |
| 块设备 | 随机读写 | SSD、eMMC | /dev/sda |
| 网络设备 | 套接字 | 以太网、WiFi | eth0, wlan0 |
/dev 设备文件
# 机器人常用设备文件
/dev/ttyUSB0 # USB串口(MCU通信)
/dev/ttyTHS0 # Jetson原生串口
/dev/video0 # USB相机(V4L2)
/dev/i2c-1 # I2C总线
/dev/spidev0.0 # SPI设备
/dev/can0 # CAN总线
/dev/input/js0 # 游戏手柄
/dev/nvme0n1 # NVMe SSD
sysfs文件系统
sysfs提供内核对象的用户空间接口:
# GPIO控制
echo 17 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio17/direction
echo 1 > /sys/class/gpio/gpio17/value
# 查看CPU温度
cat /sys/class/thermal/thermal_zone0/temp
# 输出: 45000 (表示45.000°C)
# 查看CPU频率
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
# 输出: 2400000 (表示2.4GHz)
# 设置Jetson功耗模式
sudo nvpmodel -m 0 # 最大性能
sudo nvpmodel -m 1 # 15W模式
# 查看GPU利用率(Jetson)
cat /sys/devices/gpu.0/load
V4L2相机驱动
# 列出视频设备
v4l2-ctl --list-devices
# 查看相机支持的格式
v4l2-ctl -d /dev/video0 --list-formats-ext
# 设置相机参数
v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=1920,height=1080,pixelformat=MJPG \
--set-parm=30 # 30fps
# Python读取V4L2相机
import cv2
cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
while True:
ret, frame = cap.read()
if ret:
# 处理帧
process_frame(frame)
实时补丁(PREEMPT_RT)
为什么需要实时Linux
标准Linux内核的问题:
- 内核代码段不可抢占(长时间持有锁)
- 中断处理在硬中断上下文中执行
- 调度延迟不确定(偶尔出现ms级延迟尖峰)
PREEMPT_RT关键改进
| 改进 | 说明 | 效果 |
|---|---|---|
| 完全可抢占内核 | 几乎所有内核代码可被抢占 | 降低调度延迟 |
| 中断线程化 | 硬中断转为内核线程 | 可以被高优先级任务抢占 |
| 自旋锁→互斥锁 | 改为可休眠的锁 | 减少不可抢占时间 |
| 高精度定时器 | hrtimer替代jiffies | ns级定时精度 |
安装和配置
# Ubuntu上安装RT内核
sudo apt install linux-image-rt-amd64 # x86
# 或编译自定义RT内核(Jetson)
# 下载NVIDIA的L4T源码,应用PREEMPT_RT补丁
# 验证RT内核
uname -a
# 输出应包含 "PREEMPT_RT"
# 测试实时性能
sudo cyclictest -p 80 -t 4 -n -m -l 1000000
# -p 80: 优先级80
# -t 4: 4个线程
# -n: 使用nanosleep
# -m: 锁定内存
# 结果: Min/Avg/Max 延迟(μs)
实时性能调优
# 1. 隔离CPU核心给实时任务
# 在/boot/cmdline.txt中添加:
isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3
# 2. 禁用CPU频率调节
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
# 3. 锁定内存(防止页面交换)
# 在程序中:
mlockall(MCL_CURRENT | MCL_FUTURE);
# 4. 设置实时线程优先级
# 在ROS2中:
# ros2 run --prefix "chrt -f 80" my_package my_node
启动过程
Linux启动流程
graph LR
A[上电] --> B[Bootloader<br>U-Boot/UEFI]
B --> C[内核加载<br>vmlinuz]
C --> D[initramfs<br>临时根文件系统]
D --> E[init/systemd<br>PID 1]
E --> F[系统服务启动]
F --> G[用户空间就绪]
机器人自启动配置
# 使用systemd创建开机自启服务
sudo tee /etc/systemd/system/robot.service << 'EOF'
[Unit]
Description=Robot ROS2 Launch
After=network.target
[Service]
Type=simple
User=robot
WorkingDirectory=/home/robot/ros2_ws
ExecStart=/bin/bash -c "source install/setup.bash && ros2 launch robot_bringup robot.launch.py"
Restart=always
RestartSec=5
# 实时优先级设置
Nice=-10
CPUSchedulingPolicy=fifo
CPUSchedulingPriority=50
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable robot.service
sudo systemctl start robot.service
启动时间优化
| 优化方法 | 节省时间 | 说明 |
|---|---|---|
| 精简initramfs | 2-5s | 只保留必要驱动 |
| 并行启动服务 | 3-10s | systemd并行化 |
| 禁用不必要服务 | 2-5s | 关闭蓝牙、打印等 |
| 压缩内核 | 1-2s | 使用LZ4压缩 |
| 使用轻量级发行版 | 5-10s | Ubuntu Core |
IPC(进程间通信)
Linux IPC机制
| 机制 | 延迟 | 吞吐量 | 适用场景 |
|---|---|---|---|
| 管道(Pipe) | 中 | 中 | 父子进程通信 |
| 消息队列 | 中 | 中 | 结构化消息传递 |
| 共享内存 | 低 | 高 | 大量数据共享 |
| 信号(Signal) | 低 | 低 | 简单通知 |
| Unix Socket | 中 | 高 | 本地进程通信 |
| TCP/UDP Socket | 高 | 高 | 跨机器通信 |
ROS2 DDS通信
ROS2使用DDS(Data Distribution Service)作为通信中间件:
ROS2 DDS通信栈:
├── 同一进程内: 零拷贝(指针传递)
├── 同一主机: 共享内存(Fast-DDS SHM transport)
└── 跨主机: UDP多播
参见:实时系统 了解更多关于实时部署的内容。
常用Linux命令
系统监控
# CPU和内存使用
htop # 交互式进程监控
top -H -p <pid> # 查看进程的线程
# 系统资源
free -h # 内存使用
df -h # 磁盘使用
nvidia-smi # GPU使用(Jetson用jtop)
sudo jtop # Jetson系统监控
# 实时性分析
trace-cmd record -p function_graph -l schedule
kernelshark # 图形化内核跟踪分析
性能分析
# CPU性能分析
sudo perf record -g ./robot_node
sudo perf report
# 系统调用跟踪
strace -f -e trace=read,write ./robot_node
# I/O分析
iostat -x 1 # I/O统计
iotop # I/O进程监控
小结
- 进程提供隔离,线程提供并发,ROS2组件模式是最佳实践
- Linux CFS适合一般任务,SCHED_FIFO用于实时控制
- 设备驱动通过
/dev和sysfs提供用户空间接口 - PREEMPT_RT将Linux最坏延迟从~10ms降低到~100μs
- systemd管理机器人服务的自启动
- 合理使用CPU隔离和内存锁定提升实时性能
参考资料
- Bovet, D. P., & Cesati, M. Understanding the Linux Kernel
- Linux Kernel Documentation: https://www.kernel.org/doc/
- PREEMPT_RT Wiki: https://wiki.linuxfoundation.org/realtime/
- ROS2 Real-time Working Group: https://ros-realtime.github.io/