本周经过与指导老师和组长以及另外两个成员的周会交流讨论,我们对项目架构进行了一定的调整,云端决定采用基于 OpenClaw 开发的,包括接收 WebApp 的文字/语音输入并完成解析,以及开发“序列—动作映射”这一skill;Milk-V Duo S端直接负责制作接收云端传输的动作序列,并开发持续调试机器人动作库以完成序列对应的动作组。

在开发过程中使用AI辅助生成了一些模块的初始代码,例如PWM控制、动作组执行和串口通信等。但这些代码只是作为参考,我们根据具体硬件平台进行了重构和优化,最终形成了适用于本项目的控制系统。

本周主要进行机器人端的开发。

进行控制系统的基本搭建

包括:

使用USB将32路舵机控制器连接至电脑

安装串口驱动并确认端口号

在上位机软件中通过串口(115200波特率)建立通信连接

连接成功后,可以通过软件实时向舵机发送控制指令

技术理解:这一控制方式本质上是串口协议 + PWM信号抽象控制。上位机发送的是位置参数(P值),控制器再转换为PWM信号驱动舵机。

在开发动作组之前,最重要的基础是先对每个位置的舵机不同大小的PWM值进行十分精细化的认识。

我花了很多时间做的并不是直接写动作组,而是一个一个舵机地“认识”它们。我把每个舵机子窗口单独打开,用鼠标拖着滑竿从一端划到另一端,一边看串口发出去的 P 值,一边用手感觉机器人关节的真实活动范围。调到一个位置,觉得姿态对了,就记下那个 P 值;碰到结构开始吱吱响的角度,就马上双击 MIN 或 MAX 标签把极限锁死,省得后面调试动作时误伤舵机。

偏差值 B 也是这么试出来的——同一条腿,左右两边装得再仔细也有十几微秒的传感器误差,我就反复滑动滑竿让两条腿对称,再把差值填进 B 值输入框,直到两边动作肉眼完全一致。

使用AI生成代码:提示词/VIBE/SPEC过程

 第一个动作组:站立模块

