进阶教程
web 端其余功能
坐标系操控机械臂(COORDCTRL)
前置知识
机器人中的坐标系和方向判断
机器人学中使用笛卡尔坐标系(右手坐标系)来描述机器人在三维空间中的位置和姿态。

右手定则说明:
- 伸出右手,自然张开;
- 让食指指向 X 轴正方向(机械臂正前方);
- 让大拇指指向 Z 轴正方向(垂直向上);
- 此时中指自然弯曲所指的方向,即为 Y 轴正方向(机械臂左侧)。
验证方法: 对照机械臂实物,将右手摆成上述姿势,确认三个手指方向与机械臂的前方、左侧、上方一致后,即可正确判断各轴的正负方向。
注意事项: 判断坐标轴方向时,可以参考上方坐标系标注图对照机械臂实物进行确认,确认好 X/Y/Z 方向后再操作,避免方向操作错误导致碰撞。
坐标系平面定义:
- XY 平面:水平工作平面(X 轴和 Y 轴构成)
- XZ 平面:垂直平面(X 轴和 Z 轴构成)
- YZ 平面:侧向平面(Y 轴和 Z 轴构成)
在 RoArm-M3 机械臂中,通常以基座为坐标系原点,Z 轴垂直向上为正方向。
坐标控制参数说明
坐标控制参数含义
- X、Y、Z:分别代表机械臂末端关节末端点的 X 轴、Y 轴和 Z 轴位置坐标
- T:代表机械臂末端点在竖直平面内的角度,通过坐标点逆解出各关节需要转动的角度
- R:代表手腕关节 2 的转动角度(详见 AngleCtrl 功能中的"R+ DG"列)
- G:代表末端关节的转动角度(详见 AngleCtrl 功能中的"G+ DG"列)
- INIT:点击后末端点会复位至产品开机时的中位位置
以上六个参数均可通过"+"和"-"按钮进行调节。
绘画功能
按钮功能说明
| 绘画按钮功能 | 功能解释 |
|---|---|
| HORIZONTAL DRAG | 用鼠标操控机械臂在水平平面绘画 |
| VERTICAL DRAG | 用鼠标操控机械臂在垂直平面绘画 |

- 开启绘画功能前,请确保鼠标光标位于绘画区域外,以免功能启动时机械臂快速移至光标所在坐标,影响绘画效果。
- LED 亮度值:0→255(关闭→最亮)
挑战任务
使用绘画功能实现用机械臂夹着笔在纸上画画!
JSON 指令操控机械臂
前置知识
什么是 JSON?
JSON(JavaScript Object Notation,JavaScript 对象表示法),是一种结构化的数据格式,用键值对的方式(如 键:值),像填写表格一样,把复杂的指令(比如要去哪里、要做什么、做多快)清晰地组织起来。
为什么用 JSON 指令控制机械臂?
因为 JSON 是一种人和机器都能轻松理解的通用语言,能让控制机械臂变得像点菜一样简单、灵活。
发送 JSON 指令的方式
web 端发送指令
在 Web 端使用界面中,预留有指令输入框可以发送 JSON 指令对机械臂进行设置或控制等操作。(缺点部分 JSON 指令需要反馈的内容较长会显示不全)
- 根据开始工作部分连接上机械臂的 WiFi 并打开 Web 端使用界面
- 在 Web 端使用界面中,找到 "FEEDBACK INFORMATION" 下的输入框
- 在此处输入对应的 JSON 指令与机械臂进行通信
- 点击 "SEND" 发送后,JSON 指令反馈的信息会在输入框上方显示
web 端中已经准备好每个功能对应的 JSON 代码,点击** INPUT **按钮,即可复制到输入框,以便直接发送和二次修改。

Python-HTTP 请求通信
前置知识
什么是 HTTP 协议?
HTTP 就是一套一问一答的"会话协议"。
一问一答:你发请求(GET 拿数据/POST 发数据),服务器回响应(200 成功/404 找不到),格式固定,像填表单。
无状态:服务器默认不记得你,每次请求都是独立的。想记住?自己加 Cookie/Token。
明文文本:传的是纯文本,用串口监视器就能直接看,调试不绕弯。
一句话:它是设备(ESP8266、树莓派)与云服务之间的翻译官——你按规则发句话,它替你取回结果。
什么是 Python 虚拟环境以及作用?
虚拟环境就是项目专属的"独立运行箱"。
隔离依赖:不同项目用不同版本的库,互不干扰,告别"版本冲突"。
保护系统:所有安装都锁在项目文件夹里,不污染树莓派等设备的系统 Python。
即插即用:配合 requirements.txt,换个设备也能一键还原一模一样的运行环境。
一句话:给每个项目配一套独立的 Python 工具包,省心、干净、不打架。
如何配置 Python 虚拟环境?
- 检查确认电脑已经安装 Python
- 下载并解压 RoArm-M3 配套的 Python 文件包
RoArm-M3 Python 文件包
打开可以看到 3 个文件

- 打开命令行工具 (cmd、PowerShell 等)后,cd 到解压后的文件夹路径
- 创建虚拟环境:输入命令:python -m venv (虚拟环境名称,一般叫项目名-env, 项目名自取)
python -m venv roarmpython-env
- 激活虚拟环境:输入命令:.\(虚拟环境名称)\Scripts\activate
.\roarmpython-env\Scripts\activate
- 安装项目依赖:输入命令:pip install -r requirements.txt
pip install -r requirements.txt
- 检查虚拟环境是否配置成功:输入命令:pip list
pip list
如果安装成功,会显示与 requirements.txt 中一样的安装包名称和版本号。
不删除虚拟环境相关文件的情况下一次虚拟环境配置一次虚拟环境配置。之后再使用激活即可。
激活虚拟环境方法:
- cd 打开解压后的文件夹路径
- 输入命令:(虚拟环境名称)\Scripts\activate
.\roarmpython-env\Scripts\activate
确认机械臂当前的 IP 地址:
-
如果机械臂 WIFI 模式仅处于 AP 模式,则 IP 地址为 192.168.4.1;
-
如果机械臂 WIFI 模式处于 STA 模式,则可以在机械臂的 OLED 屏幕上获得该机械臂的 IP 地址。 使用以下命令来运行 HTTP 请求通信程序
python http_simple_ctrl.py (机械臂 IP 地址)
上述两种通信方式,机械臂都需要与该脚本运行的设备处于同一个局域网内。
Python-串口通信
前置知识
机械臂驱动板板载接口介绍

