树莓派5 + PS5 手柄实战:搭建六自由度机械臂蓝牙遥控系统
项目概述
本教程将教你如何使用 PS5 DualSense 手柄、树莓派 5 和 Arduino Nano 搭建一套六自由度机械臂控制系统。PS5 手柄通过蓝牙与树莓派 5 配对;树莓派运行 Python 程序读取摇杆、按键输入值,再通过 USB 串口向 Arduino Nano 发送数字指令;Arduino Nano 接收指令后驱动机械臂对应舵机运转。
完整控制链路:
PS5 Controller → Raspberry Pi 5 → Arduino Nano → Servo Robotic Arm
如果你想学习机器人领域的游戏手柄远程操控原理,本项目是绝佳入门案例。不同于手机 APP 控制、Arduino 板载按键控制,本方案使用专业游戏手柄,复刻小型机械抓取设备的操控逻辑。
当前版本仅实现机械臂单独控制;后续可基于这套硬件框架扩展搭配 L298N 电机驱动小车,实现单支 PS5 手柄同时控制机械臂与移动底盘。

物料清单
开工前备齐全部核心硬件与工具:
硬件
- 树莓派 5
- Arduino Nano 主控板
- PS5 DualSense 手柄
- 六自由度铝合金舵机机械臂
- Arduino Nano 舵机扩展板 / 舵机驱动盾板
- 6 个伺服舵机
- 舵机独立外接电源
- Arduino Nano 配套 USB 数据线
- 树莓派 5 专用供电电源
- 预装树莓派系统的 Micro SD 存储卡
- 若干杜邦跳线
软件工具
- 树莓派系统
- Python 3
- Pygame(手柄读取库)
- PySerial(串口通信库)
- Arduino IDE
- Arduino 官方 Servo 舵机库
- Visual Studio Code
- VS Code 远程 SSH 连接插件
- GitHub(代码托管)
可选升级配件
如需将机械臂搭载在机器人小车上,额外准备:
- Arduino Uno 主控
- L298N 直流电机驱动模块
- 机器人小车底盘
- 直流减速电机
- 电机专用锂电池
- 备用 USB 线 / 串口连接线
项目开发历程
我开发这个项目,是希望找到更实用、趣味性更强的机械臂操控方案。

这套机械臂原本搭载舵机、金属支架、夹爪与 Arduino Nano 舵机扩展板,虽能完成基础动作,但原生操控方式过于简陋。我希望复刻工业机器人的操控逻辑:使用摇杆 / 游戏手柄实现灵活控制。
手头恰好有 PS5 手柄与树莓派 5,于是定下整体方案:PS5 手柄作为输入设备,树莓派读取手柄信号、转发运动指令至 Arduino Nano,最终由 Arduino 驱动舵机。
我参考了大量 Xbox 手柄搭配树莓派 + Arduino 的开源项目,理解基础通信逻辑,但硬件组合存在差异(本项目为 PS5 手柄 + 树莓派 5+Nano),因此没有直接复制代码,而是从零分步搭建整套流程:
- 无显示器模式配置树莓派 5,通过 VS Code 远程 SSH 插件远程连接树莓派,可在本地电脑直接编辑树莓派内 Python 代码,大幅简化开发流程;
- 通过蓝牙完成 PS5 手柄与树莓派配对;
- USB 线连接树莓派与 Arduino Nano,设备识别端口为
/dev/ttyUSB0,确认通信链路正常; - 原版机械臂 Arduino 程序通过 HC-05 蓝牙模块接收指令,本项目中蓝牙通信交由树莓派完成,因此修改 Arduino 代码,改为 USB 串口接收指令;
- 向 Arduino 发送第一条测试指令,舵机成功动作,证明整套控制通路通畅;
- 完成 PS5 手柄按键、摇杆映射,匹配 Arduino 数字指令,逐个调试每个舵机动作,最终编写稳定可运行的 Python 主控脚本。
系统整体架构