站立动作组是整个机器人动作编排体系的“原点”与“锚点”。它仅由单个步骤构成,使用 1 秒时间将所有 17 个舵机一次性复位到一套经过校准的标准中立姿态。这套 P 值(如肩部 #5 P2151、肘部 #6 P1570、头部 #24 P1500 等)定义了机器人在无任务时的自然站立形态,既是所有动态动作的起始基准,也是动作组安全切换的“归零”状态。正因为其极简的单步结构和完全固定的参数,站立动作组天然具备最高的兼容性——在任何复杂的动作序列前后插入它,都可以可靠地清除动作间的姿态累积误差,避免关节进入非预期的极限位置。从通信协议的角度看,它通过全局时间 T1000 同步驱动所有舵机,保证了全身关节的平顺归位,而没有任何单一舵机抢拍的风险。这个看似最没有变化的动作文件,实则是构建长时序、多组别情感动作的基石。

提示词1:

请生成一个 SmartRobot2025 上位机软件使用的动作组 XML 代码文件.严格按照以下要求输出完整的 XML 代码,不要省略任何内容,也不要添加额外解释。

文件格式要求:
- XML 声明:<?xml version="1.0" encoding="UTF-8"?>
- 根元素为 <NewDataSet>,内部包含一个 <Table1> 元素,代表唯一的一步动作。
- <Table1> 中包含:
  - <ID>:1
  - <Move>:舵机控制指令字符串,格式为 “#舵机号 P脉宽值 …”,多个舵机指令用空格分隔,必须包含全部 17 个舵机。
  - <Time>:该步动作的执行时间,格式为 “T毫秒数”。
  - <position>:该步对应的子窗口坐标字符串。

动作数据定义:
- <Move> 内容(完全照此生成,不可更改任何数值):
  #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500
- <Time> 内容:
  T1000
- <position> 内容(固定字符串,一字不差):
  POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134

请现在输出完整的 XML 文件。

产出code:

<?xml version="1.0" encoding="UTF-8"?>
<NewDataSet>
  <Table1>
    <ID>1</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T1000</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
</NewDataSet>

第二个动作组:左右挥手模块

在我们这个项目中,“挥手”动作组不仅是最简单的人机交互手势之一,也是一种将舵机序列与时间轴优雅组合的编程思路。

技术理解:

挥手动作组的本质,是在时间线上对多个舵机的脉宽值(P值)进行关键帧编排,从而让机器人手臂完成一次从静止、抬臂、挥手到复原的连贯动作。

我将这个动作组设计为如下15个步骤,之后进行一步接一步的根据机器人的动作效果反复调试参数:

步骤 动作描述
步骤 1 机器人以站立姿态准备,手臂处于自然垂放位置。
步骤 2 右臂(#24)微微抬起至 P1860,做出挥手起始动作。
步骤 3 右臂保持抬起,同时手肘(#25)下沉至 P1020、肩部(#26)前移,形成挥动的预备姿态。
步骤 4 肩部继续上扬至 P1880,脚踝(#27)联动抬起,手腕开始转动。
步骤 5 手肘回收至 P1660,手腕恢复原位,形成一次完整的挥动循环。
步骤 6 重复挥动:肩部再上抬至 P1880,脚踝配合,加强挥手幅度。
步骤 7 手肘再回收至 P1660,手腕归位,完成第二次挥动。
步骤 8 挥动速度放缓,肩部恢复原位,手臂维持抬起,停顿一下。
步骤 9 手臂快速切换至另一侧低位(#24 P1080),形成向下的摆动。
步骤 10 手腕(#22、#23)大幅转动,配合同侧手臂的挥拍动作。
步骤 11 手腕轻微回收调整,完成反向挥动的细节。
步骤 12 手臂回到低位,手腕保持转动,重复挥动节奏。
步骤 13 手腕再次微调,维持挥手动动态。
步骤 14 最后一次手腕转动,手臂仍保持低位。
步骤 15 所有关节恢复站立姿态,挥手结束。

整个动作组由 15 个步骤(Table1)构成,每个步骤都是一组完整的舵机指令字符串,其中由于我们采用的是包含了 17 个舵机的目标角度和当前步的执行时间(Time),而步骤间的切换由上位机或控制器根据时间自动推进。

我将机器人手臂抽象为两到三个关键关节:舵机 #24是挥手时上下运动的主驱动关节,它在 P1500(中间值)与 P1080(低角度)之间反复跳变,形成“招手”的视觉效果;舵机#25和 #26 则在 P2500、P2000、P1020、P1880、P1660 之间交替,分别控制手臂或手肘的伴随运动,赋予挥手动作更自然的弧线;舵机 #22 和 #23在动作中期(步骤 10‑14)短暂切换到 `P1240`/`P2060` 和 `P1040`/`P2060`,像是加入了一个细微的手腕翻腕过渡,让挥手不再机械,而更接近人类的习惯。

时间节奏上,这份动作组通过 T1000、T500 的交替分配,营造了一种“稍慢—快—快—稍慢”的节律:前两步用 1000 ms 和 500 ms 完成手臂的初始抬起,中间 10 个步骤用密集的 500 ms 往返实现快速挥手(大约 2.5 秒内完成 5 次摆动),最后一步再以 1000 ms 平滑收拢回初始姿态。这种刻意做成的速度变化,模仿了真实挥手时加速、维持、减速的自然动态,也避免了因突然停止造成的机械冲击——这正是从通信协议中 T`指令的设计初衷,它让所有舵机在指定时间内以协调的速率同步移动到目标位置,而不是各自以固定速率狂奔。

整个动作组不包含任何 S(单舵机速率)指令,所有步骤均依赖全局时间 T 来同步多舵机的运动,这保证了挥手时各关节动作的相位一致性。配合 XML 中固定的 position 信息(记录各个舵机控制子窗口的界面坐标),可以看到即使在上位机软件里,这些数据也是有序、可复现、可复用的。随着我对 B 值(偏差)和 MIN/MAX(角度限位)的深入使用,甚至可以做到同一份挥手动作组在不同装配误差的机器人上通用,这正是协议与软件设计中一次编排,处处运行的工程智慧。

提示词1:

请生成一个 SmartRobot2025 上位机软件使用的动作组 XML 文件,文件命名为“1-挥手.xml”。严格按照以下要求输出完整的 XML 代码,不要省略任何内容,也不要添加额外解释。

文件格式要求:
- XML 声明:<?xml version="1.0" encoding="UTF-8"?>
- 根元素为 <NewDataSet>,内部包含一系列 <Table1> 元素,每个 <Table1> 代表一步动作。
- 每个 <Table1> 中包含:
  - <ID>:从 1 开始递增的步序号。
  - <Move>:舵机控制指令字符串,格式为 “#舵机号 P脉宽值 …”,多个舵机指令用空格分隔。
  - <Time>:该步动作的执行时间,格式为 “T毫秒数”。
  - <position>:该步对应的子窗口坐标字符串,所有步骤的 position 保持完全一致。

动作数据定义:
1. 基础姿态(当舵机值未在步骤中特别说明时,始终使用以下基础值):
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500

2. 15 个动作步骤的 <Move> 和 <Time> 如下(每一步均需包含所有 17 个舵机的完整指令,未变化的舵机沿用基础值):
   步骤1:T1000
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500

   步骤2:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P2500 #26 P2000 #27 P1500

   步骤3:T1000
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1660 #27 P1500

   步骤4:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1880 #27 P2100

   步骤5:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1660 #27 P1500

   步骤6:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1880 #27 P2100

   步骤7:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1660 #27 P1500

   步骤8:T1000
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P2500 #26 P2000 #27 P1500

   步骤9:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1080 #25 P2500 #26 P2000 #27 P1500

   步骤10:T1000
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1240 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500

   步骤11:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P980 #22 P1040 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500

   步骤12:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1240 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500

   步骤13:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P980 #22 P1040 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500

   步骤14:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1240 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500

   步骤15:T1000
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500

3. 所有步骤的 <position> 统一使用之前发给你的固定字符串(一字不差):
   POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134

请现在输出完整的 XML 文件。

产出code:

<?xml version="1.0" encoding="UTF-8"?>
<NewDataSet>
  <Table1>
    <ID>1</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T1000</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>2</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>3</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1660 #27 P1500</Move>
    <Time> T1000</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>4</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1880 #27 P2100</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>5</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1660 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>6</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1880 #27 P2100</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>7</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P1020 #26 P1660 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>8</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1860 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T1000</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>9</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1080 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>10</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1240 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T1000</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>11</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P980 #22 P1040 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>12</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1240 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>13</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P980 #22 P1040 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>14</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1240 #23 P2060 #24 P1080 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>15</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T1000</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
</NewDataSet>

提示词2:

请根据我们测试好的参数数据文件,为我生成一个“挥手”动作组的 C 语言程序文件,
要求:
1)代码要兼容我前面已经设计好的动作组解析模块和动作控制模块
2)使用如下数据结构:
   typedef struct {
       unsigned char id;
       unsigned int pwm;
   } ServoCmd;

   typedef struct {
       const ServoCmd *cmds;
       unsigned char num;
       unsigned int time;
   } ActionStep;

   typedef struct {
       const ActionStep *steps;
       unsigned char step_num;
       const char *name;
   } ActionGroup;
3)把数据文件中每一个 Table1 节点解析成一步动作
4)Move 字段拆分成 ServoCmd 数组
5)Time 字段转换为 ActionStep.time
6)最终导出一个完整的动作组常量:
   const ActionGroup g_action_wave
7)代码风格要适合嵌入式工程,能直接放入 .c / .h 文件中使用

AI代码:

文件一:Action_Wave.h

#ifndef __ACTION_WAVE_H__
#define __ACTION_WAVE_H__

#ifdef __cplusplus
extern "C" {
#endif

/* 依赖你前面动作组核心模块中的结构体定义 */
typedef struct
{
    unsigned char id;     /* 舵机编号 0~31 */
    unsigned int  pwm;    /* 脉宽 500~2500 */
} ServoCmd;

typedef struct
{
    const ServoCmd *cmds; /* 当前步舵机数组 */
    unsigned char   num;  /* 当前步舵机数量 */
    unsigned int    time; /* 当前步执行时间 ms */
} ActionStep;

typedef struct
{
    const ActionStep *steps;
    unsigned char     step_num;
    const char       *name;
} ActionGroup;

/* 导出:挥手动作组 */
extern const ActionGroup g_action_wave;

/* 可选:导出一个动作组编号,便于统一管理 */
#define ACTION_ID_WAVE   0

#ifdef __cplusplus
}
#endif

#endif

文件二:Action_Wave.c

#include "Action_Wave.h"

/*
 * 动作名称:挥手
 * 数据来源:1-挥手.xml
 * 说明:
 * 1)每一步对应 XML 中的一个 <Table1>
 * 2)Move 字段被拆成 ServoCmd 数组
 * 3)Time 字段被转换为 ActionStep.time
 * 4)可直接接入前面设计的 AG_RunActionGroup(&g_action_wave)
 */

/*===========================================================
 * Step 1  对应 XML: ID=1  Time=T1000
 *==========================================================*/
static const ServoCmd g_wave_step1_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1500}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 2  对应 XML: ID=2  Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step2_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1860}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 3  对应 XML: ID=3  Time=T1000
 *==========================================================*/
static const ServoCmd g_wave_step3_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1860}, {25, 1020},
    {26, 1660}, {27, 1500}
};

/*===========================================================
 * Step 4  对应 XML: ID=4  Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step4_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1860}, {25, 1020},
    {26, 1880}, {27, 2100}
};

/*===========================================================
 * Step 5  对应 XML: ID=5  Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step5_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1860}, {25, 1020},
    {26, 1660}, {27, 1500}
};

/*===========================================================
 * Step 6  对应 XML: ID=6  Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step6_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1860}, {25, 1020},
    {26, 1880}, {27, 2100}
};

/*===========================================================
 * Step 7  对应 XML: ID=7  Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step7_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1860}, {25, 1020},
    {26, 1660}, {27, 1500}
};

/*===========================================================
 * Step 8  对应 XML: ID=8  Time=T1000
 *==========================================================*/
static const ServoCmd g_wave_step8_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1860}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 9  对应 XML: ID=9  Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step9_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1080}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 10 对应 XML: ID=10 Time=T1000
 *==========================================================*/
static const ServoCmd g_wave_step10_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1240}, {23, 2060}, {24, 1080}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 11 对应 XML: ID=11 Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step11_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 980}, {22, 1040}, {23, 2060}, {24, 1080}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 12 对应 XML: ID=12 Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step12_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1240}, {23, 2060}, {24, 1080}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 13 对应 XML: ID=13 Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step13_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 980}, {22, 1040}, {23, 2060}, {24, 1080}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 14 对应 XML: ID=14 Time=T500
 *==========================================================*/
static const ServoCmd g_wave_step14_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1240}, {23, 2060}, {24, 1080}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * Step 15 对应 XML: ID=15 Time=T1000
 *==========================================================*/
static const ServoCmd g_wave_step15_cmds[] =
{
    {3, 1895}, {4, 1919}, {5, 2151}, {6, 1570}, {7, 1477},
    {8, 1523}, {9, 1430}, {10, 826}, {11, 1081}, {12, 1105},
    {21, 1477}, {22, 1000}, {23, 500}, {24, 1500}, {25, 2500},
    {26, 2000}, {27, 1500}
};

/*===========================================================
 * 动作步表
 *==========================================================*/
static const ActionStep g_wave_steps[] =
{
    {g_wave_step1_cmds,  17, 1000},
    {g_wave_step2_cmds,  17, 500},
    {g_wave_step3_cmds,  17, 1000},
    {g_wave_step4_cmds,  17, 500},
    {g_wave_step5_cmds,  17, 500},
    {g_wave_step6_cmds,  17, 500},
    {g_wave_step7_cmds,  17, 500},
    {g_wave_step8_cmds,  17, 1000},
    {g_wave_step9_cmds,  17, 500},
    {g_wave_step10_cmds, 17, 1000},
    {g_wave_step11_cmds, 17, 500},
    {g_wave_step12_cmds, 17, 500},
    {g_wave_step13_cmds, 17, 500},
    {g_wave_step14_cmds, 17, 500},
    {g_wave_step15_cmds, 17, 1000}
};

/*===========================================================
 * 对外导出的挥手动作组
 *==========================================================*/
const ActionGroup g_action_wave =
{
    g_wave_steps,
    15,
    "wave"
};

前面核心模块里已经有:

  • AG_RunActionGroup(const ActionGroup *group);

  • AG_RunLocalActionById(unsigned char id);

那我们可以直接这样调用:

#include "Action_Wave.h"

/* 直接执行挥手动作组 */
AG_RunActionGroup(&g_action_wave);

把“挥手”加入统一动作表

#include "Action_Wave.h"

static const ActionGroup *g_action_table[] =
{
    &g_action_wave,   /* 0: 挥手 */
};

动作步数、舵机编号、脉宽和时间都对应测试出来的数据文件中的所有15个节点。

第三个动作组:摇头模块       

        在“摇头”动作组中,机器人仅通过头部关节舵机 #24 的脉宽值(P值)规律摆动,配合其余 16 个关节全程保持恒定,实现了全身姿态稳定下的自然摇头。舵机 #24 以 P1500 → 919 → 2058 → 1407 → 895 → 1523 → 1500 的非对称往复路径,模拟了类似人类微侧头的自然否定动作,避免了机械式的镜像对称。时间上则通过 T800、T200、T300、T500 的交替组合,形成定格—突转—加速—回稳的节奏感,所有舵机始终依赖全局时间 T 同步运动,未使用任何单舵机速率指令,确保动作协调且无抢拍冲击。

摇头动作组我们在设计开发的时候,将其划分为按照顺序依次进行的16个步骤,

这16帧步骤全部集中在头部舵机(#24)

步骤 动作描述
步骤 1 机器人以站立姿态静止,头部居中。
步骤 2 头部保持原位,做极短暂的停顿(T200)。
步骤 3 头部(#24)转向一侧至 P919,开始摇头。
步骤 4 头部在该侧短暂停留(T500),增强转向幅度。
步骤 5 头部转回中间偏另一侧至 P1523。
步骤 6 在该位置停留,准备向另一侧摆动。
步骤 7 头部大幅度转向相反侧至 P2058,完成一次摇头。
步骤 8 在该侧停留,突出摇头端点。
步骤 9 头部回摆至中间位置 P1407,过渡缓冲。
步骤 10 在中间位置保持,平衡节奏。
步骤 11 头部再次转向低位侧至 P895,重复摇头。
步骤 12 在该侧停留,维持摇头频率。
步骤 13 头部又一次大幅度转向高位侧至 P2058,加强动作。
步骤 14 在高位侧停留,形成对称摆动。
步骤 15 头部缓慢回中至 P1500,摇头动作接近结束。
步骤 16 头部继续保持居中,最终定格在站立姿态。

提示词1:

请生成一个 SmartRobot2025 上位机软件使用的动作组 XML 文件,文件命名为“2-摇头.xml”。严格按照以下要求输出完整的 XML 代码,不要省略任何内容,也不要添加额外解释。

文件格式要求:
- XML 声明:<?xml version="1.0" encoding="UTF-8"?>
- 根元素为 <NewDataSet>,内部包含一系列 <Table1> 元素,每个 <Table1> 代表一步动作。
- 每个 <Table1> 中包含:
  - <ID>:从 1 开始递增的步序号。
  - <Move>:舵机控制指令字符串,格式为 “#舵机号 P脉宽值 …”,多个舵机指令用空格分隔。
  - <Time>:该步动作的执行时间,格式为 “T毫秒数”。
  - <position>:该步对应的子窗口坐标字符串,所有步骤的 position 保持完全一致。

动作数据定义:
1. 基础姿态(除舵机 24 外,其余舵机值在所有步骤中保持不变):
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #25 P2500 #26 P2000 #27 P1500

2. 16 个动作步骤的 <Move> 和 <Time>,请严格按照以下完整指令生成,特别注意舵机 24 的 P 值变化:
   步骤1:T800
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500

   步骤2:T200
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500

   步骤3:T300
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P919 #25 P2500 #26 P2000 #27 P1500

   步骤4:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P919 #25 P2500 #26 P2000 #27 P1500

   步骤5:T300
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1523 #25 P2500 #26 P2000 #27 P1500

   步骤6:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1523 #25 P2500 #26 P2000 #27 P1500

   步骤7:T300
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500

   步骤8:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500

   步骤9:T300
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1407 #25 P2500 #26 P2000 #27 P1500

   步骤10:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1407 #25 P2500 #26 P2000 #27 P1500

   步骤11:T300
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P895 #25 P2500 #26 P2000 #27 P1500

   步骤12:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P895 #25 P2500 #26 P2000 #27 P1500

   步骤13:T300
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500

   步骤14:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500

   步骤15:T300
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500

   步骤16:T500
   #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500

3. 所有步骤的 <position> 统一使用以下固定字符串(一字不差):
   POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134

请现在输出完整的 XML 文件。
步骤 T 延时 #3 #4 #5 #6 #7 #8 #9 #10 #11 #12 #21 #22 #23 #24 #25 #26 #27
步骤 1 T800 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1500 P2500 P2000 P1500
步骤 2 T200 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1500 P2500 P2000 P1500
步骤 3 T300 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P919 P2500 P2000 P1500
步骤 4 T500 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P919 P2500 P2000 P1500
步骤 5 T300 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1523 P2500 P2000 P1500
步骤 6 T500 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1523 P2500 P2000 P1500
步骤 7 T300 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P2058 P2500 P2000 P1500
步骤 8 T500 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P2058 P2500 P2000 P1500
步骤 9 T300 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1407 P2500 P2000 P1500
步骤 10 T500 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1407 P2500 P2000 P1500
步骤 11 T300 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P895 P2500 P2000 P1500
步骤 12 T500 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P895 P2500 P2000 P1500
步骤 13 T300 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P2058 P2500 P2000 P1500
步骤 14 T500 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P2058 P2500 P2000 P1500
步骤 15 T300 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1500 P2500 P2000 P1500
步骤 16 T500 P1895 P1919 P2151 P1570 P1477 P1523 P1430 P826 P1081 P1105 P1477 P1000 P500 P1500 P2500 P2000 P1500

产出code:

<?xml version="1.0" encoding="UTF-8"?>
<NewDataSet>
  <Table1>
    <ID>1</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T800</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>2</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T200</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>3</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P919 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T300</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>4</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P919 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>5</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1523 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T300</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>6</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1523 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>7</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T300</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>8</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>9</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1407 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T300</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>10</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1407 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>11</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P895 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T300</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>12</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P895 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>13</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T300</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>14</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P2058 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>15</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T300</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
  <Table1>
    <ID>16</ID>
    <Move> #3 P1895 #4 P1919 #5 P2151 #6 P1570 #7 P1477 #8 P1523 #9 P1430 #10 P826 #11 P1081 #12 P1105 #21 P1477 #22 P1000 #23 P500 #24 P1500 #25 P2500 #26 P2000 #27 P1500</Move>
    <Time> T500</Time>
    <position> POS3X=221Y=165 POS4X=251Y=249 POS5X=251Y=332 POS6X=251Y=416 POS7X=122Y=416 POS8X=554Y=419 POS9X=427Y=419 POS10X=427Y=336 POS11X=428Y=253 POS12X=467Y=170 POS21X=57Y=128 POS22X=92Y=39 POS23X=223Y=81 POS24X=346Y=3 POS25X=467Y=87 POS26X=596Y=47 POS27X=637Y=134</position>
  </Table1>
</NewDataSet>

 在动作组代码生成阶段,我们将对17个舵机各个角度范围测试过之后,的舵机移动参数文件作为高层动作描述数据,通过提示词引导 AI 将每个 Table1 节点转换为一步动作,并进一步映射为 ServoCmdActionStepActionGroup 三层数据结构。以“挥手”和“站立”两个动作组为例,最终生成的代码已经能够直接接入前面设计的动作组解析模块和动作控制模块,实现“动作组数据 → 串口协议 → 控制器执行”的完整链路。其中,“站立”动作组由单步姿态构成,而“挥手”动作组则由多步连续动作构成。

 多路舵机PWM控制模块设计

提示词:

请帮我用C语言实现一个基于51单片机的多路舵机PWM控制程序,
要求:
1)使用定时器中断
2)控制17路舵机
3)脉宽范围500~2500us
4)周期20ms
5)代码结构清晰,方便扩展

AI代码生成:

#define SERVO_NUM 17

unsigned int pwm_value[SERVO_NUM] = {1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500};

void timer0_ISR() interrupt 1
{
    static unsigned char state = 0;
    
    switch(state)
    {
        case 0:
            P0 = 0xFF; // 全部拉高
            set_timer(pwm_value[0]);
            break;
        case 1:
            P0 = 0x00;
            set_timer(20000 - pwm_value[0]);
            break;
    }
    
    state++;
}

后续我们进行了针对性优化,

  • 引入 状态机轮询(16阶段)

  • 支持 每路独立PWM控制

  • 优化定时器精度

动作组解析模块(核心)

  • 支持串口协议发送

  • 支持批量舵机同步控制

  • 支持动作组编号调用

  • 实现了“动作组 → 串口指令 → 控制器执行”

提示词:

请帮我设计一个动作组执行函数,
要求:
1)输入多个舵机编号和目标脉宽
2)支持同时控制多个舵机
3)支持执行时间控制

AI生成代码

/************************************************************
 * 文件名:ActionGroup.c / ActionGroup.h(可合并使用)
 * 功  能:动作组解析模块(核心)
 * 说  明:
 *   1. 将动作组数据转换为舵机控制器协议字符串
 *   2. 支持多舵机同步控制
 *   3. 支持动作组编号调用
 *   4. 支持动作组执行速度比、开始步编号、单次执行等扩展命令
 ************************************************************/

#include <stdio.h>
#include <string.h>

/*===========================================================
 * 一、底层串口发送接口适配
 *==========================================================*/
/*
 * 说明:
 * 1)如果你是 STM32 工程,保留 extern void UART_WriteByte(char Data);
 * 2)如果你是 STC 工程,改成 extern void UART1SendOneChar(unsigned char valu);
 * 3)这里统一封装成 AG_SendChar / AG_SendString
 */

/* --------- 方案1:STM32 --------- */
extern void UART_WriteByte(char Data);

/* --------- 方案2:STC(如果用STC就取消下面注释,并注释上面的extern) --------- */
/* extern void UART1SendOneChar(unsigned char valu); */

static void AG_SendChar(char ch)
{
    UART_WriteByte(ch);
    /* STC平台改成:
       UART1SendOneChar((unsigned char)ch);
    */
}

static void AG_SendString(const char *str)
{
    while (*str != '\0')
    {
        AG_SendChar(*str++);
    }
}

/*===========================================================
 * 二、动作组核心数据结构
 *==========================================================*/

/* 单个舵机控制命令 */
typedef struct
{
    unsigned char id;     /* 舵机编号 0~31 */
    unsigned int  pwm;    /* 脉宽 500~2500 */
} ServoCmd;

/* 单步动作:多个舵机同时到位 */
typedef struct
{
    const ServoCmd *cmds; /* 舵机命令数组 */
    unsigned char   num;  /* 本步参与舵机数量 */
    unsigned int    time; /* 本步执行时间 ms */
} ActionStep;

/* 完整动作组:多个动作步 */
typedef struct
{
    const ActionStep *steps;     /* 动作步数组 */
    unsigned char     step_num;  /* 步数 */
    const char       *name;      /* 动作组名称,便于调试 */
} ActionGroup;

/*===========================================================
 * 三、协议字符串构造函数
 *==========================================================*/

/*
 * 舵机控制器协议格式(多舵机同步):
 *   #5 P1600 #10 P750 T2500\r\n
 *
 * 动作组控制协议格式:
 *   PL 0 SQ 5 SM 100\r\n
 */

#define AG_TX_BUFFER_SIZE 256

/* 将单步动作转换为协议字符串 */
static int AG_BuildStepCommand(const ServoCmd cmds[],
                               unsigned char num,
                               unsigned int time,
                               char *buffer,
                               unsigned int buffer_size)
{
    unsigned int used = 0;
    unsigned char i;
    int len;

    if (buffer == NULL || buffer_size == 0)
    {
        return -1;
    }

    buffer[0] = '\0';

    for (i = 0; i < num; i++)
    {
        /* 按说明书格式拼接:#<id> P<pwm> */
        len = snprintf(buffer + used,
                       buffer_size - used,
                       "#%u P%u ",
                       cmds[i].id,
                       cmds[i].pwm);

        if (len < 0 || (unsigned int)len >= (buffer_size - used))
        {
            return -2; /* 缓冲区不足 */
        }

        used += (unsigned int)len;
    }

    /* 最后拼时间参数 */
    len = snprintf(buffer + used,
                   buffer_size - used,
                   "T%u\r\n",
                   time);

    if (len < 0 || (unsigned int)len >= (buffer_size - used))
    {
        return -3;
    }

    return 0;
}

/* 构造动作组调用协议字符串:
 * PL 0 SQ <seq> [SM <speed>] [IX <index>] [ONCE]
 */
static int AG_BuildGroupCommand(unsigned char seq,
                                int speed_percent,
                                unsigned char start_index,
                                unsigned char use_once,
                                char *buffer,
                                unsigned int buffer_size)
{
    int len;
    unsigned int used = 0;

    if (buffer == NULL || buffer_size == 0)
    {
        return -1;
    }

    buffer[0] = '\0';

    len = snprintf(buffer + used, buffer_size - used, "PL 0 SQ %u ", seq);
    if (len < 0 || (unsigned int)len >= (buffer_size - used))
    {
        return -2;
    }
    used += (unsigned int)len;

    /* 速度比可正可负,100表示正向100% */
    len = snprintf(buffer + used, buffer_size - used, "SM %d ", speed_percent);
    if (len < 0 || (unsigned int)len >= (buffer_size - used))
    {
        return -3;
    }
    used += (unsigned int)len;

    /* 起始步 */
    len = snprintf(buffer + used, buffer_size - used, "IX %u ", start_index);
    if (len < 0 || (unsigned int)len >= (buffer_size - used))
    {
        return -4;
    }
    used += (unsigned int)len;

    /* 是否单次执行 */
    if (use_once)
    {
        len = snprintf(buffer + used, buffer_size - used, "ONCE ");
        if (len < 0 || (unsigned int)len >= (buffer_size - used))
        {
            return -5;
        }
        used += (unsigned int)len;
    }

    len = snprintf(buffer + used, buffer_size - used, "\r\n");
    if (len < 0 || (unsigned int)len >= (buffer_size - used))
    {
        return -6;
    }

    return 0;
}

/*===========================================================
 * 四、动作执行接口
 *==========================================================*/

/* 执行单步动作:多个舵机同步到位 */
int AG_RunStep(const ServoCmd cmds[], unsigned char num, unsigned int time)
{
    char tx_buffer[AG_TX_BUFFER_SIZE];
    int ret;

    ret = AG_BuildStepCommand(cmds, num, time, tx_buffer, sizeof(tx_buffer));
    if (ret != 0)
    {
        return ret;
    }

    AG_SendString(tx_buffer);
    return 0;
}

/* 逐步执行完整动作组 */
int AG_RunActionGroup(const ActionGroup *group)
{
    unsigned char i;
    int ret;

    if (group == NULL || group->steps == NULL || group->step_num == 0)
    {
        return -1;
    }

    for (i = 0; i < group->step_num; i++)
    {
        ret = AG_RunStep(group->steps[i].cmds,
                         group->steps[i].num,
                         group->steps[i].time);
        if (ret != 0)
        {
            return ret;
        }

        /*
         * 注意:
         * 这里通常不需要本地 delay_ms(time);
         * 因为控制器收到 Txxx 后会在指定时间内完成动作。
         * 如果你的上位控制逻辑需要等待再发下一步,可在外层加延时。
         */
    }

    return 0;
}

/* 通过控制器内置动作组编号直接调用 */
int AG_RunGroupBySeq(unsigned char seq,
                     int speed_percent,
                     unsigned char start_index,
                     unsigned char use_once)
{
    char tx_buffer[AG_TX_BUFFER_SIZE];
    int ret;

    ret = AG_BuildGroupCommand(seq,
                               speed_percent,
                               start_index,
                               use_once,
                               tx_buffer,
                               sizeof(tx_buffer));
    if (ret != 0)
    {
        return ret;
    }

    AG_SendString(tx_buffer);
    return 0;
}

/*===========================================================
 * 五、示例动作组定义
 *==========================================================*/

/*
 * 示例1:双舵机同步动作
 * 对应协议:
 *   #5 P1600 #10 P750 T2500\r\n
 */
static const ServoCmd g_action_wave_step1_cmds[] =
{
    {5, 1600},
    {10, 750}
};

static const ActionStep g_action_wave_steps[] =
{
    {g_action_wave_step1_cmds, 2, 2500}
};

static const ActionGroup g_action_wave =
{
    g_action_wave_steps,
    1,
    "wave_demo"
};

/*
 * 示例2:多步动作组
 * 第一步:回中
 * 第二步:展开
 */
static const ServoCmd g_action_demo_step1_cmds[] =
{
    {0, 1500},
    {1, 1500},
    {2, 1500}
};

static const ServoCmd g_action_demo_step2_cmds[] =
{
    {0, 1800},
    {1, 1200},
    {2, 1700}
};

static const ActionStep g_action_demo_steps[] =
{
    {g_action_demo_step1_cmds, 3, 1000},
    {g_action_demo_step2_cmds, 3, 1500}
};

static const ActionGroup g_action_demo =
{
    g_action_demo_steps,
    2,
    "multi_step_demo"
};

/* 动作组表:支持按编号调用 */
static const ActionGroup *g_action_table[] =
{
    &g_action_wave, /* 0 */
    &g_action_demo  /* 1 */
};

#define AG_ACTION_TABLE_SIZE  (sizeof(g_action_table) / sizeof(g_action_table[0]))

/*===========================================================
 * 六、按编号调用本地动作组
 *==========================================================*/

int AG_RunLocalActionById(unsigned char id)
{
    if (id >= AG_ACTION_TABLE_SIZE)
    {
        return -1;
    }

    return AG_RunActionGroup(g_action_table[id]);
}

/*===========================================================
 * 七、可选的调试辅助接口
 *==========================================================*/

/* 发送单舵机控制命令 */
int AG_SetSingleServo(unsigned char id, unsigned int pwm, unsigned int time)
{
    ServoCmd cmd;
    cmd.id  = id;
    cmd.pwm = pwm;
    return AG_RunStep(&cmd, 1, time);
}

/* 停止控制器动作场景 */
void AG_StopGroupScene(void)
{
    AG_SendString("PL 0\r\n");
}

/* 暂停控制器动作场景 */
void AG_PauseGroupScene(void)
{
    AG_SendString("PL 0 SM 0\r\n");
}

/*===========================================================
 * 八、示例主调函数(按需放到 main.c 中)
 *==========================================================*/
/*
void ActionGroup_Test(void)
{
    // 1) 直接执行本地封装的单步动作组
    AG_RunLocalActionById(0);
    // 实际发送:#5 P1600 #10 P750 T2500\r\n

    // 2) 执行本地多步动作组
    AG_RunLocalActionById(1);

    // 3) 直接控制单个舵机
    AG_SetSingleServo(1, 1500, 500);

    // 4) 调用控制器内部编号动作组
    //    PL 0 SQ 5 SM 100 IX 0 ONCE\r\n
    AG_RunGroupBySeq(5, 100, 0, 1);

    // 5) 暂停/停止动作组场景
    AG_PauseGroupScene();
    AG_StopGroupScene();
}
*/

舵机平滑运动控制模块设计

提示词:

请帮我写一个舵机平滑运动函数,
要求:
1)输入目标角度
2)每次递增1度
3)带延时控制
4)避免舵机抖动
void servo_move_smooth(int *angle, int target)
{
    if(*angle < target)
    {
        (*angle)++;
    }
    else if(*angle > target)
    {
        (*angle)--;
    }
    
    delay_ms(10);
}

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