| 序号 | 资源名称 | 介绍 |
|---|---|---|
| 1 | ESP32-WROOM-32 主控模组 | 可使用 Arduino IDE 进行开发 |
| 2 | IPEX 一代 WIFI 接口 | 用于连接 IPEX1 外螺内孔的天线 |
| 3 | 激光雷达接口 | 集成了雷达转接板的功能 |
| 4 | IIC 外设扩展接口 | 可用于连接 OLED 屏幕或其它 IIC 传感器 |
| 5 | 复位按键(EN) | 按下后松开,ESP32 会重启 |
| 6 | 下载按键(BOOT) | 按下时开机,ESP32 会进入到下载模式 |
| 7 | DC-DC 5V 稳压电路 | 可为上位机例如树莓派或 Jetson nano 等供电 |
| 8 | Type-C 接口 (LADAR) | 激光雷达数据接口 |
| 9 | Type-C 接口 (USB) | ESP32 串口通信接口、可为 ESP32 上传程序 |
| 10 | XH2.54 供电接口 | 输入 DC7~12.6V,该接口直接为总线舵机和电机供电 |
| 11 | INA219 | 电压电流监测芯片 |
| 12 | 电源开关 | 控制外部供电的开关(上图处于 ON 的位置) |
| 13 | ST3215 总线舵机接口 | 用于连接 ST3215 总线舵机 |
| 14 | 电机接口 PH2.0 6P | B 组带编码器的电机接口 |
| 15 | 电机接口 PH2.0 6P | A 组带编码器的电机接口 |
| 16 | 电机接口 PH2.0 2P | A 组无编码器的电机接口(该产品中为 LED 灯接口) |
| 17 | 电机接口 PH2.0 2P | B 组无编码器的电机接口 |
| 18 | AK09918C | 3 轴电子罗盘 |
| 19 | QMI8658 | 6 轴运动传感器 |
| 20 | TB6612FNG | 电机控制芯片 |
| 21 | 总线舵机控制电路 | 连接多个 ST3215 总线舵机,并获取舵机反馈 |
| 22 | SD 卡槽 | 可用于存储日志或 WIFI 配置 |
| 23 | 40PIN 扩展接口 | 方便接入树莓派 4B、树莓派 Zero 或 Jetson Orin Nano |
| 24 | 40PIN 扩展接口 | 方便使用安装在驱动板上的上位机的引脚 |
| 25 | CP2102 芯片 | 串口转 USB,用于雷达数据传输 |
| 26 | CP2102 芯片 | 串口转 USB,用于 ESP32 串口通信 |
| 27 | 自动下载电路 | 为 ESP32 上传程序时不需要按 EN 和 BOOT 按键 |
-
使用 USB 线通过 Type-C 接口(上图中的 9 号接口)将 PC 与机械臂进行连接。
-
在“开始”中的搜索栏中搜索设备管理器查看新插入的端口号,这里新插入的为 COM20,不同电脑插入的端口号不一样,记住机械臂接入的端口号。

如果设备管理器中没有显示端口,从操作选项中选择添加过时硬件选项进行端口添加。
-
使用以下命令来运行串口通信程序,COM 端口号用上面设备管理器里显示的端口号。
python serial_simple_ctrl.py (COM 端口号)运行完成后,可以看见机械臂进行初始化后的返回信息。在这个界面中可以发送 JSON 格式的指令,也可以获取机械臂的反馈信息,从而与机械臂进行通信。