整套系统分为四大核心单元:
- PS5 DualSense 手柄
- 树莓派 5
- Arduino Nano
- 六自由度机械臂
PS5 控制器不直接连接到 Arduino,而是通过蓝牙连接到树莓派。
树莓派运行 Python 脚本,读取 PS5 控制器输入,决定应发送的命令,并通过 USB 串行将命令发送到 Arduino Nano。
Arduino Nano 接收命令并移动对应的伺服系统。
系统流程:
PS5 DualSense Controller
↓ Bluetooth
Raspberry Pi 5
↓ USB Serial
Arduino Nano
↓ Servo Signals
6DOF Robotic Arm
这种设置优势明显:树莓派更适合读取蓝牙控制器输入和运行 Python 逻辑,而 Arduino Nano 更适合生成稳定的伺服控制信号。
简单来说:树莓派 = 大脑和控制器读取器,Arduino Nano = 舵机驱动器,PS5 控制器 = 人工输入设备,机械臂 = 输出系统。
硬件架构
硬件分为两大线路:信号/控制连接与电源连接。信号负责发送命令,电源负责向舵机提供足够的电流。
树莓派 5 通过其 USB-C 电源供电。Arduino Nano 通过 USB 电缆连接到树莓派,此 USB 电缆用于串行通信,也为 Arduino Nano 的逻辑端供电。
但切勿从树莓派或 Nano USB 线给舵机供电。舵机会消耗大量电流,尤其是多个关节移动或手臂负载时。如果从错误的来源取电,手臂可能会抖动、复位或表现异常。
标准供电逻辑:
树莓派 5 电源 → 仅给树莓派 5
树莓派 USB 端口 → Arduino Nano 逻辑与串行通信
外部舵机电源 → 舵机扩展板与舵机马达
硬件接线链路:
树莓派 5 USB 端口
↓
Arduino Nano USB 端口
↓
舵机扩展板
↓
6 个舵机
外接电源需接入舵机扩展板的供电端子,电源电压、电流规格需匹配所用舵机参数。
机械臂组装调试教程
从仔细组装机械臂开始。本项目使用六自由度铝制舵机机械臂,包含多个舵机关节和一个两指手爪。每个舵机控制一个关节或手臂的一部分。
组装注意事项:
- 切勿急躁装配机械结构,舵机盘安装错位会导致动作卡顿、提前撞机械限位;
- 牢固锁紧舵机摆盘;
- 禁止手动强行掰动关节;
- 上电调试前将所有关节回中置中立位;
- 避免线材挤压卡在金属支架缝隙;
- 旋转关节螺丝不要锁死过紧;
- 保证夹爪开合无卡顿;
- 上电前手动轻推每个关节测试活动顺畅度。
组装完成后,需熟记每条数字指令对应的舵机动作(Arduino 依靠数字指令区分动作)。机械臂正对本人时,本项目指令映射如下:
18 = Servo 5 right
19 = Servo 5 left
20 = Servo 3 up
21 = Servo 3 down
22 = Servo 6 gripper close
23 = Servo 6 gripper open
24 = Servo 2 up
25 = Servo 2 down
26 = Servo 1 base left
27 = Servo 1 base right
16 = Servo 4 up
17 = Servo 4 down
不同组装方式会改变舵机转向,建议逐条指令单独测试确认动作。
Arduino Nano 程序配置
Arduino Nano 负责驱动全部舵机。原版机械臂程序通过软件串口 SoftwareSerial 读取 HC‑05 蓝牙模块数据;本项目无需蓝牙模块,手柄蓝牙连接交由树莓派处理,指令改为 USB 串口传输,因此需要修改代码输入源。
原蓝牙通信代码片段:
#include <SoftwareSerial.h>
SoftwareSerial Bluetooth(3, 2);
Bluetooth.begin(9600);
dataIn = Bluetooth.read();
修改为 USB 串口读取:
Serial.begin(9600);
dataIn = Serial.read();
所有使用 Bluetooth.available() 和 Bluetooth.read() 的地方,全部替换为 Serial.available() 和 Serial.read()。这允许 Arduino Nano 通过 USB 直接从树莓派接收命令字节。编辑代码后,使用 Arduino IDE 将其上传到 Arduino Nano。
如果使用 Arduino Nano 克隆板,可能需要选择 Board: Arduino Nano,Processor: ATmega328P (Old Bootloader)。
程序上传完成后,断开 Nano 与电脑的连接,改接到树莓派 5。
VS Code 远程连接树莓派 5 配置
本项目全程以 VS Code 作为开发环境,无需切换多个终端窗口:通过 SSH 远程直连树莓派,在同一软件内完成代码编辑、终端调试、程序运行。
安装 VS Code 与远程插件
本地电脑安装 Visual Studio Code,打开扩展商店搜索并安装「Remote – SSH」插件。
树莓派无显示器前置配置
树莓派 5 采用无头无屏运行模式,日常无需显示器、键鼠。使用 Raspberry Pi Imager 烧录 microSD 卡时,启用 SSH 并配置 Wi‑Fi。重要设置:Hostname: raspberrypi,Username: pi,SSH 启用,密码认证,Wi‑Fi 已配置。SD 卡插入树莓派上电,等待数分钟完成开机启动。
VS Code 远程连接树莓派
在 VS Code 输入 Ctrl + Shift + P,搜索 Remote-SSH: Connect to Host,输入 pi@raspberrypi.local,平台选择 Linux,输入树莓派登录密码。连接成功后,VS Code 会打开一个新窗口连接到树莓派。打开终端,确认显示 pi@raspberrypi:~ $。
创建项目文件夹
在连接到 Pi 的 VS Code 终端中,创建并打开项目文件夹:
mkdir -p ~/ps5_arm
cd ~/ps5_arm
更新树莓派并安装依赖
sudo apt update
sudo apt full-upgrade -y
sudo apt install -y python3-pip python3-venv python3-serial python3-pygame joystick evtest bluetooth bluez git
这些软件包的作用:
python3-serial:允许 Python 通过串口与 Arduino 通信python3-pygame:读取 PS5 控制器输入joystick:提供jstest控制器测试工具bluetooth/bluez:处理蓝牙配对
从现在起,所有项目命令都应在连接到树莓派的 VS Code 终端中运行。
PS5 手柄蓝牙配对树莓派
在 VS Code 终端中检查蓝牙状态:
sudo systemctl status bluetooth
确认处于活动状态后,打开蓝牙控制工具:
bluetoothctl
在 bluetoothctl 中执行:
power on
agent on
default-agent
scan on
将 PS5 控制器置于配对模式:按住 PS 键 + Create 键,直到控制器灯开始闪烁。当控制器出现在蓝牙扫描中时,配对并连接:
pair XX:XX:XX:XX:XX:XX
trust XX:XX:XX:XX:XX:XX
connect XX:XX:XX:XX:XX:XX
quit
用屏幕上显示的 MAC 地址替换 XX:XX:XX:XX:XX:XX。
配对后,检查操纵杆设备:
ls /dev/input/js*
本项目 PS5 控制器表现为 /dev/input/js0。运行 jstest /dev/input/js0 测试,移动摇杆或按下按钮,若数值变化则表示工作正常。
映射 PS5 游戏手柄控件
不要凭猜测编写 PS5 按钮编号,需通过映射脚本实测。在 /home/pi/ps5_arm 中创建 map_ps5.py,运行该脚本以标识所有轴和按钮编号。本项目的确认映射如下:
摇杆轴:
- 左摇杆 X = 轴 0,左摇杆 Y = 轴 1
- 右摇杆 X = 轴 3,右摇杆 Y = 轴 4
方向值:
- 左摇杆左推 = 轴 0 负值,右推 = 轴 0 正值
- 左摇杆上推 = 轴 1 负值,下推 = 轴 1 正值
- 右摇杆左推 = 轴 3 负值,右推 = 轴 3 正值
- 右摇杆上推 = 轴 4 负值,下推 = 轴 4 正值
按钮映射:
- X / Cross = 按钮 0
- Circle = 按钮 1
- Triangle = 按钮 2
- Square = 按钮 3
- L1 = 按钮 4
- R1 = 按钮 5
- L2 = 按钮 6 同时关联轴 2
- R2 = 按钮 7 同时关联轴 5
- PS 键 = 按钮 10
- 左摇杆按下 / L3 = 按钮 11
- 右摇杆按下 / R3 = 按钮 12
- 触摸板点击 = 无输入检测
D‑pad 映射为 HAT 0:
- 上 = (0, 1)
- 下 = (0, -1)
- 左 = (-1, 0)
- 右 = (1, 0)
- 释放 = (0, 0)
该映射确保最终控制脚本准确无误。
测试树莓派到 Arduino 串行通信
在将 PS5 控制器与机械臂结合之前,先验证树莓派能否与 Arduino Nano 正常通信。
用 USB 将 Arduino Nano 连接到树莓派。在 VS Code 终端运行:
python3 -m serial.tools.list_ports
输出中应显示 /dev/ttyUSB0,即 Arduino Nano。
创建一个名为 arduino_test.py 的测试脚本:
import serial
import time
PORT = "/dev/ttyUSB0"
BAUD = 9600
ser = serial.Serial(PORT, BAUD, timeout=1)
time.sleep(2)
ser.write(bytes([19]))
time.sleep(0.5)
ser.write(bytes([0]))
ser.close()
关键点:发送命令需使用 ser.write(bytes([19])),而不是 ser.write(b"19")。前者发送命令编号 19,后者发送字符 ‘1’ 和 ‘9’,会导致 Arduino 无法识别。
测试时若舵机动作,则证明树莓派到 Arduino Nano 通信正常。
最终主控脚本:PS5 控制机械臂
现在,将控制器读取与串行通信整合起来。树莓派 Python 脚本将:
- 读取 PS5 控制器输入
- 检测哪个按钮或摇杆处于活动状态
- 将该输入转换为 Arduino 命令编号
- 通过 USB 串行将命令发送到 Arduino Nano
- 无命令时停止手臂运动
在 VS Code 中创建最终文件 ps5_to_arm_final.py。为了消除信号抖动与不稳定问题,最终脚本引入了以下机制:
- 死区阈值:过滤摇杆微小漂移噪声
- 按键消抖:屏蔽按键快速连击杂讯
- 指令保持:保证单次动作指令稳定输出
- 发送限速:限制串口指令下发频率
- 急停功能:发送指令 0 停止所有舵机
优化后操控顺滑、运行安全稳定。
最终操控布局方案
经过多版调试,底座旋转舵机分配至 L1/R1 肩键操控最顺手,便于接近机械限位时精细调整。完整操控布局:
L1 / R1 = 底座左/右(舵机 1)
左摇杆左/右 = 舵机 4 上/下
左摇杆上/下 = 舵机 2 上/下
右摇杆左/右 = 舵机 5 左/右
右摇杆上/下 = 舵机 3 上/下
X / Circle = 夹爪开/关
Triangle = 急停
CTRL + C = 安全停止程序
对应命令映射:
L1 → 底座左 → 命令 26
R1 → 底座右 → 命令 27
左摇杆左/右 → 舵机 4 → 命令 16 / 17
左摇杆上/下 → 舵机 2 → 命令 24 / 25
右摇杆左/右 → 舵机 5 → 命令 19 / 18
右摇杆上/下 → 舵机 3 → 命令 20 / 21
X → 夹爪开 → 命令 23
Circle → 夹爪关 → 命令 22
Triangle → 停止 → 命令 0
这一布局并非强制,可根据个人习惯调整。
底层控制逻辑细节
Python 脚本单次仅下发一条动作指令,这是刻意设计:若同时下发多关节运动指令,会大幅提升舵机瞬时功耗,操控难度上升。初代方案单指令输出更安全、方便故障排查。
核心参数设定:
- 死区
DEADZONE = 0.45:摇杆必须移动超过 ±0.45 才视为有效移动 - 消抖时间
DEBOUNCE_TIME = 0.10:输入必须保持稳定约 100 毫秒才接受命令 - 发送间隔
SEND_INTERVAL = 0.10:树莓派每 100 毫秒发送一次命令,避免淹没 Arduino Nano
Arduino 命令系统简洁:命令编号由树莓派发送,Arduino 读取后移动对应的舵机。这种设计便于扩展,例如后续增加汽车底盘时可为小车创建另一组命令编号。
故障排除和经验教训
- VS Code 远程 SSH 验证:确认终端提示为
pi@raspberrypi:~ $,确保命令在 Pi 上执行。 - 树莓派 SSH 登录失败:必须在 Raspberry Pi Imager 中启用 SSH,并正确设置用户名和密码。
- 确认 Arduino Nano 端口:固定使用
/dev/ttyUSB0,在 Python 脚本中明确指定。 - 手柄映射异常:禁止凭经验写死按键编号,必须运行映射脚本逐个实测轴和按钮。
- 按键抖动导致机械臂乱晃:通过死区、消抖、指令限速三重机制解决信号波动问题。
- 底座舵机限位异常:底座旋转至 180° 左右偶尔失控;后续可在 Arduino 代码内限制舵机角度区间,杜绝超出安全行程。
- 舵机抖动、主控重启:舵机必须使用独立外接电源供电,禁止从树莓派或 Arduino USB 取电。
后续升级方案:机械臂搭载 L298N 机器人小车
下一次升级是将机械臂安装在机器人汽车底盘上。可通过 Arduino Uno、L298N 电机驱动模块、直流电机、电机电池和底盘实现。同一个 PS5 控制器可控制机械臂和汽车。
未来系统构想:
PS5 Controller
↓ Bluetooth
Raspberry Pi 5
↓ USB Serial 1
Arduino Nano → 机械臂
Raspberry Pi 5
↓ USB Serial 2
Arduino Uno → L298N → 小车
树莓派将充当主控制器,读取 PS5 控制器,决定命令应发送给机械臂还是汽车。简单的控制设想:摇杆控制机械臂,D‑pad 控制小车移动,L2/R2 调速,Triangle 急停,Square 切换模式。也可采用模式切换,使控制更整洁并防止命令冲突。
参考资料
- Raspberry Pi 官方文档
- VS Code 远程 SSH 文档
- Pygame 操纵杆文档
- Python PySerial 文档
- Arduino Servo 库文档
- Linux 操纵杆输入工具
- GitHub 项目仓库
旧 Xbox 控制器机械臂项目曾为本项目提供了灵感:使用树莓派作为游戏手柄和 Arduino 之间的桥梁。本项目基于这一理念并做如下适配:PS5 控制器、树莓派 5、Arduino Nano、USB 串行通信、六自由度铝制机械臂以及 VS Code 远程 SSH 工作流。
系统框图
主系统信号框图
PS5 DualSense Controller
↓ Bluetooth
Raspberry Pi 5
↓ USB Serial
Arduino Nano
↓ Servo signals
Servo Expansion Board
↓
6DOF Robotic Arm
供电框图
树莓派 5 电源
↓
树莓派 5
树莓派 USB 端口
↓
Arduino Nano 逻辑与串行通信
外部舵机电源
↓
舵机扩展板
↓
舵机马达
VS Code 开发流程框图
笔记本电脑运行 VS Code
↓ Remote - SSH
树莓派 5
↓ Python 脚本
Arduino Nano
↓ 舵机命令
机械臂
小车拓展框图
PS5 控制器
↓ Bluetooth
树莓派 5
↓ USB Serial
Arduino Nano → 机械臂
树莓派 5
↓ USB Serial
Arduino Uno → L298N → 直流电机
代码
代码分为两大主体:
树莓派 Python 程序
文件:raspberry-pi/ps5_to_arm_final.py
该脚本读取 PS5 控制器,应用死区和消抖,然后通过 /dev/ttyUSB0 向 Arduino Nano 发送命令编号。它处理 PS5 摇杆输入、按钮输入、紧急停止、串行通信及命令稳定性。
Arduino Nano 固件
文件:arduino/24G6_fixed_USB_SERIAL.ino
该草图通过 USB 串行接收命令编号,并移动对应的伺服系统,完全用 USB 串行输入替换了旧的 HC‑05 蓝牙输入。
测试脚本
ps5_test.py:确认 Python 能读取控制器map_ps5.py:查找真实的按钮和轴编号arduino_test.py:确认树莓派能向 Arduino Nano 发送串行命令map_arm.py:测试每个 Arduino 命令并观察哪个舵机动作
所有 Python 文件均可在通过 Remote – SSH 连接到树莓派后,直接在 VS Code 中创建、编辑和运行。
总结评述
本项目验证了 PS5 手柄 + 树莓派 5 + Arduino Nano 方案可稳定远程操控六自由度机械臂,整套控制链路闭环可用:
PS5 Controller → Raspberry Pi 5 → Arduino Nano → Robotic Arm
VS Code 远程 SSH 不仅让树莓派摆脱显示器,也让代码开发如同普通项目一样便利。本项目还有改进空间:下一个升级是将手臂安装在移动小车上并用同一手柄控制;另一个改进是修改 Arduino 舵机代码,将每个舵机角度安全限制在其行程范围内,使手臂在极限附近更加可预测和安全。当前版本为 PS5 控制的机械臂遥操作提供了坚实的工作基础。
代码下载地址:GitHub 仓库