1. 树莓派串口通信基础与硬件选型
在嵌入式开发中,串口通信是最基础也最可靠的通信方式之一。树莓派作为一款流行的单板计算机,其串口配置却有着不少"坑",特别是当我们在树莓派上运行非官方系统(如Ubuntu)时。让我们先理清几个关键概念:
树莓派3/4代提供了两个串口资源:
- 硬件串口(/dev/ttyAMA0):由专用时钟源驱动,支持稳定的高波特率通信(最高可达4Mbps),抗干扰能力强,适合可靠的数据传输
- Mini串口(/dev/ttyS0):依赖CPU内核时钟,当CPU负载变化时会导致波特率漂移,实测在115200波特率下就可能出现数据错误
关键细节:树莓派3B+的硬件串口默认分配给蓝牙模块,而GPIO引脚上的串口实际上是性能较差的mini串口。这就是为什么我们需要重新配置串口映射。
2. Ubuntu系统下的串口配置实战
2.1 系统环境准备
当使用Ubuntu代替Raspberry Pi OS时,最大的区别在于缺少raspi-config这个专用配置工具。我们需要手动修改底层配置:
bash复制# 首先确保有编辑权限
sudo apt update
sudo apt install nano -y
2.2 关键配置文件修改
创建/编辑启动配置文件:
bash复制sudo nano /boot/firmware/usercfg.txt
加入以下关键配置:
code复制# 启用硬件UART
enable_uart=1
# 禁用蓝牙释放ttyAMA0
dtoverlay=disable-bt
# 修复Ubuntu下的GPIO映射问题
dtoverlay=pi3-miniuart-bt
经验之谈:在树莓派4B上,还需要额外添加
dtoverlay=uart4和dtoverlay=uart5来启用额外的硬件串口。
2.3 验证配置生效
重启后执行:
bash复制ls -l /dev/ttyAMA*
应该看到:
code复制crw-rw---- 1 root dialout 204, 64 May 10 15:30 /dev/ttyAMA0
如果没有看到,可能需要检查:
- 配置文件是否正确保存
- 是否使用了正确的文件路径(Ubuntu与Raspberry Pi OS的boot分区位置不同)
- 是否有其他服务占用了串口
3. 硬件连接与信号测试
3.1 引脚对应关系
树莓派40针GPIO接口中:
- TXD (GPIO14):物理引脚8(发送数据)
- RXD (GPIO15):物理引脚10(接收数据)
- GND:任意接地引脚(如引脚6、9、14等)
血泪教训:务必先连接GND再连接信号线!我曾因忘记接地导致串口电平不稳定,烧毁过一个USB转TTL模块。
3.2 使用minicom进行测试
安装串口工具套件:
bash复制sudo apt install minicom screen -y
启动minicom(以9600波特率为例):
bash复制minicom -D /dev/ttyAMA0 -b 9600
关键操作命令:
Ctrl+A → E:开启本地回显Ctrl+A → Q:退出minicomCtrl+A → C:清除屏幕
3.3 进阶测试技巧
如果要测试自发自收:
- 短接TXD和RXD引脚
- 在minicom中输入字符,应该立即看到回显
- 如果出现乱码,检查波特率设置和线缆质量
4. 舵机控制协议解析
4.1 PWM信号要求
常见舵机控制协议要求:
- 周期:20ms(50Hz)
- 高电平脉宽:0.5ms-2.5ms对应0°-180°
- 电压:通常4.8-6V
4.2 通过串口发送控制指令
示例控制协议(自定义):
code复制# 格式:<舵机编号><角度><速度>
# 示例:1号舵机转到90度,速度50
S1,90,50\n
Python控制脚本示例:
python复制import serial
import time
ser = serial.Serial('/dev/ttyAMA0', 9600, timeout=1)
def set_servo(servo_id, angle, speed=50):
cmd = f"S{servo_id},{angle},{speed}\n"
ser.write(cmd.encode())
time.sleep(0.1) # 等待舵机响应
# 示例:让1号舵机缓慢转动
for angle in range(0, 180, 10):
set_servo(1, angle)
5. 常见问题排查指南
5.1 串口无法识别
现象:ls /dev/ttyAMA0无输出
解决步骤:
- 检查
/boot/firmware/usercfg.txt是否包含enable_uart=1 - 执行
dmesg | grep tty查看内核识别情况 - 尝试添加用户到dialout组:
sudo usermod -aG dialout $USER
5.2 数据收发异常
现象:收到乱码或数据丢失
排查方法:
- 确认双方波特率一致(用示波器测量实际波特率)
- 检查地线连接是否可靠
- 尝试降低波特率测试(如从115200降到9600)
5.3 舵机无反应
现象:发送指令后舵机不动作
检查清单:
- 使用万用表测量舵机供电电压
- 确认控制线连接正确(黄色/白色信号线接GPIO)
- 尝试直接给舵机发送PWM信号测试
6. 性能优化与进阶技巧
6.1 提高通信可靠性
- 添加校验机制:在协议中加入CRC校验
- 使用硬件流控:连接RTS/CTS引脚(需支持硬件流控的转换器)
- 设置接收超时:
ser.timeout = 0.5# 0.5秒超时
6.2 多舵机协同控制
通过串口发送批量指令:
code复制# 格式:M<舵机1角度>,<舵机2角度>,...\n
M90,45,180\n
对应的Python解析代码:
python复制def parse_multi_command(cmd):
if cmd.startswith('M'):
angles = cmd[1:].strip().split(',')
for i, angle in enumerate(angles):
set_servo(i+1, int(angle))
6.3 实时监控实现
创建双向通信协议:
- 树莓派发送控制指令
- 舵机控制器返回当前状态
- 加入时间戳实现同步
我在实际项目中发现,使用硬件串口配合合理的协议设计,可以稳定控制多达12个舵机同时动作。关键是要做好以下几点:
- 每个指令包含唯一序列号便于追踪
- 设置合理的指令间隔(建议≥20ms)
- 实现简单的重传机制