WiFi 配置
前置知识
无线网络设备的三种工作模式
一句话:无线设备可以当"路由器"(AP)、当"网卡"(STA)、或者两者同时干(AP+STA)——决定了它是发射 Wi-Fi、连接 Wi-Fi,还是做信号中继。
为什么需要知道这些模式?
如果你在做一个物联网项目,想让它既能连上家里的 Wi-Fi 上网,又能在没有网络时让手机直接连它进行配置,搞不清 AP 和 STA 的区别就会卡住。
这三种模式就是告诉你:设备在无线网络里扮演什么角色。
三种模式详解
1. AP 模式(Access Point)—— "开热点"
设备变成一个 Wi-Fi 发射器,其他设备(手机、电脑)可以搜到它并连上来。
- 典型用途:创建你自己的无线局域网,比如用树莓派开一个热点,让手机连上去控制它。
- 注意:这时候设备本身通常不通过另一个 Wi-Fi 上网,它就是网络的中心。
2. STA 模式(Station)—— "连 Wi-Fi"
设备像你的手机一样,去连接一个已有的 Wi-Fi 热点(比如家里的路由器)。
- 典型用途:让 ESP8266 连上互联网,把传感器数据传到云端。
- 注意:这个模式下设备不会发射 Wi-Fi 信号,它只是个客户端。
3. AP+STA 模式 —— "一边连上级,一边开热点"
设备同时干两件事——它作为 STA 连到家里的路由器上网,同时又作为 AP 开一个新热点,让别的设备连到它。
- 典型用途:Wi-Fi 信号中继器(放大信号)、或调试模式(设备正常联网工作,同时手机能直连它修改参数)。
- 注意:两个网络通常是隔离的,但设备可以转发数据,所以能扩展覆盖范围。
一句话:
- 想让别人连你 → 用 AP
- 想连别人的网 → 用 STA
- 想一边上网一边让别人连你 → 用 AP+STA
本产品出厂时默认 WIFI 处于 AP 模式下,如果要设置为其它模式,可以通过输入 json 指令实现。
设置默认 WiFi 模式
CMD_WIFI_ON_BOOT
{"T":401,"cmd":3}
设置开机后 WIFI 的默认工作模式
cmd:默认工作模式代号,0:关闭,1:AP,2:STA,3:AP+STA。
设置 WiFi 模式
CMD_SET_AP
{"T":402,"ssid":"RoArm-M3","password":"12345678"}
设置 WIFI 为 AP 模式,建立 WiFi 热点。
ssid:AP 模式下 WIFI 的名称(SSID),最大长度 32 个字符。password:AP 模式下 WIFI 的密码,最大长度 64 个字符。
CMD_SET_STA
{"T":403,"ssid":"yourWiFiName","password":"yourWiFiPassword"}
设置 WIFI 为 STA 模式,连接到现有的 WiFi 网络。
ssid:STA 模式下要连接的 WiFi 网络的名称(SSID),最大长度 32 个字符。password:STA 模式下要连接的 WiFi 网络的密码,最大长度 64 个字符。
CMD_SET_APSTA
{"T":404,"ap_ssid":"RoArm-M3","ap_password":"12345678","sta_ssid":"yourWiFiName","sta_password":"yourWiFiPassword"}
设置 WIFI 为 AP+STA 模式,同时连接到现有的 WiFi 网络。
ap_ssid:AP 模式下 WIFI 的名称(SSID),最大长度 32 个字符。ap_password:AP 模式下 WIFI 的密码,最大长度 64 个字符。sta_ssid:STA 模式下要连接的 WiFi 网络的名称(SSID),最大长度 32 个字符。sta_password:STA 模式下要连接的 WiFi 网络的密码,最大长度 64 个字符。
使用该指令,机械臂将会连接到现有的 WIFI,同时建立一个名为 RoArm-M3 的热点。此模式下,OLED 屏幕上会第一行会显示 AP 的 WIFI 名称,第二行会显示无线网络分配的 ip 地址。
查看当前 WiFi 信息
CMD_WIFI_INFO
{"T":405}
查看机械臂当前 WIFI 信息。 返回值如下:
{"ip":"192.168.10.90","rssi":-50,"wifi_mode_on_boot":3,"sta_ssid":"yourWiFiName","sta_password":"yourWiFiPassword","ap_ssid":"RoArm-M3","ap_password":"12345678"}
ip:当前连接的 WiFi 网络的名称(SSID)。rssi:当前连接的 WiFi 网络的信号强度,若机械臂仅在 AP 模式下,该值为 0。wifi_mode_on_boot:当前连接的 WiFi 模式,0:关闭,1:AP,2:STA,3:AP+STA。sta_ssid:设置的 STA 模式下要连接的 WiFi 网络的名称(SSID)。sta_password:STA 模式下要连接的 WiFi 网络的密码。ap_ssid:AP 模式下 WIFI 的名称(SSID)。ap_password:AP 模式下 WIFI 的密码。
生成 WiFi 配置文件
WiFi 配置文件是储存在机械臂的 flash 内存中的 wifiConfig.json 文件,文件内容如下:
{"wifi_mode_on_boot":3,"sta_ssid":"JSBZY-2.4G","sta_password":"waveshare0755","ap_ssid":"RoArm-M3","ap_password":"12345678"}
CMD_WIFI_CONFIG_CREATE_BY_STATUS
{"T":406}
根据当前 WIFI 状态生成 WiFi 配置的 wifiConfig.json 文件。 使用该指令后,机械臂会根据当前的 WIFI 状态生成 wifiConfig.json 文件,如果之前没有生成过该文件,则会在 flash 内存中创建一个新的 wifiConfig.json 文件;如果之前已经生成过该文件,则会覆盖原有的 wifiConfig.json 文件。
CMD_WIFI_CONFIG_CREATE_BY_INPUT
{"T":407,"mode":3,"ap_ssid":"RoArm-M3","ap_password":"12345678","sta_ssid":"JSBZY-2.4G","sta_password":"waveshare0755"}
将输入的信息写入 flash 内存中的 wifiConfig.json 文件中。
mode:WiFi 模式代号,0:关闭,1:AP,2:STA,3:AP+STA。
关闭 WiFi 连接
CMD_WIFI_STOP
{"T":408}
关闭 WiFi 连接。
机械臂运动控制(MOVING CTRL)

