1. 项目概述这不是在写代码而是在给机械手“装大脑”“Building Custom OpenClaw Skills: A Hands-On Tutorial”——这个标题乍看像极了某篇开源硬件文档的副标题但真正上手做过OpenClaw项目的人都知道它背后藏着的不是一行行Python脚本而是一整套物理世界与数字指令之间的神经映射系统。我第一次把OpenClaw夹爪接上树莓派、运行起官方demo时它能稳稳夹起一颗葡萄可当我试着让它“先旋转30度再轻捏释放”结果是葡萄被拧成两半、电机过热报警、串口日志里刷出一连串ERROR: torque limit exceeded。那一刻我才意识到OpenClaw本身不是技能平台它是一块裸露的“运动皮层”而所谓“Custom Skills”本质是为这层皮层编写可复用、可组合、可容错的运动语义单元。核心关键词“OpenClaw”、“Custom Skills”、“Hands-On Tutorial”已经划出了三条硬边界第一对象是OpenClaw这一特定开源夹爪硬件非Generic Robotic Arm非UR5非DJI RoboMaster第二目标不是调通基础通信而是构建具备行为逻辑的技能模块Skill ≠ ScriptSkill State Transition Guard Recovery第三“Hands-On”意味着所有内容必须经得起螺丝刀、万用表和实时串口日志的检验——不能只讲ROS节点图得告诉你/dev/ttyACM0权限怎么加才不重启生效不能只贴rosrun openclaw_skill_server start.py得说明为什么start.py里第47行要强制sleep(0.3)否则夹爪会抖动。适合谁来读如果你正卡在“能动但不会思考”的阶段——比如你已成功让OpenClaw响应串口指令完成开合但面对“识别到红色方块后以0.8N力矩抓取并平移至坐标(0.12, -0.05, 0.08)”这类需求时还在手动拼接set_position()、set_torque()、wait_for_stop()三段式代码那这篇就是为你写的。它不假设你懂ROS Action Server但要求你分得清GPIO引脚和UART TX/RX它不回避PID调参但会用“拧水龙头”类比解释为什么位置模式下Kp设太高会让夹爪像抽筋一样震颤。我做这个项目的真实动因是帮本地一所职校的智能制造实训室搭建教学案例。他们原有的一套OpenClaw演示台学生只能按按钮执行预设动作无法理解“技能”如何被拆解、编排、调试。于是我们花了6周时间从零构建了一套可嵌入教学流程的Custom Skills框架包含基础运动技能Grip、Release、Rotate、感知耦合技能ColorPick、SizeAlign、以及复合任务技能SortByColor、StackThree。所有技能都通过YAML配置驱动学生改几个参数就能生成新行为而不用碰C底层驱动。这篇教程就是把这6周踩过的坑、调过的参数、验证过的结构原原本本摊开给你看。2. 整体设计思路为什么放弃ROS Action选择状态机事件总线架构2.1 技能的本质不是“执行”而是“可观测的意图表达”很多初学者一上来就想用ROS Action Server封装OpenClaw技能理由很充分Action有goal、feedback、result三段式接口天然匹配“我要夹东西→正在夹→夹完了”的流程。但我在实测中发现三个致命问题第一Action Server的抽象层级过高。OpenClaw的底层控制周期是2ms500Hz而ROS默认的Action feedback发布频率是10Hz。这意味着当你在execute_cb里写while not self.reached_target:实际循环中每100次底层位置更新你只收到1次feedback。更糟的是OpenClaw的电机编码器分辨率仅12位4096脉冲/圈在微小位移场景比如夹取0.5mm厚的PCB板1个脉冲就代表0.022°而ROS的float32精度在该量级下开始丢失有效数字——你看到的current_position: 0.123456真实值可能是0.123401或0.123512。这种精度断层导致基于feedback判断“是否到位”的逻辑频繁误判。第二Action Server缺乏细粒度错误隔离能力。当一个技能包含“移动到A点→旋转夹爪→施加扭矩→等待稳定→确认夹持”5个子步骤时Action Server把它们全塞进一个execute_cb函数。一旦第3步扭矩超限触发保护整个Action直接abort你无法知道是电机堵转还是供电不足更无法让系统自动执行“降扭矩重试→切换为位置模式→记录异常日志”这样的分级恢复策略。第三教学场景需要“可打断、可单步、可回放”的技能执行过程。职校学生调试时经常需要“暂停在旋转夹爪后手动微调角度再继续”。Action Server没有pause/resume接口强行实现会破坏其状态机契约。所以最终我们彻底弃用Action Server转向轻量级状态机State Machine 事件总线Event Bus架构。这不是为了炫技而是由OpenClaw的物理特性倒逼出来的选择。2.2 状态机设计每个技能都是独立的状态图而非函数调用链我们定义了一个最小可行技能单元Minimal Skill Unit, MSUState技能当前所处的明确状态如IDLE、MOVING_TO_TARGET、APPLYING_TORQUE、VERIFYING_GRIP、RECOVERINGTransition触发状态迁移的条件分为两类•Internal Transition由技能自身逻辑触发如APPLYING_TORQUE → VERIFYING_GRIP当torque_sensor threshold * 0.95持续50ms•External Transition由外部事件触发如收到emergency_stop事件时任何状态都必须立即跳转到EMERGENCY_HOLDGuard状态迁移前的守卫条件防止非法跳转。例如从IDLE到MOVING_TO_TARGETGuard必须检查motor_power_enabled True and battery_voltage 11.2VRecovery进入RECOVERING状态后的固定动作序列如disable_motor → log_error → beep_3times → wait_2s → reinitialize_encoder这种设计带来的直接好处是技能行为完全可观测、可预测、可审计。我们在每个状态入口插入日志打印格式为[SKILL:Grip][STATE:APPLYING_TORQUE][TS:1723456789.123] torque_set0.85N·m, encoder_diff12.4deg。学生调试时只需看日志流就能准确定位问题发生在哪个状态、持续多久、触发了什么条件——这比ROS的rqt_console里翻找混合日志高效十倍。2.3 事件总线解耦技能与硬件驱动让“教技能”变成“配参数”状态机解决了技能内部逻辑但技能如何与OpenClaw硬件交互我们没选择直接调用openclaw_driver.set_torque()而是引入一层事件总线Event Bus。所有硬件操作都转化为事件发布MotorEnableEvent(motor_id1, enableTrue)PositionSetEvent(motor_id1, target_pos1250, max_speed800)TorqueSetEvent(motor_id1, target_torque0.85)SensorReadRequest(sensor_typeencoder, motor_id1)驱动层订阅这些事件并转换为具体的串口指令如$POS,1,1250,800#。关键在于技能代码永远不持有硬件句柄只负责发事件。这带来两个教学级优势可模拟调试在没接OpenClaw实物时学生可启动一个MockDriver它订阅相同事件但只打印日志不发串口。这样“写技能”和“调硬件”可以并行极大缩短实训课时。参数即技能一个ColorPick技能的全部行为由YAML文件定义name: red_block_picker states: IDLE: on_enter: [log(Ready to pick red block)] MOVING_TO_DETECTION_ZONE: transition_on: sensor_event.color red actions: [publish(PositionSetEvent(motor_id2, target_pos3200))] APPLYING_TORQUE: guard: battery_voltage 11.0 actions: [publish(TorqueSetEvent(motor_id1, target_torque0.72))] transition_on: torque_sensor 0.68学生改target_torque值就是在调整技能而不是改C源码。我们统计过职校学生修改YAML参数的平均耗时是2.3分钟而修改C代码并重新编译部署平均耗时11.7分钟——这对45分钟一节课的教学节奏是决定性的。提示事件总线必须是同步阻塞的。我们曾尝试用asyncio.Queue做异步事件分发结果在高频率位置控制200Hz下事件处理延迟抖动达±15ms导致夹爪运动出现肉眼可见的“卡顿感”。最终回归threading.Event queue.Queue用生产者-消费者模型保证事件处理确定性。3. 核心细节解析从串口协议到力控阈值每一个参数都有物理意义3.1 OpenClaw串口协议的“隐藏规则”必须手撕文档OpenClaw官方文档里写着“支持ASCII指令集”但没告诉你这些指令背后藏着三重时序陷阱。我用Saleae逻辑分析仪抓了整整两天串口波形才理清真实约束指令帧头校验所有指令必须以$开头#结尾但$和第一个字符之间不能有任何空格或延时。实测发现如果树莓派Python脚本里写ser.write(b$POS,1,1250,800#\n)\n会导致OpenClaw固件解析失败——因为固件只认#不认换行符。正确写法是ser.write(b$POS,1,1250,800#)且发送后必须time.sleep(0.002)等待固件处理。多指令流水线冲突OpenClaw固件采用单线程解析当连续发送$POS,1,1250,800#和$TOR,1,0.85#时若间隔5ms第二条指令会被丢弃。解决方案不是加长sleep而是用指令队列ACK确认机制每发一条指令必须等待OpenClaw返回$ACK,1#1为指令ID才发下一条。我们在驱动层实现了带超时的ACK等待超时则重发重试3次失败则报COMM_TIMEOUT。编码器数据的“伪实时”真相$ENC,1#指令返回格式为$ENC,1,3245,12.34#其中3245是原始计数值12.34是角度度。但实测发现当夹爪高速运动时12.34这个值其实是上一次$ENC请求时的快照而非当前时刻。真实延迟约8~12ms。因此在VERIFYING_GRIP状态里我们绝不依赖单次$ENC读数判断是否到位而是采样连续5次间隔10ms计算角度变化率当变化率0.1°/s持续300ms才认定“已稳定”。注意OpenClaw的串口默认波特率是115200但实测在树莓派4B上当CPU负载70%时会出现字节丢失。我们最终将波特率降至57600并在/boot/config.txt中添加init_uart_baud57600固化设置同时禁用蓝牙串口dtoverlaydisable-bt确保UART资源独占。3.2 力控不是“设个值”而是建立“力-位移-时间”三维安全域OpenClaw支持两种控制模式位置模式$POS和扭矩模式$TOR。新手常犯的错误是以为“夹东西就用扭矩模式设个0.8N·m就行”。但物理世界远比这复杂。我们做了组对照实验用同一块0.5mm厚的FR4 PCB板分别在以下条件下测试夹持成功率100次控制模式目标扭矩(N·m)夹持速度(mm/s)成功率典型失效现象扭矩模式0.81542%PCB边缘压溃、铜箔翘起扭矩模式0.51578%偶尔滑脱位置扭矩混合0.5限幅1599%无损伤关键突破在于不单独使用扭矩模式而是在位置模式下启用扭矩限幅Torque Limit。OpenClaw固件支持$LIM,1,0.5#指令设置电机1的扭矩上限。这样当夹爪以位置模式逼近目标时一旦接触物体电机电流上升导致扭矩接近0.5N·m固件自动降低输出电压使夹爪“软停止”既保证夹持力又避免硬碰撞。但这就引出新问题0.5N·m这个值怎么定我们推导出一个经验公式T_max (F_desired × r_eff) / η其中F_desired是期望夹持力N对PCB板取3.5N足够防滑小于FR4抗弯强度r_eff是夹爪等效力臂mOpenClaw手册标注为0.028m从电机轴心到指尖接触点的垂直距离η是传动效率实测为0.72因谐波减速器损耗代入得T_max (3.5 × 0.028) / 0.72 ≈ 0.136 N·m。但实测发现0.136太小夹不住。原因在于公式中的F_desired是静态理论值而实际夹持需克服材料弹性变形。我们通过压力传感器实测夹爪指尖压强分布发现当目标物体厚度1mm时需将T_max提高至理论值的5.8倍因接触面积极小局部应力集中。最终对薄板类物体T_max设为0.78N·m对直径20mm的塑料圆柱则设为0.42N·m。实操心得永远用“力-位移曲线”校准扭矩值。方法固定OpenClaw用千分表顶住指尖缓慢增加$TOR值记录千分表位移量。当位移从线性变为非线性拐点时对应的扭矩值即为该物体的“临界夹持扭矩”。我们为常用教学物料PCB、乐高砖、亚克力片、橡胶球都建立了这样的校准表存在/etc/openclaw/calibration/下技能加载时自动读取。3.3 “Custom Skill”的最小可运行单元一个可验证的Grip技能现在我们把前述所有细节组装成一个真正可用的Grip技能。它不是demo而是经过2000次循环测试的工业级模块class GripSkill(StateMachine): def __init__(self, config_path): super().__init__() self.config yaml.safe_load(open(config_path)) # 加载校准参数不同物料对应不同扭矩和速度 self.calib CalibrationLoader.load(self.config[material]) def on_enter_IDLE(self): self.publish(LogEvent(fStarting Grip for {self.config[material]})) self.publish(MotorEnableEvent(motor_id1, enableTrue)) def on_enter_MOVING_TO_GRIP_POS(self): # 使用位置模式快速到达预夹位置避免空载扭矩消耗 target_pos self.calib[pre_grip_pos] self.publish(PositionSetEvent( motor_id1, target_postarget_pos, max_speedself.calib[approach_speed] )) # Guard确保到达后停留200ms消除机械振动 self.wait_for_condition( lambda: abs(self.encoder_pos - target_pos) 5, timeout2.0, on_timeoutlambda: self.transition_to(RECOVERING) ) def on_enter_APPLYING_TORQUE(self): # 切换为扭矩限幅模式施加目标扭矩 self.publish(TorqueLimitEvent(motor_id1, limitself.calib[torque_limit])) self.publish(TorqueSetEvent(motor_id1, target_torqueself.calib[torque_limit])) # 关键不是等“扭矩达到”而是等“扭矩稳定位移停止” start_time time.time() while time.time() - start_time 1.5: if (self.torque_sensor self.calib[torque_limit] * 0.9 and self.torque_sensor self.calib[torque_limit] * 1.05 and abs(self.encoder_delta_last_50ms) 0.3): self.transition_to(VERIFYING_GRIP) return time.sleep(0.01) self.transition_to(RECOVERING) def on_enter_VERIFYING_GRIP(self): # 连续采样10次确认夹持稳定性 stable_count 0 for _ in range(10): if (abs(self.torque_sensor - self.calib[torque_limit]) 0.05 and abs(self.encoder_delta) 0.1): stable_count 1 time.sleep(0.05) if stable_count 8: self.publish(SkillSuccessEvent(skill_nameGrip)) self.transition_to(IDLE) else: self.transition_to(RECOVERING)这个GripSkill类有三个设计精妙之处状态内聚性每个on_enter_*方法只做一件事且包含完整的错误处理闭环。比如on_enter_APPLYING_TORQUE里while循环自带超时超时即跳转RECOVERING不依赖外部中断。物理参数绑定所有魔法数字如0.9、0.05、1.5都来自self.calib而calib由YAML加载与物料强关联。学生换一种物料只需改YAML不用动Python。可观测性埋点每个状态入口都发LogEvent且关键判断条件如torque_sensor limit * 0.9在日志中显式打印方便学生理解“为什么这里要设0.9而不是0.95”。我们把这个技能编译成grip_skill.so用Cython加速关键循环学生在终端输入openclaw-skill run grip --material pcb即可执行。全程无需打开IDE符合职校实训“所见即所得”的教学原则。4. 实操全流程从树莓派烧录到技能部署一步一坑的现场记录4.1 硬件准备与树莓派系统固化别让环境问题毁掉第一课OpenClaw对运行环境极其敏感。我们曾遇到最诡异的问题同一份技能代码在A树莓派上100%成功在B树莓派上70%失败日志显示encoder_delta异常跳变。用示波器查了三天最终发现B树莓派的USB-C电源适配器接地不良导致UART信号参考电平漂移编码器计数值在3245和3246间随机抖动。因此硬件准备必须标准化树莓派型号严格限定为Raspberry Pi 4B4GB RAM禁用Pi 5USB控制器驱动不成熟和Pi ZeroUSB带宽不足。电源必须使用官方27W USB-C电源RPi官方认证型号RPi-PSU-27W禁用手机充电器。我们采购了20个同批次电源统一编号管理。SD卡Class 10 UHS-I容量≥32GB品牌限定为SanDisk Extreme Pro。普通TF卡在频繁日志写入下3天内必坏。串口连接OpenClaw通过micro-USB直连树莓派USB口不使用USB-HUB。树莓派侧USB口编号固定为/dev/ttyACM0通过udev规则固化# /etc/udev/rules.d/99-openclaw.rules SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, SYMLINKopenclaw这样无论插哪个USB口设备名永远是/dev/openclaw避免学生因插错口导致Device not found错误。系统烧录步骤学生可照着做下载Raspberry Pi OS Lite2023-10-10版本用Raspberry Pi Imager烧录烧录后在SD卡boot分区创建空文件ssh启用SSH创建wpa_supplicant.conf配置WiFi教学网SSID/PWD由实训室统一分发关键一步在config.txt末尾添加# OpenClaw专用优化 init_uart_baud57600 dtoverlaydisable-bt core_freq500 gpu_mem16其中core_freq500锁定CPU核心频率避免动态调频导致串口时序抖动gpu_mem16最小化GPU内存占用为UART留足DMA缓冲区。首次启动后执行sudo usermod -a -G dialout $USER # 加入串口用户组 sudo systemctl disable hciuart # 彻底禁用蓝牙串口 sudo reboot踩过的坑有学生用Balena Etcher烧录系统结果Etcher默认启用“验证写入”选项导致烧录速度极慢45分钟且验证阶段易因SD卡质量差失败。我们强制要求用Raspberry Pi Imager并在实训室电脑上预装好禁止学生自行下载工具。4.2 驱动层编译与校准让OpenClaw“听懂人话”OpenClaw官方提供的是Arduino固件源码但树莓派需要的是Linux驱动。我们基于libusb-1.0开发了轻量驱动openclaw_usb它不依赖ROS纯C编写编译后仅124KB。编译步骤学生终端逐行输入# 1. 安装依赖 sudo apt update sudo apt install -y build-essential libusb-1.0-0-dev # 2. 获取驱动源码已镜像到校内GitLab git clone https://gitlab.intra/openclaw/openclaw_usb.git cd openclaw_usb # 3. 编译关键必须指定架构Pi4是armv7l make ARCHarmv7l # 4. 安装到系统路径 sudo make install # 5. 加载内核模块此步常被忽略 sudo modprobe usbserial vendor0x1a86 product0x7523驱动安装后必须进行三阶校准这是学生最容易跳过的环节却直接决定技能成功率第一阶零点校准Zero Point Calibration断电状态下手动将夹爪完全张开至机械限位然后上电。运行sudo openclaw_calibrate zero驱动会读取此时编码器值作为pos_min。此值存于/etc/openclaw/hardware.conf后续所有位置指令都以此为基准。第二阶行程校准Stroke Calibration用游标卡尺测量夹爪完全闭合时指尖间距记为stroke_mm。运行sudo openclaw_calibrate stroke --mm 12.5驱动据此计算pos_max并验证pos_max - pos_min是否与编码器理论行程一致4096脉冲。第三阶力-位移校准Force-Displacement Calibration此步需压力传感器。将OpenClaw固定传感器顶住指尖运行sudo openclaw_calibrate force --sensor-path /dev/ttyUSB0驱动自动执行0.1N→1.0N阶梯加压记录每步对应的编码器位移生成/etc/openclaw/force_curve.csv。这个CSV文件就是前文CalibrationLoader加载的依据。实操心得校准必须在25±2℃环境下进行。我们发现温度每升高10℃编码器零点漂移达3个脉冲0.066°。实训室空调必须恒温且校准前OpenClaw需静置30分钟与室温平衡。4.3 技能开发环境搭建VS Code远程开发让学生专注逻辑而非环境为避免学生在“配环境”上浪费课时我们构建了VS Code Remote-SSH开发环境树莓派上预装code-serverVS Code服务端通过https://pi4.local:8443访问学生用浏览器打开无需安装任何软件工作区预配置好tasks.json一键编译技能CtrlShiftB预装openclaw-skill-debug插件点击“Run Skill”按钮自动启动openclaw_usb驱动加载指定YAML配置启动技能状态机在右侧面板实时显示状态迁移日志和传感器数据流。学生开发ColorPick技能时典型工作流是在/home/pi/skills/color_pick.yaml中修改target_color: blue在VS Code中按F5启动调试观察右侧面板日志[STATE:MOVING_TO_DETECTION_ZONE] - [STATE:APPLYING_TORQUE] - [STATE:VERIFYING_GRIP]若失败日志中会精确显示[ERROR] torque_sensor unstable at 0.42N·m (expected 0.75)学生立刻知道是蓝色物体反光导致颜色识别误判而非技能逻辑错误。这套环境使学生从“写代码”回归到“设计行为”把注意力集中在“如何让夹爪理解蓝色”上而不是“为什么import rospy报错”。4.4 首个Custom Skill实战5分钟教会学生写自己的“叠积木”技能现在我们带学生完成第一个真正意义上的Custom SkillStackThree——让OpenClaw抓取三个相同积木按顺序堆叠成塔。Step 1分析物理约束积木尺寸48×48×24mm标准乐高尺寸OpenClaw夹持宽度范围12~65mm → 可夹单个积木但无法同时夹两个堆叠高度限制OpenClaw Z轴行程仅80mm三层积木总高72mm余量8mm用于微调Step 2拆解为原子技能StackThree不是新技能而是Grip、MoveTo、Release三个已有技能的编排Grip夹取积木物料类型lego_redMoveTo移动到目标坐标需预设三个坐标点Release松开夹爪扭矩设为0位置模式回退50脉冲Step 3编写YAML编排文件# /home/pi/skills/stack_three.yaml name: stack_three description: Stack three LEGO bricks in pyramid sequence: - skill: Grip params: {material: lego_red} timeout: 5.0 - skill: MoveTo params: {target: base_plate, z_offset: 0.0} timeout: 8.0 - skill: Release params: {} timeout: 2.0 - skill: Grip params: {material: lego_red} timeout: 5.0 - skill: MoveTo params: {target: first_brick, z_offset: 0.024} # 第二层Z24mm timeout: 8.0 - skill: Release params: {} timeout: 2.0 # ... 第三层同理Step 4执行与验证学生在终端输入openclaw-skill run stack_three --debug--debug参数会启用详细日志并在每步技能执行前暂停等待学生按Enter继续。这样学生能亲眼看到夹爪如何一步步完成堆叠理解“技能编排”与“物理执行”的对应关系。我们统计过学生首次独立完成StackThree的平均耗时是4分38秒含阅读文档最快纪录是2分15秒。而如果让他们从零写C控制代码平均耗时是3小时27分钟且成功率不足30%。5. 常见问题与排查技巧那些让你熬夜到凌晨三点的“幽灵Bug”5.1 串口通信时好时坏90%的问题出在电源和接地现象OpenClaw偶尔失联dmesg | grep tty显示usb 1-1.2: usbfs: process 1234 (python3) did not claim interface 0 before use但ls /dev/openclaw始终存在。排查路径首先排除软件拔掉OpenClaw运行sudo openclaw_test --loopback环回测试若失败则是树莓派USB问题若环回正常插上OpenClaw用万用表测/dev/openclaw的GND与树莓派外壳是否等电位应0.1V若电位差0.5V说明接地不良——这是最常见原因。解决方案• 用一根AWG22导线一端焊在OpenClaw电路板GND焊盘另一端接到树莓派GPIO Pin 6GND• 或更换为带金属屏蔽层的USB线并确保屏蔽层两端可靠接地。根本原因OpenClaw的USB转串口芯片CH340对参考地电平极其敏感。当树莓派和OpenClaw由不同电源供电时地电位差形成共模噪声导致UART信号误判。我们曾用示波器测到地电位差达1.2V直接淹没3.3V逻辑电平。5.2 夹爪“抽搐”不是代码bug是PID参数与机械共振的共舞现象在位置模式下夹爪接近目标时高频微震约15Hz伴随电机嗡鸣编码器读数在目标值±3脉冲间跳变。排查路径先确认是否为机械问题手动转动夹爪听是否有异响检查谐波减速器润滑脂是否干涸若机械正常则是PID震荡。OpenClaw固件的PID参数存储在EEPROM中可通过$PID,1,Kp,Ki,Kd#指令修改。但新手常误设Kp100导致系统响应过快激发机械结构固有频率。解决方案采用“Ziegler-Nichols临界比例度法”现场整定将Ki0, Kd0逐步增大Kp直到夹爪出现等幅振荡记录此时Kp_critical42振荡周期T_critical0.15s按公式计算Kp 0.6 * Kp_critical 25.2,Ki 1.2 * Kp_critical / T_critical 336,Kd 0.075 * Kp_critical * T_critical 0.47写入固件$PID,1,25.2,336,0.47#。注意Ki值很大336是因为OpenClaw电机惯量小积分作用需强才能消除静差。但Ki过大又会导致超调所以必须配合Kd抑制。我们给学生配了速查表对乐高积木推荐Kp22~28对亚克力片Kp18~22因摩擦系数不同。5.