1. 项目概述
在工业自动化检测领域,机械臂与视觉系统的协同作业已成为提升生产效率的关键技术。传统方案通常采用集中式控制架构,存在单点故障风险高、系统扩展性差等问题。我们基于ROS1设计了一套分布式机械臂-多YOLO节点协同检测系统,实现了"到达即检测"的智能化流水线作业。
这个系统最显著的特点是采用了完全去中心化的架构设计。每个YOLO检测节点都是独立运行的ROS节点,它们通过订阅机械臂的状态反馈来自主决定是否启动检测任务。这种设计不仅提高了系统的可靠性(单个节点故障不会影响整体运行),还使得新增检测工位变得非常简单——只需部署新的YOLO节点并配置其负责的工位编号即可。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 整体架构解析
系统采用典型的发布-订阅模式构建,主要包含三大核心组件:
-
机械臂控制节点(Action Server)
- 接收并执行检测任务序列
- 控制机械臂运动到各个检测工位
- 发布当前状态和位置信息
- 接收并处理YOLO节点的检测结果
-
YOLO检测节点集群
- 每个节点负责特定工位的目标检测
- 独立订阅机械臂状态话题
- 当机械臂到达负责的工位时自动触发检测
- 将检测结果发布到专属话题
-
客户端节点
- 发送任务启动指令
- 监控任务执行状态
2.2 关键设计决策
2.2.1 无中心调度器的优势
传统方案通常会设计一个中央视觉调度节点来协调所有检测任务。我们摒弃了这种设计,主要基于以下考虑:
- 降低系统复杂度:省去了中心节点与各检测节点间的复杂通信逻辑
- 提高可靠性:中心节点故障会导致整个系统瘫痪,而分布式架构无此风险
- 增强扩展性:新增检测工位只需添加对应YOLO节点,无需修改中心调度逻辑
2.2.2 动态触发机制
每个YOLO节点通过检查机械臂发布的current_task和current_part字段来判断是否需要进行检测。这种设计实现了:
- 精准触发:只有当机械臂确实到达指定工位时才启动检测
- 资源节约:避免不必要的计算资源消耗
- 灵活配置:通过修改参数即可调整各节点负责的工位范围
2.2.3 独立结果发布
每个YOLO节点将检测结果发布到独立的话题(如/yolo_gap31/result),这种设计解决了:
- 消息混淆问题:机械臂只需订阅当前工位对应的结果话题
- 调试便利性:可以单独监控每个检测节点的输出
- 性能隔离:某个节点的高延迟不会阻塞其他节点的消息传递
3. 核心实现细节
3.1 消息接口设计
3.1.1 Action接口定义
我们设计了专门的Action消息类型robot_detection.action来规范机械臂与客户端的交互:
python复制# Goal定义
uint8 task_id # 任务类型标识
# Result定义
bool is_completed
uint8 final_arm_state
uint8 vision_final_result
# Feedback定义
uint8 arm_state
uint8 progress
uint8 current_task
uint8 current_part
bool is_detection_ready
uint8 vision_step_status
这种设计充分考虑了:
- 任务多样性:通过task_id支持不同类型的检测任务
- 状态完整性:feedback包含机械臂运动状态、检测进度等多维信息
- 结果明确性:最终结果清晰区分正常完成与异常情况
3.1.2 检测结果消息
YOLO节点使用YoloResult.msg发布检测结果:
python复制uint8 vision_step_status
string detection_info
这种精简的设计实现了:
- 状态标准化:使用与Action相同的状态枚举值,保证一致性
- 信息丰富性:通过JSON字符串传递详细的检测结果
- 扩展便利性:新增字段不会破坏现有系统的兼容性
3.2 机械臂控制节点实现
3.2.1 状态机设计
机械臂节点实现了精细的状态管理:
python复制STATE_IDLE = 0 # 空闲状态
STATE_MOVING = 1 # 运动中
STATE_POSE_READY = 2 # 到达目标位置
STATE_RESETTING = 3 # 复位中
STATE_HOMED = 4 # 已复位
STATE_FAULT = 5 # 故障状态
状态机的合理设计带来了以下优势:
- 行为可预测:每个状态下机械臂有明确的允许操作
- 异常处理完善:故障状态有专门的恢复流程
- 调试友好:通过状态值可以快速定位问题所在
3.2.2 多线程处理
节点采用多线程架构处理不同任务:
- 主线程:执行任务序列,控制机械臂运动
- 急停监控线程:实时监听急停信号
- 回调处理线程:处理YOLO节点的检测结果
这种架构确保了:
- 实时响应:急停信号能够立即中断机械臂运动
- 高效执行:主线程不会被阻塞等待IO操作
- 资源合理利用:CPU时间得到充分利用
3.3 YOLO节点实现
3.3.1 基类设计
我们设计了YoloNodeBase基类,封装了通用逻辑:
python复制class YoloNodeBase:
def __init__(self, task_id, part_id, result_topic, model_path=None):
# 初始化ROS接口
# 加载模型
# 启动订阅
def perform_detection(self):
# 图像等待逻辑
# 异常处理
# 结果发布
基类设计带来了以下好处:
- 代码复用:通用逻辑只需实现一次
- 开发高效:新检测节点只需继承基类并实现inference方法
- 维护方便:基础功能修改只需调整基类
3.3.2 具体节点实现
以门缝检测节点为例:
python复制class YoloGap31(YoloNodeBase):
def __init__(self):
super().__init__(task_id=3, part_id=31,
result_topic='/yolo_gap31/result',
model_path="models/gap31.pth")
def inference(self, image):
# 实现具体的检测逻辑
return '{"gap_width":2.3, "status":"ok"}'
这种设计使得:
- 职责清晰:每个节点只关注自己的检测逻辑
- 部署灵活:可以根据实际需求配置不同模型
- 性能优化:每个节点可以独立进行性能调优
4. 关键技术与难点解决方案
4.1 线程同步机制
4.1.1 条件变量的应用
系统使用threading.Condition实现高效的线程同步:
python复制# 在机械臂节点中
with self.vision_cond:
while self.waiting_for_vision:
remaining = timeout_duration - (time.time() - start_wait)
if remaining <= 0:
break
self.vision_cond.wait(remaining)
# 在结果回调中
with self.vision_cond:
self.waiting_for_vision = False
self.vision_cond.notify_all()
这种方案相比传统方法具有明显优势:
| 同步方案 | CPU占用 | 响应延迟 | 实现复杂度 |
|---|---|---|---|
| 忙等待 | 高 | 低 | 低 |
| 定期轮询 | 中 | 中 | 低 |
| 条件变量 | 低 | 低 | 中 |
4.1.2 超时处理策略
系统实现了智能的超时处理机制:
- 设置总超时时间(10秒)
- 计算剩余等待时间
- 超时后自动标记为VISION_STEP_TIMEOUT
- 继续执行后续任务
这种设计确保了:
- 系统健壮性:不会因单个检测超时而卡死
- 生产效率:超时后能够继续后续工位的检测
- 可追溯性:明确记录超时发生的工位和任务
4.2 异常处理机制
4.2.1 急停功能实现
急停系统采用独立线程监控:
python复制def estop_monitor(self):
rospy.Subscriber('/emergency_stop', Bool, self.estop_callback)
def estop_callback(self, msg):
if msg.data:
with self.emergency_lock:
self.emergency_stop = True
self.handle_emergency_stop()
急停触发后的处理流程:
- 立即停止机械臂运动
- 取消当前任务
- 将状态标记为FAULT
- 通知所有等待线程
- 向客户端返回中止状态
4.2.2 检测失败处理
对于检测失败(YOLO返回VISION_STEP_FAILED)的情况:
- 记录失败信息
- 在feedback中更新状态
- 根据任务需求决定是否继续后续工位检测
- 在最终结果中汇总所有失败情况
5. 系统部署与优化
5.1 启动配置
系统使用launch文件统一启动所有节点:
xml复制<launch>
<node name="arm_server" pkg="my_robot" type="arm_server.py"/>
<node name="yolo_gap31" pkg="my_vision" type="yolo_gap31.py"/>
<node name="yolo_gap32" pkg="my_vision" type="yolo_gap32.py"/>
<!-- 更多YOLO节点 -->
</launch>
启动配置考虑了:
- 资源分配:可以通过roslaunch参数控制节点CPU占用
- 日志管理:每个节点的输出可以单独重定向
- 依赖管理:确保核心节点优先启动
5.2 性能优化技巧
在实际部署中,我们总结了以下优化经验:
-
图像传输优化
- 使用ROS的压缩图像传输
- 调整图像分辨率和帧率
- 考虑使用硬件加速编解码
-
检测性能优化
- 对YOLO模型进行量化
- 使用TensorRT加速推理
- 批处理多个检测请求
-
系统响应优化
- 合理设置线程优先级
- 优化机械臂运动轨迹
- 预加载下一个工位所需的资源
6. 实际应用案例
6.1 门缝检测系统
我们将其应用于电梯门缝检测场景:
- 机械臂依次移动到4个检测位置
- 每个位置对应的YOLO节点检测门缝宽度
- 系统记录所有位置的检测结果
- 生成完整的门缝质量报告
实施效果:
- 检测效率提升3倍(相比人工检测)
- 测量精度达到±0.1mm
- 可24小时不间断工作
6.2 按键面板检测系统
应用于电梯按键面板功能检测:
- 机械臂携带相机扫描按键区域
- YOLO节点识别按键状态(正常/卡住/损坏)
- 另一个YOLO节点检测屏幕显示内容
- 系统综合判断面板整体功能状态
实施效果:
- 检测准确率99.2%
- 平均检测时间45秒/台
- 自动生成检测报告
7. 扩展与改进方向
基于当前系统,还可以进一步扩展:
-
动态任务配置
- 通过服务接口实时更新检测流程
- 支持临时插入紧急检测任务
-
自适应检测策略
- 根据历史数据自动调整检测参数
- 实现基于质量的检测频率调整
-
多机械臂协同
- 扩展系统支持多机械臂协作
- 实现负载均衡和任务分配
-
云端监控与分析
- 将检测数据上传云端
- 实现远程监控和大数据分析
在实际使用这套系统时,有几点特别值得注意:
-
机械臂运动轨迹规划:要确保机械臂在工位间的移动路径最优,避免不必要的空程。我们采用S曲线加减速算法,使运动更加平滑。
-
视觉-运动补偿:当检测到目标位置有偏差时,系统会自动计算补偿量。这里使用的公式是:
code复制Δx = (实测x - 理论x) × 比例系数 Δy = (实测y - 理论y) × 比例系数比例系数需要根据实际机械精度进行标定。
-
检测超时处理:除了系统预设的10秒超时外,我们还添加了动态超时调整机制。当连续多个工位检测都接近超时时,系统会自动延长后续工位的超时阈值,避免因临时性能波动导致误判。
-
资源监控:每个YOLO节点都实现了资源使用率监控,当CPU或内存使用超过阈值时,会自动降低检测频率或分辨率,保证系统稳定运行。