这部分是一套机械臂的 JSON 指令集,每条指令对应一个动作,通过 Web 端发送给机械臂执行。
简单控制指令
初始化 / 状态查询
CMD_MOVE_INIT
{"T":100}
让机械臂所有关节转动到初始位置。
CMD_SERVO_RAD_FEEDBACK
{"T":105}
读取当前各关节的弧度值和负载值。 反馈的信息包括:
x、y、z:分别代表末端点 X 轴、Y 轴、Z 轴的坐标。tit、b、s、e、t、r、g:分别代表末端关节姿态、基础关节、肩关节、肘关节、手腕关节 1、手腕关节 2、末端关节角度,以弧度制形式显示。tB、tS、tE、tT、tR:分别代表基础关节、肩关节、肘关节、手腕关节 1、手腕关节 2 的负载。torswitchB、torswitchS、torswitchE、torswitchT、torswitchR、torswitchG:分别代表基础关节、肩关节、肘关节、手腕关节 1、手腕关节 2、末端关节的扭矩开关状态(0:关闭扭矩锁;1:开启扭矩锁)。v:代表当前电压,单位:0.01V
单关节控制
CMD_SINGLE_JOINT_CTRL
{"T":101, "joint":0, "rad":0, "spd":0, "acc":10}
控制单个关节转动到指定弧度。
-
joint:关节编号(1~6) 关节序号含义: 1:BASE_JOINT 基础关节 2:SHOULDER_JOINT 肩关节 3:ELBOW_JOINT 肘关节 4:WRIST_JOINT 手腕关节 1 5:ROLL_JOINT 手腕关节 2 6:EOAT_JOINT 末端关节
-
rad:目标弧度 各关节角度范围(弧度制):关节名称 初始值 范围 转动方向 BASE_JOINT 0 -3.14~3.14 增加向左转,减少向右转 SHOULDER_JOINT 0 -1.57~1.57 增加向前转,减少向后转 ELBOW_JOINT 1.57 0~3.14 增加向下转,减少向反方向转 WRIST_JOINT 0 -1.57~1.57 增加向下转,减少向上转 ROLL_JOINT 0 -3.14~3.14 增加顺时针转,减少逆时针转 EOAT_JOINT 3.14 1.08~3.14 减少时夹爪张开 -
spd:转动速度 单位为步/秒,数值没有范围,越大速度越快。程序已设定好,当数值为 0 时,以最大速度转动。 -
acc:转动开始和结束时的加速度 单位为步/秒/秒,数值越小启停越平滑,数值可以为 0-254。如设置为 10 时,则按照 1000 步每秒的平方加减速度变速。当加速度值为 0 时,则按照最大的加速度运行。
CMD_SINGLE_JOINT_ANGLE
{"T":121, "joint":1, "angle":0, "spd":10, "acc":10}
同上,但用角度(0~360°)而非弧度。
挑战任务
只用 CMD_SINGLE_JOINT_CTRL 让机械臂做一套"广播体操"
任务目标
仅使用 CMD_SINGLE_JOINT_CTRL 指令,依次控制机械臂的各个关节运动,完成一套"伸展→旋转→归位"的动作序列。
操作步骤
在 Web 端重复点击 CMD_SINGLE_JOINT_CTRL 按钮,每次修改参数后发送,依次执行以下动作:
1. 基础关节右转 90°(约 1.57 rad)
{"T":101, "joint":1, "rad":1.57, "spd":0.5, "acc":10}
2. 肩关节抬起 45°(约 0.785 rad)
{"T":101, "joint":2, "rad":0.785, "spd":0.5, "acc":10}
3. 肘关节弯曲 60°(约 1.047 rad)
{"T":101, "joint":3, "rad":1.047, "spd":0.5, "acc":10}
4. 手腕关节 1 向下 30°(约 0.524 rad)
{"T":101, "joint":4, "rad":0.524, "spd":0.5, "acc":10}
5. 基础关节左转回中(0 rad)
{"T":101, "joint":1, "rad":0, "spd":0.5, "acc":10}
6. 肩关节落回 0 rad
{"T":101, "joint":2, "rad":0, "spd":0.5, "acc":10}
7. 肘关节伸直回 1.57 rad(初始位置)
{"T":101, "joint":3, "rad":1.57, "spd":0.5, "acc":10}
8. 手腕关节 1 回 0 rad
{"T":101, "joint":4, "rad":0, "spd":0.5, "acc":10}
验证
如果机械臂按顺序完成以下动作,则挑战成功:
- 基础关节右转
- 肩关节抬起
- 肘关节弯曲
- 手腕关节 1 下弯
- 基础关节回中
- 肩关节回位
- 肘关节回位
- 手腕关节 1 回位
最终回到初始姿态。
- 实际关节运动范围请参考上方各关节角度范围表格,必要时调整
rad的值 - 如果夹爪也使用此指令控制,可额外加入夹爪开合动作
- 速度
spd和加速度acc可根据需要调整,让动作更流畅或更平缓
多关节联动
CMD_JOINTS_RAD_CTRL
{"T":102, "base":0, "shoulder":0, "elbow":1.57, "wrist":0, "roll":0, "hand":1.57, "spd":0, "acc":10}
同时控制所有关节的目标弧度(每个关节一个字段)。
CMD_JOINTS_ANGLE_CTRL
{"T":122, "b":0, "s":0, "e":90, "t":0, "r":0, "h":180, "spd":10, "acc":10}
同上,用角度(b/s/e/t/r/h 分别对应不同关节)。
夹爪 / 末端执行器
CMD_EOAT_HAND_CTRL
{"T":106, "cmd":3.14, "spd":0, "acc":0}
控制夹爪(或末端工具)。
cmd:夹爪开合程度,角度转动范围为 1.08 至 3.14 之间,角度减少时,夹爪关节会张开。
延时
CMD_DELAY_MILLIS
{"T":111, "cmd":3000}
暂停 3000 毫秒,用于指令间等待。
总结
- T:指令类型(类似“动作编号”)
- 参数:要么是弧度(rad)、要么是角度(angle)
- 速度/加速度:控制动作的快慢和平滑度 这就像一个“机械臂命令表”——你按格式填好 JSON,发给机械臂,它就知道是动关节、控制夹爪,还是暂停等待。
挑战任务
用单关节和多关节指令让机械臂做一套"抬起手臂→等待→放下→张开手"的动作
场景设定
机械臂当前处于初始状态(所有关节角度为 0°),夹爪闭合。
任务目标
通过 Web 端依次点击指令按钮,修改 JSON 参数,让机械臂完成:
- 抬起肩关节(shoulder 转到 90°)
- 等待 2 秒
- 放下肩关节(shoulder 回到 0°)
- 张开夹爪(hand 转到 90° 或张开位置)
操作方式
在 Web 端依次点击下列指令按钮,修改参数并发送:
步骤 1:抬起肩关节
- 点击 CMD_SINGLE_JOINT_ANGLE(或
CMD_SINGLE_JOINT_CTRL,这里用角度更直观) - 修改 JSON(假设
joint=1对应 shoulder,角度单位 °):
{"T":121, "joint":1, "angle":90, "spd":30, "acc":20}
步骤 2:等待 2 秒
- 点击 CMD_DELAY_MILLIS
- 修改 JSON:
{"T":111, "cmd":2000}
步骤 3:放下肩关节(回到 0°)
- 再次点击 CMD_SINGLE_JOINT_ANGLE
- 修改 JSON:
{"T":121, "joint":1, "angle":0, "spd":30, "acc":20}
步骤 4:张开夹爪
- 点击 CMD_EOAT_HAND_CTRL
- 修改 JSON(假设
cmd=3.14为张开,具体值视夹爪范围而定):
{"T":106, "cmd":3.14, "spd":10, "acc":10}
验证
如果机械臂先抬起肩关节,停顿 2 秒,再放下,最后夹爪张开,则任务成功。
若关节编号或夹爪范围不同,请根据实际机械臂手册调整 joint 和 cmd 的数值。
末端运动学控制
末端位置控制(运动学)
CMD_XYZT_GOAL_CTRL
{"T":104, "x":235, "y":0, "z":234, "t":0, "r":0, "g":3.14, "spd":0.25}
让机械臂末端移动到指定的三维空间坐标(x,y,z),并给定末端朝向(t,r,g)。
spd:移动速度(单位:m/s 或比例)适合做点对点运动。
CMD_XYZT_DIRECT_CTRL
{"T":1041, "x":235, "y":0, "z":234, "t":0, "r":0, "g":3.14}
类似上面,区别是立即执行(不带速度/加速度规划),用于精确控制。
总结
- T:指令类型(类似"动作编号")
- 参数:使用三维空间坐标(x,y,z)和末端朝向(t,r,g)
- 速度:控制末端移动的快慢
末端运动学控制让你可以直接指定机械臂末端的空间位置,而不需要关心每个关节的具体角度。
挑战任务
只用末端位置控制,让机械臂画个正方形
任务目标
使用 CMD_XYZT_GOAL_CTRL 指令,让机械臂末端依次走过正方形的四个角点,形成闭环轨迹。
操作步骤
在 Web 端依次点击 CMD_XYZT_GOAL_CTRL 按钮,每次修改参数后发送:
1. 起点 A(200, 0, 150)
{"T":104, "x":200, "y":0, "z":150, "t":0, "r":0, "g":3.14, "spd":0.2}
2. 点 B(向右 100mm)
{"T":104, "x":300, "y":0, "z":150, "t":0, "r":0, "g":3.14, "spd":0.2}
3. 点 C(向前 100mm)
{"T":104, "x":300, "y":100, "z":150, "t":0, "r":0, "g":3.14, "spd":0.2}
4. 点 D(向左 100mm)
{"T":104, "x":200, "y":100, "z":150, "t":0, "r":0, "g":3.14, "spd":0.2}
5. 返回起点 A
{"T":104, "x":200, "y":0, "z":150, "t":0, "r":0, "g":3.14, "spd":0.2}
验证
观察机械臂末端运动轨迹,如果依次经过 A→B→C→D→A,且路径近似正方形,则挑战成功。
- 坐标 (x,y,z) 可根据实际机械臂工作空间调整,确保在可达范围内
- g 为末端姿态角,保持不变即可
- 如需更平滑的过渡,可适当降低速度
spd
连续运动控制(角控制+逆运动学控制)
前置知识
顺运动 vs. 逆运动学
顺运动学(Forward Kinematics, FK)
给你一组关节角度(比如 base=0, shoulder=1.57, elbow=0),问:机械臂末端在空间哪个位置?
这叫顺解——从关节角度"正向"算出末端坐标。就像已知大臂和小臂的角度,推算手的位置。
逆运动学(Inverse Kinematics, IK)
给你一个末端目标位置(比如 x=200, y=50, z=150),问:每个关节应该转多少度?
这叫逆解——从末端坐标"反向"解出关节角度。就像已知手要够到杯子,反推出肩、肘该弯多少。
两者对比
- 顺运动学:原因 → 结果(关节角度 → 末端位置)
- 逆运动学:结果 → 原因(末端位置 → 关节角度)
类比
- 顺运动学 = 你掰动木偶的四肢(输入角度),看手移动到哪(输出位置)
- 逆运动学 = 你抓住木偶的手(输入位置),让木偶自动算出四肢该摆成什么样(输出角度)
连续运动控制
CMD_CONSTANT_CTRL
{"T":123,"m":0,"axis":0,"cmd":0,"spd":0}
用于机械臂的连续控制。收到该指令后,机械臂会按照指定模式持续运动,直到收到停止指令或新的控制指令为止。该指令既支持关节角度控制,也支持末端坐标控制。
参数说明:
-
m:控制模式- 0:角度控制模式 - 控制机械臂各关节按角度方向连续转动。
- 1:坐标控制模式 - 控制机械臂末端执行器在空间坐标系中连续移动;系统通常会通过逆运动学将末端坐标变化换算为各关节动作。
-
axis:控制对象 不同模式下,axis 表示的控制对象不同。当 m = 0(角度控制模式)时:
- 1:BASE,底座关节
- 2:SHOULDER,肩关节
- 3:ELBOW,肘关节
- 4:WRIST1,手腕关节 1
- 5:WRIST2 / ROLL,手腕关节 2
- 6:HAND,夹爪关节
当 m = 1(坐标控制模式)时:
- 1:X 轴
- 2:Y 轴
- 3:Z 轴
- 4:Pitch 角
- 5:Roll 角
- 6:HAND / 手腕相关自由度
-
cmd:运动方向或状态- 0:STOP,停止运动
- 1:INCREASE,正方向持续运动 - 角度控制模式下目标关节角度增加;坐标控制模式下目标坐标值增加
- 2:DECREASE,反方向持续运动 - 角度控制模式下目标关节角度减少;坐标控制模式下目标坐标值减少
-
spd:速度系数表示连续运动的速度等级。数值越大,运动速度越快。由于机械臂各关节的最大转速和系统控制频率有限,建议取值范围为 0–20。实际生效速度还会受到硬件能力、负载和安全限制影响。
挑战任务
用 CMD_CONSTANT_CTRL 完成"L 型轨迹"(仅用坐标模式)
目标:让机械臂末端在平面上走出一个"L"形(先沿 X 轴正向移动一段,再沿 Y 轴正向移动一段),最后回到起点。
限制:只能使用 CMD_CONSTANT_CTRL 指令,且 m 必须为 1(坐标模式,逆运动学控制)。不能使用位置指令(如 T=104)。
操作步骤
依次在 Web 端点击 CMD_CONSTANT_CTRL,每次修改参数后发送,用目测判断移动距离,适时停止并切换方向:
-
沿 X 轴正向移动(假设移动约 100mm)
→ 末端开始沿 X 轴匀速移动。
观察末端位置,感觉走了约 100mm 后,发送停止: -
沿 Y 轴正向移动
→ 末端改为沿 Y 轴移动。同样目测约 100mm 后停止。 -
返回起点(先沿 Y 负向,再沿 X 负向)
→ 停止后返回。
JSON 指令序列:
-
沿 X 轴正向移动:
{"T":123, "m":1, "axis":1, "cmd":1, "spd":10} -
停止:
{"T":123, "m":1, "axis":1, "cmd":0, "spd":10} -
沿 Y 轴正向移动:
{"T":123, "m":1, "axis":2, "cmd":1, "spd":10} -
沿 Y 轴负向返回:
{"T":123, "m":1, "axis":2, "cmd":2, "spd":10} -
沿 X 轴负向返回:
{"T":123, "m":1, "axis":1, "cmd":2, "spd":10} -
停止:
{"T":123, "m":1, "axis":1, "cmd":0, "spd":10}
验证:
如果末端轨迹近似一个"L"形(先水平向右,再垂直向前),并且最终回到大致起点位置,则挑战成功。
- 由于没有精确的位置反馈,你需要肉眼观察末端移动距离,在合适时机发送停止和换向指令。
- 速度系数
spd可以调低(如 5~8),方便控制。 - 如果想更精确,可以先发送
CMD_XYZT_GOAL_CTRL让末端去一个已知点,然后从那里开始 L 形移动。
FLASH 文件系统操作
前置知识
Flash 文件系统与掉电保存
一句话:Flash 文件系统是一种让机械臂主控板在掉电后也能记住数据的方法——就像给板子配了一个微型 U 盘。
为什么需要它?
机械臂的下位机(如 ESP32、STM32)运行时,变量、参数默认存储在 RAM(内存) 中。
RAM 读写极快,但断电即清空——就像黑板上的粉笔字,一关电就没了。
如果你希望保存的数据(如零点校准值、任务计数、Wi-Fi 密码)在下次上电后还能读取,就需要在掉电之前将其写入 Flash 存储器。
核心概念
| 概念 | 说明 |
|---|---|
| Flash | 一种非易失性存储芯片,断电后内容不丢失。常见容量 4MB、16MB 等。 |
| 文件系统 | 一种管理 Flash 上数据的软件层,让你能用"文件名、文件夹、读写、删除"的方式操作数据,而不是直接管理物理地址。 |
| 写入时机 | 在掉电前(或数据变化后)主动调用保存函数,将数据写入 Flash。 |
| 读取时机 | 上电初始化时,从 Flash 中读取文件,恢复到变量中。 |
类比:
- RAM = 白板(方便擦写,但一断电字就消失)
- Flash = 刻字石板(断电后字还在,但写入次数有限)
- 文件系统 = 给石板划分格子并贴上标签("校准值。txt"),让你不用记住第几行第几列。
FLASH 文件操作
CMD_SCAN_FILES
{"T":200}
扫描当前 Flash 文件系统中的全部文件。 返回每个文件的文件名和文件内的第一行内容。
CMD_CREATE_FILE
{"T":201,"name":"file.txt","content":"inputContentHere."}
新建一个文件。
name:文件名称(需包含完整后缀)content:文件第一行内容
CMD_READ_FILE
{"T":202,"name":"mission_a.mission"}
读取某一个文件的内容,返回内容会标注行号。
name:文件名称(需包含完整后缀)
CMD_DELETE_FILE
{"T":203,"name":"file.txt"}
删除指定文件。
name:文件名称(需包含完整后缀)
CMD_APPEND_LINE
{"T":204,"name":"file.txt","content":"inputContentHere."}
在指定文件的末尾增加一行内容。
name:文件名称content:要增加的内容
CMD_INSERT_LINE
{"T":205,"name":"file.txt","lineNum":3,"content":"content"}
在指定文件中的指定行数处插入一行内容。
name:文件名称lineNum:插入的行数(第一行为 1)content:要插入的内容
CMD_REPLACE_LINE
{"T":206,"name":"file.txt","lineNum":3,"content":"Content"}
替换指定文件中的指定行数的内容。
name:文件名称lineNum:要替换的行数content:替换后的内容
CMD_READ_LINE
{"T":207,"name":"file.txt","lineNum":3}
读取指定文件中的指定行数的内容。
name:文件名称lineNum:要读取的行数
CMD_DELETE_LINE
{"T":208,"name":"file.txt","lineNum":3}
删除指定文件的指定行数的内容。
name:文件名称lineNum:要删除的行数
文件类型说明
.mission 文件:任务文件,可存储指令用于机械臂批量操作boot.mission:开机自动运行的任务文件(无文件时自动创建)wifiConfig.json:存储 WiFi 相关配置(无文件时自动创建)
返回格式示例
扫描文件返回:
>>>---=== File Name and First line ===---<<<
[file]: [boot.mission]
[first line]:
{"name":"boot","intro":"these cmds run automatically at boot."}
>>>---=== File Name and First line ===---<<<
[file]: [mission_a.mission]
[first line]:
{"name":"mission_a","intro":"test mission created in flash."}
读取文件返回:
---=== File Content ===---
reading file: [mission_a.mission] starts:
[lineNum: 1 ] - {"name":"mission_a","intro":"test mission created in flash."}
[lineNum: 2 ] - {"T":104,"x":235,"y":0,"z":234,"t":0,"r":0,"g":3.14,"spd":0.25}
^^^ ^^^ ^^^ reading file: mission_a.mission ends. ^^^ ^^^ ^^^
步骤录制和重现
在 ESP32 的 Flash 文件系统中存一个 .mission 文件,里面放 JSON 指令,就能批量录制和回放机械臂的动作。
本部分指令与 FLASH 文件系统操作指令的区别在于,本章仅用来对任务文件进行操作,而 FLASH 文件系统操作可以对所有的文件进行操作。
任务文件操作
任务文件操作基于 FLASH 文件系统函数封装,文件名不需要输入".mission"后缀。
CMD_CREATE_MISSION
{"T":220,"name":"mission_a","intro":"test mission created in flash."}
用来新建一个任务文件。
name:文件名称intro:文件介绍
CMD_MISSION_CONTENT
{"T":220,"name":"mission_a","intro":"test mission created in flash."}
用来读取任务文件的具体内容。
name:文件名称 读取到的任务文件为 mission_a.mission,返回值如下:
{"T":221,"name":"mission_a"}
---=== File Content ===---
reading file: [mission_a] starts:
{"name":"mission_a","intro":"test mission created in flash."}
[StepNum: 1 ] - {"T":104,"x":235,"y":0,"z":234,"t":3.14,"spd":0.25}
[StepNum: 2 ] - {"T":104,"x":104.3172406,"y":-112.6415887,"z":65.13450799,"t":0,"r":0,"g":3.14,"spd":0.25}
[StepNum: 3 ] - {"T":114,"led":155}
[StepNum: 4 ] - {"T":104,"x":-163.7763876,"y":-138.2353466,"z":105.0922663,"t":0,"r":0,"g":3.14,"spd":0.5}
[StepNum: 5 ] - {"T":114,"led":0}
[StepNum: 6 ] - {"T":114,"led":255}
[StepNum: 7 ] - {"T":104,"x":156.428798,"y":40.20501586,"z":76.68339473,"t":0,"r":0,"g":3.14,"spd":0.25}
[StepNum: 8 ] - {"T":111,"cmd":3000}
[StepNum: 9 ] - {"T":114,"led":0}
^^^ ^^^ ^^^ reading file: mission_a.mission ends. ^^^ ^^^ ^^^
注意:任务文件的第一行内容为任务文件的名称和简要介绍,从第二行起才是需要执行的第一步 JSON 指令,上述读取到的内容会标注出来每个步骤的序号
实际该任务文件案例的内容如下:
{"name":"mission_a","intro":"test mission created in flash."}
{"T":104,"x":235,"y":0,"z":234,"t":3.14,"spd":0.25}
{"T":104,"x":104.3172406,"y":-112.6415887,"z":65.13450799,"t":0,"r":0,"g":3.14,"spd":0.25}
{"T":114,"led":155}
{"T":104,"x":-163.7763876,"y":-138.2353466,"z":105.0922663,"t":0,"r":0,"g":3.14,"spd":0.5}
{"T":114,"led":0}
{"T":114,"led":255}
{"T":104,"x":156.428798,"y":40.20501586,"z":76.68339473,"t":0,"r":0,"g":3.14,"spd":0.25}
{"T":111,"cmd":3000}
{"T":114,"led":0}
CMD_APPEND_STEP_JSON
{"T":222,"name":"mission_a","step":"{\"T\":104,\"x\":235,\"y\":0,\"z\":234,\"t\":3.14,\"r\":0,\"g\":3.14,\"spd\":0.25}"}
用来将一个 JSON 指令追加到指定任务文件中。
name:文件名称step:要添加的 JSON 指令,具体格式参考上面的示例。
CMD_APPEND_STEP_FB
{"T":223,"name":"mission_a","spd":0.25}
文件末尾新增运动至当前位置
name:文件名称spd:设置机械臂运动到该目标位置的速度。
CMD_APPEND_DELAY
{"T":224,"name":"mission_a","delay":3000}
任务文件步骤之间新增延迟指令
name:文件名称delay:延迟时间,单位为毫秒。
CMD_INSERT_STEP_JSON
{"T":225,"name":"mission_a","stepNum":3,"step":"{\"T\":114,\"led\":255}"}
任务文件步骤之间新增 JSON 指令到指定序号
name:文件名称stepNum:要插入的步骤序号,从 1 开始计数。step:要插入的 JSON 指令,具体格式参考上面的示例。
注意:在本条指令和后续指令中,给的 stepNum 值是为 JSON 指令执行的步数,而非行数。如果给定的 stepNum 值为 3,则在该任务文件中为第 3 步要执行的 JSON 指令。
CMD_INSERT_STEP_FB
{"T":226,"name":"mission_a","stepNum":3,"spd":0.25}
任务文件步骤之间新增运动至当前位置到指定序号
name:文件名称stepNum:要插入的步骤序号,从 1 开始计数。spd:设置机械臂运动到该目标位置的速度。
CMD_INSERT_DELAY
{"T":227,"name":"mission_a","stepNum":3,"spd":3000}
任务文件步骤之间新增延迟指令到指定序号
name:文件名称stepNum:要插入的步骤序号,从 1 开始计数。spd:延迟时间。
CMD_REPLACE_STEP_JSON
{"T":228,"name":"mission_a","stepNum":3,"step":"{\"T\":114,\"led\":255}"}
任务文件步骤之间替换 JSON 指令到指定序号
name:文件名称stepNum:要替换的步骤序号,从 1 开始计数。step:要替换的 JSON 指令,具体格式参考上面的示例。
CMD_REPLACE_STEP_FB
{"T":229,"name":"mission_a","stepNum":3,"spd":0.25}
任务文件步骤之间替换运动至当前位置到指定序号
name:文件名称stepNum:要替换的步骤序号,从 1 开始计数。spd:设置机械臂运动到该目标位置的速度。
CMD_REPLACE_DELAY
{"T":230,"name":"mission_a","stepNum":3,"delay":3000}
任务文件步骤之间替换延迟指令到指定序号
name:文件名称stepNum:要替换的步骤序号,从 1 开始计数。delay:延迟时间,单位为毫秒。
CMD_DELETE_STEP
{"T":231,"name":"mission_a","stepNum":3}
任务文件步骤之间删除指定序号
name:文件名称stepNum:要删除的步骤序号,从 1 开始计数。
CMD_MOVE_TO_STEP
{"T":241,"name":"mission_a","stepNum":3}
执行任务文件中的指定序号命令
name:文件名称stepNum:要执行的步骤序号,从 1 开始计数。
CMD_MISSION_PLAY
{"T":242,"name":"mission_a","times":3}
播放任务文件中的所有命令
name:文件名称times:要执行的次数。
ESP-NOW 控制
前置知识
ESP‑NOW 控制(含数据结构)
一句话:ESP‑NOW 是 ESP32 之间"不用路由器、配对就能直连"的对讲机协议,适合给机械臂做低延迟遥控。
核心特点
- 无路由器:直接点对点通信,适合室外或网络不稳定的环境
- 低延迟:毫秒级响应,实时操控机械臂
- 短数据包:每次最多 250 字节,刚好塞下一条 JSON 指令
ESP‑NOW 通信数据结构体
机械臂下位机使用固定结构体接收数据:
typedef struct struct_message {
byte devCode; // 设备编号(可忽略,设 0 即可)
float base; // 基座关节弧度
float shoulder; // 肩关节弧度
float elbow; // 肘关节弧度
float hand; // 夹爪/腕关节弧度
byte cmd; // 控制类型(参照各 JSON 指令的 T 值含义)
char message[210]; // 备用字符串,当 cmd==1 时当作 JSON 指令执行
} struct_message;
广播从动模式设置
CMD_BROADCAST_FOLLOWER
{"T":300,"mode":1}
{"T":300,"mode":0,"mac":"00:00:00:00:00:00"}
设置该设备的广播从动模式。
mode:- 1 - [出厂默认] 该设备可以被其它设备发出的广播信号来控制。
- 0 - 该设备不可以被其它设备发出的广播信号来控制。
mac:在 mode 值为 0 的情况下,唯一 Leader 控制设备的 MAC 地址。给定一个 MAC 地址,则该设备只可以被给定 MAC 地址的设备所发出的 ESP-NOW 信息而控制;如果该设备不需要被任何设备控制,可以输入任意一个编造的 MAC 地址,例如:00:00:00:00:00:00。
ESP-NOW 工作方式设置
CMD_ESP_NOW_CONFIG
{"T":301,"mode":3}
设置该设备 ESP-NOW 的工作方式。
mode:ESP-NOW 的工作方式的代号。- 0 - 关闭;
- 1 - 流组播 Leader,持续向 peerList 中的设备发送自己的关节位置信息;
- 2 - 流单播/流广播 Leader,持续向某一 MAC 地址的设备发送自己的关节位置信息,当 MAC 地址设置为 FF:FF:FF:FF:FF:FF 则为流广播控制;
- 3 - [出厂默认] Follower,当机械臂处于这一模式下时,可以接收来自其它 Leader 设备的 ESP-NOW 信息,也可以作为 Leader 设备向其它设备发送 ESP-NOW 信息。
只有在流组播、流单播/流广播模式下,主控制设备会持续向被控制设备发送自己的关节位置信息,手动转动主控制设备,被控制设备才会跟着做出相同的运动动作。
获取本设备 MAC 地址
CMD_GET_MAC_ADDRESS
{"T":302}
获得本设备的 MAC 地址。
返回值示例:
44:17:93:EE:FD:70
每个设备的 MAC 地址都是独一无二的。当你使用 ESP-NOW 的相关功能时,除广播控制外,都需要获得被控制设备的 MAC 地址。默认情况下,每一台机械臂的 OLED 屏幕上会显示自己的 MAC 地址。
添加被控制设备到 peerList
CMD_ESP_NOW_ADD_FOLLOWER
{"T":303,"mac":"44:17:93:EE:FD:70"}
将被控制设备的 MAC 地址添加到 peerList 中。peerList 是用来存储 MAC 地址的。
mac:需要添加的被控制设备的 MAC 地址。 peerList 中可以添加十几个 MAC 地址用于组播控制,但是当使用组播控制时,peerList 中不可以存有用于广播控制的 MAC 地址:FF:FF:FF:FF:FF:FF。
从 peerList 删除被控制设备
CMD_ESP_NOW_REMOVE_FOLLOWER
{"T":304,"mac":"44:17:93:EE:FD:70"}
将被控制设备的 MAC 地址从 peerList 中删除。
mac:需要删除的被控制设备的 MAC 地址。
组播控制
CMD_ESP_NOW_GROUP_CTRL
{"T":305,"dev":0,"b":0,"s":0,"e":1.57,"h":1.57,"cmd":0,"megs":"hello!"}
{"T":305,"dev":0,"b":0,"s":0,"e":0,"h":0,"cmd":1,"megs":"{\"T\":114,\"led\":255}"}
使用该指令将信息通过 ESP-NOW 组播发送给 peerList 中的全部设备。 参考 ESP-NOW 通信数据结构体部分的内容,该 JSON 指令中各个键对照结构体变量如下,且含补充部分:
dev:对应变量 devCode。b、s、e、h:分别对应变量 base、shoulder、elbow 和 hand。cmd:ESP-NOW 控制信息类型。- 当
cmd为 0 时,被控制的机械臂会转动到给定的各个关节的角度; - 当
cmd为 1 时,b、s、e、h 无效,在 megs 输入不会引起阻塞的 JSON 指令,机械臂会执行 JSON 指令对应的功能。
- 当
megs:对应变量 message。
单播/广播控制
CMD_ESP_NOW_SINGLE
{"T":306,"mac":"44:17:93:EE:FD:70","dev":0,"b":0,"s":0,"e":1.57,"h":1.57,"cmd":0,"megs":"hello!"}
{"T":306,"mac":"FF:FF:FF:FF:FF:FF","dev":0,"b":0,"s":0,"e":1.57,"h":1.57,"cmd":0,"megs":"hello!"}
使用该指令可以单播或广播控制 peerList 中的设备。
mac:被控制设备的 MAC 地址,当 MAC 地址为 FF:FF:FF:FF:FF:FF 时,该指令为广播信号,会发送给全部设备。 参考 ESP-NOW 通信数据结构体部分的内容,该 JSON 指令中各个键对照结构体变量如下,且含补充部分:dev:对应变量 devCode。b、s、e、h:分别对应变量 base、shoulder、elbow 和 hand。cmd:ESP-NOW 控制信息类型。- 当
cmd为 0 时,被控制的机械臂会转动到给定的各个关节的角度; - 当
cmd为 1 时,b、s、e、h 无效,在 megs 输入不会引起阻塞的 JSON 指令,机械臂会执行 JSON 指令对应的功能。
- 当
megs:对应变量 message。
无论是组播控制,还是单播/广播控制,都需要提前将被控制设备的 MAC 地址添加到 peerList 中。
挑战任务
ESP-NOW 多设备控制实战
目标:使用机械臂 A 分别实现广播控制、单播控制和组播控制,掌握 ESP-NOW 三种控制模式的实际应用。
场景设定:假设您有四个机械臂 A、B、C、D,其中 A 作为主控制设备,B、C、D 作为被控制设备。
任务一:广播控制
使用机械臂 A 同时控制 B、C、D 三个机械臂:
- 添加广播 MAC 地址到 peerList:
{"T":303,"mac":"FF:FF:FF:FF:FF:FF"} - 发送 LED 控制指令:
{"T":306,"mac":"FF:FF:FF:FF:FF:FF","dev":0,"b":0,"s":0,"e":0,"h":0,"cmd":1,"megs":"{\"T\":114,\"led\":255}"} - 关闭机械臂 A 扭矩锁:
{"T":210,"cmd":0} - 开启流广播模式:
{"T":301,"mode":2} - 手动转动机械臂 A,观察 B、C、D 是否同步运动
任务二:单播控制
使用机械臂 A 单独控制机械臂 B:
- 添加机械臂 B 的 MAC 地址:
{"T":303,"mac":"BB:BB:BB:BB:BB:BB"} - 发送 LED 控制指令给 B:
{"T":306,"mac":"BB:BB:BB:BB:BB:BB","dev":0,"b":0,"s":0,"e":0,"h":0,"cmd":1,"megs":"{\"T\":114,\"led\":255}"} - 开启流单播模式:
{"T":301,"mode":2} - 手动转动机械臂 A,观察只有 B 同步运动
任务三:组播控制
使用机械臂 A 同时控制机械臂 B 和 C:
-
添加 B 和 C 的 MAC 地址到 peerList
-
删除广播地址(如果存在):
{"T":304,"mac":"FF:FF:FF:FF:FF:FF"} -
发送组播 LED 控制指令:
{"T":305,"dev":0,"b":0,"s":0,"e":0,"h":0,"cmd":1,"megs":"{\"T\":114,\"led\":255}"} -
开启流组播模式:
{"T":301,"mode":1} -
手动转动机械臂 A,观察 B 和 C 同步运动
提示挑战要点:
- 理解三种控制模式的区别:广播(无需 MAC)、单播(指定 MAC)、组播(多个 MAC)
- 掌握 peerList 的管理:添加、删除 MAC 地址
- 熟悉 ESP-NOW 工作模式的切换
- 注意:所有指令都通过机械臂 A 发送