
2026 年电赛 E 题公布之后“五自由度”“soarm101”“拼图装置”这几个词几乎同时进入赛前准备的高频搜索列表。很多队伍拿到题的第一反应是机械臂没玩过视觉没系统做过怎么拼图另一部分队伍则相反觉得买台现成机械臂就能交差。这两种心态都会在赛场上付出代价。E 题拼图装置真正考察的不是“会不会接一条串口线”而是你把视觉、运动学、抓取策略串成一条可靠流水线的能力。本文把第一二三问的完整思路、系统架构、关键代码和踩坑记录整理出来希望能帮下一届少走弯路。这套方案的技术栈并不玄乎OpenCV 做目标识别透视变换做像素坐标到物理坐标的转换几何法求解五自由度机械臂逆运动学再用状态机把动作串起来。项目完全开源文中所有代码都是可运行的“思路级”框架参数需要根据自己的机械臂和赛题要求替换。读完之后你应该能独立搭出一个从“看到拼图块”到“放好拼图块”的完整闭环。1. 这道题真正的难点系统集成先说一个可能反直觉的判断E 题拼图装置难的不是机械臂也不是视觉而是系统集成。如果你只做机械臂控制让机械臂按固定轨迹走这是很成熟的事。如果你只做视觉识别用 OpenCV 找拼图块的中心点这也是很成熟的事。但电赛给的是完整任务机械臂要先找到拼图块再算出怎么抓再移动到目标点再放下然后保证拼出来的图案正确。这一步和下一步之间是互相影响的。误差会沿着链路逐级累积。视觉标定差 2 毫米运动学模型差 1 毫米舵机重复定位差 2 毫米夹爪或者吸盘再偏 1 毫米最后到拼图位置上的误差可能就是 6 到 8 毫米。拼图块的间距通常很小累积误差超过半个块宽就可能导致图案错位。所以这道题表面上是编程题实际上是一道“误差预算”题你要在每一个环节都把误差压到可接受范围而不是指望最后统一补偿。还有一个常见的误区是“照搬工业机械臂方案”。工业六轴机械臂有成熟的运动学库、高精度伺服闭环、视觉标定工具但五自由度 SOARM101 这类竞赛平台没有这些条件。它的舵机精度有限结构刚度有限通信协议也简单得多。这意味着你需要自己做很多“工程补偿”比如在逆解之后加平滑滤波在抓取前加到位确认在放置后加视觉校验。这些工作之前被很多人忽略却恰恰是决定第一二三问能不能稳定拿分的关键。从备赛角度说建议把精力按这个比例分配视觉标定占三成运动学与轨迹规划占三成机械结构调试占两成任务调度与容错占两成。不要把所有时间都花在训练识别模型上因为这道题里 OpenCV 的传统方法已经足够好。2. SOARM101 与五自由度机械臂的基础认知2.1 什么是 SOARM101SOARM101 是竞赛和教学场景里常见的一款五自由度串联机械臂。它由底座旋转关节、肩关节、肘关节、腕部关节和末端旋转关节组成整体结构类似缩小版的工业关节臂。驱动方式一般是舵机控制板通过串口接收关节角度指令驱动各个舵机运动。这款平台的优点是很适合入门结构紧凑、价格可控、有现成的上位机控制接口。短板也很明显舵机的重复定位精度通常不如伺服电机负载能力有限高速运动时容易抖动。备赛时一定要先摸清自己这台机械臂的“脾气”不同批次、不同舵机的机械臂运动学参数都可能略有差异。2.2 为什么五自由度够用很多队伍会问为什么不直接用六自由度机械臂这里要理解自由度与任务需求的关系。对比项五自由度 SOARM101常见六自由度工业臂旋转轴数量5 个6 个末端姿态能力主要保证位置 绕 Z 轴朝向可任意指定末端三维姿态逆运动学求解几何法即可解算快解析法或数值法可能有多组解控制复杂度较低适合竞赛快速开发较高需要完整位姿描述平面拼图任务完全够用属于能力冗余典型场景抓取、搬运、拼图、码垛曲面加工、空间装配拼图任务本质上是一个“平面操作”任务拼图块平放在底板上机械臂末端需要到达某个 X、Y、Z 位置让末端执行器对准拼图块然后吸起或夹起再移到目标位置放下。整个过程里末端执行器的姿态变化基本集中在绕 Z 轴旋转不需要像焊接、打磨那样调整复杂空间姿态。所以五自由度的构型是够用的把第五关节和第四关节配合好就能控制末端绕 Z 轴的朝向。2.3 必须理解的三个坐标系做机械臂控制坐标系是绕不开的概念。初学者最容易在这个地方栽跟头。基座坐标系固定在机械臂底座原点在底座中心或第一个关节轴线上是运动学计算的基准。关节坐标系每个关节有自己的坐标系描述相邻连杆之间的相对关系。工具坐标系固定在末端执行器吸盘或夹爪上表示“手”到底在哪里。视觉识别得到的是拼图块在图像中的像素坐标通过标定可以转换到基座坐标系下的物理坐标然后运动学解算得到关节角。这三步里任何一步坐标系搞混机械臂就会抓偏。建议在代码里用统一的变量命名比如pixel_*、world_*、joint_*避免后面调试时逻辑混乱。3. 赛题第一二三问拆解与总体策略3.1 第一问基础动作控制第一问通常是让机械臂完成一些基础动作比如从初始位置运动到指定坐标或者按顺序到达若干个目标点。这一问本质是考察运动学基本功和通信控制能力。技术栈不算复杂解析目标坐标调用逆运动学求关节角通过串口下发指令等待机械臂到位。但失分点往往在于“运动不平稳”和“到位慢”。如果机械臂在运动过程中出现明显抖动裁判或自动判分系统可能会判定动作不合格。建议第一问就做好两件事一是实现关节角度的平滑插值不要直接跳变到目标角度二是加入到位判断也就是收到机械臂“运动完成”的反馈或者通过角度传感器确认到达再进入下一动作。3.2 第二问目标识别与定点抓放第二问升级为“识别 抓取”机械臂需要识别视野中的拼图块抓起来放到指定区域。这一问的核心是坐标标定的精度。识别拼图块并不难难的是把图像坐标准确映射到机械臂坐标系。常见方案是顶置相机加四点标定在机械臂工作区域放四个已知物理坐标的标记点用透视变换求出像素坐标与物理坐标的转换矩阵。很多队伍在这一问失分是因为只做了“识别”没有做“定位校验”。识别到拼图块中心后没有先让机械臂移动到拼图块上方确认一次就直接下降抓取。如果标定矩阵稍有偏差抓取自然失败。更好的做法是先做一次“预到点”机械臂移动到识别位置上方 2 到 3 厘米处用近距离视觉或人工确认偏移再做精确抓取。3.3 第三问完整拼图任务第三问是整合题机械臂需要根据给定的图案从一堆拼图块中选出正确的块依次放到指定位置最终拼出目标图案。这一问真正考验的是任务调度和容错。拼图块可能有多种颜色或图案识别模块不仅要知道“这里有一块拼图”还要知道“这块是什么图案/颜色”以及“它该放到哪里”。如果任务中途某一块放偏了后续所有块的位置都会受影响因此要考虑“放置后校验”逻辑。问数典型任务核心技术点常见失分点第一问基础动作与定点运动运动学、轨迹规划、串口通信运动抖动、到位慢第二问识别目标并抓取至指定位置视觉识别、坐标标定标定误差导致抓偏第三问按图案完成拼图任务调度、多目标管理、容错单块放错导致连锁失败总体策略建议是“先跑通第二问再做第三问”。第三问的大部分能力在第二问里都要用到先把单个抓放循环做得稳定再考虑任务调度。4. 系统架构与通信控制4.1 整体链路这套系统的硬件和软件链路可以分成两条硬件链路上位机笔记本或树莓派→ USB 转串口 → 机械臂主控板 → 舵机。软件链路OpenCV 视觉采集 → 识别拼图块 → 坐标转换 → 逆运动学解算 → 关节角 → 串口协议打包 → 主控板执行。这里要特别注意视觉模块和运动控制模块最好解耦。不要把图像处理和机械臂控制写在一个大循环里否则一旦视觉处理耗时波动机械臂的控制节拍也会跟着乱。建议开两个线程一个负责视觉识别一个负责运动控制中间通过队列传递目标坐标。4.2 环境准备开发环境建议使用 Python 3.x依赖库尽量精简pip install opencv-python opencv-contrib-python numpy pyserial如果不需要 ArUco 识别可以只装opencv-python。装opencv-contrib-python是为了使用cv2.aruco模块。有些版本的新版 OpenCV 把 ArUco 移到了cv2.aruco之外如果import cv2.aruco报错说明需要换用带 contrib 的版本。串口通信是另一个容易踩坑的地方。机械臂主控板用的波特率、数据位、停止位必须和上位机配置一致。开发时先用串口助手测试一下避免代码写完了才发现通信根本不通。4.3 串口发送关节角SOARM101 这类机械臂通常通过串口接收关节角度指令协议格式一般是“帧头 数据长度 关节角数据 校验/结束符”。下面是一个示例帧格式import serial import struct import time # 串口配置端口号和波特率以实际设备为准 ser serial.Serial(/dev/ttyUSB0, 115200, timeout0.1) def pack_joint_command(joint_angles_deg): 将 5 个关节角度打包成串口指令帧。 joint_angles_deg: list长度为 5单位为度。 这里使用简化的演示格式 帧头 AA 55数据长度关节角度每个角放大 100 倍2 字节小端结束符 0D。 if len(joint_angles_deg) ! 5: raise ValueError(joint_angles_deg must have 5 elements) data [0xAA, 0x55, 5 * 2 2] for angle in joint_angles_deg: # 将浮点角度放大 100 倍再转为 int16 小端字节 raw int(round(angle * 100)) data.append(raw 0xFF) data.append((raw 8) 0xFF) data.append(0x0D) return bytes(data) def send_joint_angles(angles): cmd pack_joint_command(angles) ser.write(cmd) time.sleep(0.02)这段代码的重点是角度量化方式和字节序。角度放大 100 倍是为了提高整数传输精度具体放大倍数要看主控板协议的定义。如果角度出现负数需要确认协议里是无符号还是有符号整数有符号时通常要用struct.pack(h, raw)而不是手动拆分。5. 运动学解算从目标坐标到关节角5.1 为什么需要逆运动学机械臂末端要到达某个三维坐标我们需要知道五个关节分别转多少度。这个“由末端坐标反推关节角”的过程就是逆运动学。正运动学是“已知关节角求末端坐标”逆运动学反过来。对五自由度机械臂来说逆解通常不唯一可能存在多组关节角都能让末端到达同一位置。比赛策略是选择一组“运动路径最短”或“姿态最自然”的解避免机械臂绕远路。5.2 几何法解算思路SOARM101 这类五自由度平台结构上适合用平面几何法求解。核心思路分三步用末端坐标的 X、Y 求出底座关节角 θ1θ1 atan2(y, x)。把问题投影到机械臂所在的竖直平面内变成一个二连杆问题。用余弦定理求出肘关节角再反推肩关节角。下面是一个简化的平面几何法逆解示例参数仅作演示必须替换为实际机械臂连杆长度import math def inverse_kinematics(x, y, z, phi0.0): 几何法求解五自由度机械臂逆运动学。 x, y, z: 末端目标位置单位米。 phi: 末端绕 Z 轴的期望朝向角单位弧度。 返回值: 5 个关节角度单位弧度。 注意L1、L2、height_base 等参数需要根据实际机械臂标定。 L1 0.12 # 大臂长度演示值 L2 0.10 # 小臂长度演示值 height_base 0.05 # 底座到肩关节的高度演示值 # 1. 底座旋转角 theta1 math.atan2(y, x) # 2. 将目标点投影到机械臂平面 r_planar math.hypot(x, y) z_local z - height_base # 3. 由余弦定理求肘关节角 theta3 dist math.hypot(r_planar, z_local) cos_theta3 (dist * dist - L1 * L1 - L2 * L2) / (2 * L1 * L2) cos_theta3 max(-1.0, min(1.0, cos_theta3)) theta3 math.acos(cos_theta3) # 4. 求肩关节角 theta2 alpha math.atan2(z_local, r_planar) beta math.atan2(L2 * math.sin(theta3), L1 L2 * math.cos(theta3)) theta2 alpha - beta # 5. 腕关节与末端旋转关节根据实际机械臂结构组合 theta4 phi - theta2 - theta3 theta5 phi return [theta1, theta2, theta3, theta4, theta5]这里最容易出错的地方是theta4的计算。不同机械臂的腕关节定义差异很大有的腕关节角度是相对于大臂的有的是相对于小臂的还有的是相对于水平面的。写代码前一定要先看机械臂的结构图把每个关节的正方向和零位搞清楚。逆解算出来之后还要做关节限位检查。机械臂每个关节都有机械限位超出限位的角度必须剔除。否则机械臂可能撞到自身结构轻则动作异常重则损坏舵机。5.3 轨迹平滑避免抖动直接让关节角从当前值跳变到目标值机械臂会非常粗暴地甩过去不仅画面难看还可能因为惯性导致末端过冲。建议在每两个目标点之间插入多个中间关节角让机械臂平滑过渡。def interpolate_joint_trajectory(start_angles, end_angles, steps20): 对关节角做线性插值返回包含 steps 个中间点的小列表。 更平滑的做法是使用 S 形速度规划这里展示最小可用版本。 trajectory [] for i in range(steps 1): ratio i / steps frame [ start (end - start) * ratio for start, end in zip(start_angles, end_angles) ] trajectory.append(frame) return trajectory插值在小范围内足以让动作看起来正常。如果追求更顺滑的轨迹可以引入五次多项式插值或梯形速度规划但比赛阶段线性插值配合较小的步长已经够用。6. 视觉识别与坐标标定6.1 识别方案选择拼图块的识别方案主要有三种颜色阈值、轮廓形状、ArUco 码。比赛时可以根据拼图块特征选一种也可以组合使用。颜色阈值的优点是速度快缺点是受光照影响大需要严格控制环境光。轮廓形状适合拼图块形状规则的情况但要求拼图块之间不能粘连。ArUco 码的优点是每个拼图块有独立 ID识别稳定还能直接得到旋转角度缺点是需要在拼图块上额外贴码如果赛题限定不能改动拼图块表面就不能使用。如果拼图块是彩色图案推荐“颜色 轮廓”的组合先用颜色过滤出候选区域再用轮廓筛选得到块中心和外接矩形。6.2 像素坐标到物理坐标摄像头拍到的是一张图片机械臂工作在一个物理平面内。要把图像中的像素点转换成机械臂坐标系里的毫米坐标需要做透视变换。标准做法是四点标定在工作台上选四个已知物理坐标的点同时在图像中找到对应的四个像素点然后求解透视变换矩阵。import cv2 import numpy as np # 图像中四个标定点的像素坐标按 左上、右上、右下、左下 顺序 src_points np.float32([ [100, 100], [540, 120], [520, 460], [80, 440] ]) # 对应标定点的物理坐标单位 mm按相同顺序 dst_points np.float32([ [0, 0], [200, 0], [200, 200], [0, 200] ]) # 计算单应性矩阵 M cv2.getPerspectiveTransform(src_points, dst_points) def pixel_to_world(px, py): 将像素坐标转换为物理坐标。 返回 (x_mm, y_mm) point np.array([[[px, py]]], dtypenp.float32) world cv2.perspectiveTransform(point, M) return world[0][0]标定时要注意四点顺序必须一致否则矩阵会变成一个扭曲的映射。另一个问题是相机安装位置与工作台不平行这种情况下透视变换仍然能工作但标定点的分布范围要覆盖机械臂的实际工作区域避免外推误差。6.3 ArUco 识别示例如果允许在拼图块上贴 ArUco 码识别过程会简单很多import cv2 from cv2 import aruco # 使用 4x4 字典包含 50 个码 aruco_dict aruco.Dictionary_get(aruco.DICT_4X4_50) parameters aruco.DetectorParameters_create() cap cv2.VideoCapture(0) # 根据实际相机编号调整 while True: ret, frame cap.read() if not ret: break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) corners, ids, _ aruco.detectMarkers(gray, aruco_dict, parametersparameters) if ids is not None: for i in range(len(ids)): c corners[i][0] # 取矩形对角线的中点作为标码中心 center_x int((c[0][0] c[2][0]) / 2) center_y int((c[0][1] c[2][1]) / 2) # 进一步转换到世界坐标 world_x, world_y pixel_to_world(center_x, center_y) print(id%s center(%d, %d) world(%.1f, %.1f) % ( ids[i], center_x, center_y, world_x, world_y)) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()ArUco 的最大优势是自带 ID 和旋转角估计拼图时可以直接判断“这块是什么图案”以及“它朝哪个方向”。如果赛题不允许贴码就把识别部分换成颜色或轮廓算法坐标系转换逻辑不变。7. 主流程设计状态机与容错7.1 为什么用状态机拼图任务看起来是“抓这块、放那块”实际执行时有大量分支找不到拼图块怎么办抓取失败怎么办放偏了怎么办如果不用状态机而是散落一堆if-else代码很快会变得无法维护越改越乱。状态机把整个流程拆成有限个状态每个状态只负责一件事状态之间的转移条件清晰。这样调试时只需要关注当前状态在哪、为什么卡住、下一步应该转移到哪里。7.2 最小状态机框架下面是一个适合拼图任务的状态机骨架import time # 状态定义 STATE_INIT INIT STATE_SCAN SCAN STATE_PLAN PLAN STATE_MOVE_ABOVE MOVE_ABOVE STATE_GRAB GRAB STATE_MOVE_TARGET MOVE_TARGET STATE_PLACE PLACE STATE_VERIFY VERIFY STATE_FINISH FINISH def run_puzzle_loop(): state STATE_INIT puzzle_list load_puzzle_targets() # 载入拼图目标列表 current_index 0 while state ! STATE_FINISH: if state STATE_INIT: # 回到机械臂初始位置 move_to_home() state STATE_SCAN elif state STATE_SCAN: target detect_next_puzzle(current_index) if target is None: # 没有找到目标可以重试或提示报错 state STATE_SCAN else: state STATE_PLAN elif state STATE_PLAN: joint_angles plan_grab_path(target) if joint_angles is None: # 规划失败可能是目标不可达 state STATE_SCAN else: state STATE_MOVE_ABOVE elif state STATE_MOVE_ABOVE: move_arm(joint_angles_above, waitTrue) state STATE_GRAB elif state STATE_GRAB: enable_gripper() time.sleep(0.5) if not gripper_has_block(): # 抓取失败重新扫描 state STATE_SCAN else: state STATE_MOVE_TARGET elif state STATE_MOVE_TARGET: move_arm(joint_angles_place, waitTrue) state STATE_PLACE elif state STATE_PLACE: disable_gripper() time.sleep(0.3) state STATE_VERIFY elif state STATE_VERIFY: ok verify_placement() if ok: current_index 1 if current_index len(puzzle_list): state STATE_FINISH else: state STATE_SCAN else: # 放偏了进行纠偏 state STATE_PLACE print(拼图任务完成)状态机里最容易被忽略的是“抓取失败判断”和“放置校验”。比赛现场拼图块位置可能和预设略有偏差舵机老化后抓取力度也可能变化。如果没有失败检测机械臂会对着空气反复执行同一个动作浪费时间还容易扣分。建议在抓手上加一个简单的到位传感器或者通过视觉判断拼图块是否被吸起。放置校验同样重要。拼图块放下去之后可以用顶置相机再看一眼目标位置确认拼图块中心是否在允许误差范围内。如果不在就进入纠偏流程。8. 常见问题与排查思路比赛调试过程中绝大多数问题都集中在这几个方向问题现象可能原因排查方式解决方案机械臂运动时剧烈抖动关节角跳变、舵机负载偏大、轨迹没有插值检查发送的关节角序列观察是否突变使用轨迹插值降低运动速度抓取位置总是偏同一个方向坐标标定矩阵不准用标定点重新验证像素到物理坐标映射重新五点或四点标定覆盖工作区识别时有时无光照变化、曝光固定、目标太小查看图像直方图观察阈值分割效果固定光源调整曝光用自适应阈值串口指令发出但机械臂不动波特率不匹配、协议字节错误、电源不足先用串口助手发送固定指令测试核对协议文档逐字节对比同一位置多次执行结果不一致舵机重复精度不足、机械结构松动让机械臂多次空跑同一目标点降低速度检查螺丝紧固必要时软件补偿拼图块被夹歪或带偏夹爪行程不合适、放置位置过高观察放置瞬间拼图块姿态增加下压缓冲调整放置高度第一个问题最典型。很多队伍第一问就栽在抖动上原因不是逆解错了而是把目标关节角直接发给机械臂没有做任何插值。机械臂从 0 度瞬间跳到 90 度舵机承受巨大冲击底盘也会跟着晃。解决方法是把目标角度拆成 20 到 50 个中间点依次下发每个点之间延迟几十毫秒。整个过程耗时可能只增加一两秒但稳定性会明显提升。第二个问题需要特别强调标定不是做一次就完事的。比赛场地更换、相机移动、工作台挪动之后标定矩阵都必须重新计算。建议把标定过程写成一个独立脚本每次换场地后先跑一遍标定再进入正式任务。串口问题也不能忽视。赛场上电磁环境复杂USB 转串口模块质量参差不齐偶尔会出现丢包。建议在串口协议里加上简单的校验和同时在代码里加入超时重发机制。否则机械臂可能只收到半个帧直接忽略或者乱动。9. 从“能跑”到“稳跑”工程建议9.1 先离线慢速再在线全速不要一上来就让机械臂全速跑完整流程。建议先把视觉输出、坐标转换、逆解结果全部打印到终端用数据确认每个环节都正确然后再让机械臂执行。这一步能帮你节省大量调试时间。更推荐的做法是做一个“空跑模式”机械臂按规划路径移动但不打开夹爪。这样能提前发现路径上是否有干涉、运动是否平滑、目标点是否可达又不会因为抓取失败打乱节奏。9.2 代码要模块化把视觉、运动学、串口、状态机分成独立模块每个模块提供清晰接口。比赛后期最怕的是改一个识别参数结果影响了机械臂运动。模块化之后每个文件的职责单一改动范围可控。建议的目录结构puzzle_project/ ├── main.py # 主程序状态机入口 ├── vision.py # 识别与坐标转换 ├── kinematics.py # 正逆运动学 ├── serial_control.py # 串口通信与协议 ├── calibrate.py # 标定脚本 └── config.py # 常量与参数配置config.py里放机械臂连杆长度、舵机限位、串口端口、速度档位等所有可能调整的参数。这样比赛现场调参时不需要翻遍整个项目找硬编码值。9.3 比赛实录里的三个血泪经验从整个备赛过程和比赛实录来看有三个经验最值得记下来。第一标定一定要提前做。比赛现场的时间非常紧张如果到了现场才第一次做标定一旦相机位置或者灯光有变化很容易手忙脚乱。正确做法是赛前把标定脚本写好现场只花五分钟执行一遍。第二拼图任务要设计“重试”而不是“一次到底”。第三问的拼图流程长中间任何一次抓放失败都可能导致后续连环错误。状态机里必须预留重试路径抓取失败重新识别放置失败重新调整。不要试图让机械臂一次动作做到完美而是设计出让错误可以修正的机制。第三保护机械臂零位。比赛过程中如果机械臂撞到工作台边缘或者拼图框关节会被顶偏后续所有运动学计算都会出错。建议在代码里加软件限位同时在机械结构上做好硬限位保护。每次比赛开始前让机械臂回一次零位确认所有关节角度都正确。9.4 完全开源的意义项目标题里写着“完全开源”这不仅是把代码发出来更是把调试过程、踩坑记录和第一二三问的复盘思路一起分享出来。对下一届准备电赛的队伍来说最有价值的其实不是源代码本身而是“为什么这样设计”和“这个坑是怎么踩出来的”。如果你准备用这套代码建议不要直接抄而是先跑通整个流程再根据自己的机械臂型号和赛题要求做修改。特别要注意不同版本的 SOARM101 机械臂连杆长度、舵机型号、主控板协议都可能不同代码里的演示参数必须重新标定。10. 总结E 题拼图装置这道题真正区分队伍实力的地方不是会不会调用某个库而是能不能把视觉、运动学、串口通信、任务调度这些模块稳定地串在一起。第一问拼运动控制第二问拼标定精度第三问拼容错设计每一问都在上一问的基础上加一环最终形成完整的系统能力。本文给出的代码框架可以帮你快速跑通从识别到抓放的完整流程。接下来的工作是测量自己机械臂的连杆长度标定相机坐标调整状态机里的超时和重试逻辑然后在真实场地上反复测试。如果只带一句话进赛场我希望是这句先让机械臂稳定地空跑一千次再谈识别和拼图。稳定是 1其他都是后面的 0。