news 2026/7/2 9:59:37

工业场景视觉测距实战:AGV 导航与避障

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
工业场景视觉测距实战:AGV 导航与避障

工业场景视觉测距实战:AGV 导航与避障

1. AGV 视觉导航需求

AGV 视觉导航功能: ├── 定位:视觉 SLAM / 二维码定位 ├── 测距:障碍物距离检测 ├── 避障:实时障碍物规避 ├── 导航:路径规划与跟踪 └── 装载:货物对接与装卸

2. 障碍物距离检测

#!/usr/bin/env python3"""agv_obstacle.py - AGV 障碍物检测"""importcv2importnumpyasnpfromultralyticsimportYOLOclassAGVObstacleDetector:"""AGV 障碍物检测器"""def__init__(self,model_path,camera_matrix,safety_distance=2.0):self.model=YOLO(model_path)self.camera_matrix=camera_matrix self.safety_distance=safety_distance# 安全距离(米)self.fx=camera_matrix[0,0]self.fy=camera_matrix[1,1]# 已知物体尺寸self.known_sizes={'person':1.7,'forklift':2.0,'pallet':0.15,'box':0.4,'obstacle':1.0,}defdetect_obstacles(self,image):"""检测障碍物并估算距离"""results=self.model.predict(image,conf=0.3,verbose=False)obstacles=[]forrinresults:forboxinr.boxes:cls_name=self.model.names[int(box.cls)]bbox=box.xyxy[0].tolist()conf=float(box.conf)# 估算距离distance=self._estimate_distance(bbox,cls_name)# 判断是否在安全距离内is_danger=distance<self.safety_distance obstacles.append({'class':cls_name,'bbox':bbox,'confidence':conf,'distance':distance,'is_danger':is_danger,})returnobstaclesdef_estimate_distance(self,bbox,cls_name):"""估算距离"""x1,y1,x2,y2=bbox pixel_height=y2-y1ifcls_nameinself.known_sizes:real_height=self.known_sizes[cls_name]distance=(real_height*self.fy)/pixel_heightelse:# 默认估算distance=500/pixel_heightreturndistancedefget_navigation_command(self,obstacles):"""根据障碍物生成导航命令"""# 检查前方障碍物front_obstacles=[oforoinobstaclesifo['is_danger']]ifnotfront_obstacles:return{'action':'forward','speed':'normal'}# 计算障碍物方向forobsinfront_obstacles:cx=(obs['bbox'][0]+obs['bbox'][2])/2img_center=self.camera_matrix[0,2]ifcx<img_center-100:return{'action':'turn_right','reason':obs['class']}elifcx>img_center+100:return{'action':'turn_left','reason':obs['class']}else:return{'action':'stop','reason':obs['class']}return{'action':'stop','reason':'obstacle'}if__name__=="__main__":calib=np.load("calibration.npz")detector=AGVObstacleDetector("yolo26n.pt",calib["camera_matrix"])cap=cv2.VideoCapture(0)whileTrue:ret,frame=cap.read()ifnotret:breakobstacles=detector.detect_obstacles(frame)command=detector.get_navigation_command(obstacles)# 绘制forobsinobstacles:x1,y1,x2,y2=map(int,obs['bbox'])color=(0,0,255)ifobs['is_danger']else(0,255,0)cv2.rectangle(frame,(x1,y1),(x2,y2),color,2)label=f"{obs['class']}{obs['distance']:.1f}m"cv2.putText(frame,label,(x1,y1-10),cv2.FONT_HERSHEY_SIMPLEX,0.6,color,2)# 显示导航命令cv2.putText(frame,f"CMD:{command['action']}",(10,30),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,255),2)cv2.imshow("AGV",frame)ifcv2.waitKey(1)&0xFF==ord('q'):breakcap.release()cv2.destroyAllWindows()

3. 深度相机避障

#!/usr/bin/env python3"""depth_avoidance.py - 深度相机避障"""importcv2importnumpyasnpimportpyrealsense2asrsclassDepthAvoidance:"""深度相机避障"""def__init__(self,safety_distance=1.0):self.pipeline=rs.pipeline()config=rs.config()config.enable_stream(rs.stream.depth,640,480,rs.format.z16,30)self.pipeline.start(config)self.safety_distance=safety_distance*1000# m → mmdefcheck_obstacles(self):"""检查障碍物"""frames=self.pipeline.wait_for_frames()depth_frame=frames.get_depth_frame()depth=np.asanyarray(depth_frame.get_data())# 分区域检查h,w=depth.shape regions={'left':depth[:,:w//3],'center':depth[:,w//3:2*w//3],'right':depth[:,2*w//3:],}obstacles={}forname,regioninregions.items():# 忽略 0 值(无效深度)valid=region[region>0]iflen(valid)>0:min_distance=np.percentile(valid,5)# 5% 分位数obstacles[name]={'min_distance':min_distance/1000,# mm → m'is_safe':min_distance>self.safety_distance,}returnobstacles,depthdefget_avoidance_command(self,obstacles):"""避障命令"""left_safe=obstacles.get('left',{}).get('is_safe',True)center_safe=obstacles.get('center',{}).get('is_safe',True)right_safe=obstacles.get('right',{}).get('is_safe',True)ifcenter_safe:return{'action':'forward'}elifleft_safe:return{'action':'turn_left'}elifright_safe:return{'action':'turn_right'}else:return{'action':'stop'}if__name__=="__main__":avoidance=DepthAvoidance(safety_distance=1.0)whileTrue:obstacles,depth=avoidance.check_obstacles()command=avoidance.get_avoidance_command(obstacles)print(f"障碍物:{obstacles}")print(f"命令:{command}")

4. 货物对接测距

#!/usr/bin/env python3"""docking.py - 货物对接"""importcv2importnumpyasnpclassCargoDocking:"""货物对接"""def__init__(self,camera_matrix):self.fx=camera_matrix[0,0]self.fy=camera_matrix[1,1]self.cx=camera_matrix[0,2]self.cy=camera_matrix[1,2]defdetect_docking_target(self,image,marker_size=0.1):"""检测对接目标(ArUco 标记)"""aruco_dict=cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_50)detector=cv2.aruco.ArucoDetector(aruco_dict)corners,ids,_=detector.detectMarkers(image)targets=[]ifidsisnotNone:fori,(corner,marker_id)inenumerate(zip(corners,ids.flatten())):# 估计位姿rvec,tvec,_=cv2.aruco.estimatePoseSingleMarkers(corner,marker_size,np.eye(3),np.zeros(5))distance=np.linalg.norm(tvec[0][0])x_offset=tvec[0][0][0]y_offset=tvec[0][0][1]targets.append({'id':marker_id,'distance':distance,'x_offset':x_offset,'y_offset':y_offset,'rvec':rvec[0][0],'tvec':tvec[0][0],})returntargetsdefget_docking_command(self,target):"""生成对接命令"""iftargetisNone:return{'action':'search'}distance=target['distance']x_offset=target['x_offset']# 对接精度distance_threshold=0.05# 5cmangle_threshold=0.05# ~3°ifdistance<distance_thresholdandabs(x_offset)<angle_threshold:return{'action':'dock','status':'aligned'}elifdistance<distance_threshold:return{'action':'adjust_lateral','offset':x_offset}elifabs(x_offset)>angle_threshold:return{'action':'rotate','angle':x_offset}else:return{'action':'approach','distance':distance}if__name__=="__main__":calib=np.load("calibration.npz")docking=CargoDocking(calib["camera_matrix"])cap=cv2.VideoCapture(0)whileTrue:ret,frame=cap.read()ifnotret:breaktargets=docking.detect_docking_target(frame)iftargets:command=docking.get_docking_command(targets[0])print(f"目标:{targets[0]['id']}, 距离:{targets[0]['distance']:.3f}m")print(f"命令:{command}")cv2.imshow("Docking",frame)ifcv2.waitKey(1)&0xFF==ord('q'):breakcap.release()cv2.destroyAllWindows()

总结

功能传感器精度响应时间
障碍物检测单目+YOLO±10%30ms
避障深度相机±2%30ms
货物对接ArUco+深度±1cm50ms
路径跟踪视觉 SLAM±5cm100ms
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 17:33:45

Element Plus 级联选择器实战:仿学科网教材多级选择的完整方案

基于 Element Plus 2.10 的 el-cascader&#xff0c;实现一个「前两级单选 后续层级同父多选」的教材选择器&#xff0c;涵盖 props 配置、选中逻辑、UI 定制和数据提交。一、需求背景 在资源上传场景中&#xff0c;教材数据是一个多级树结构&#xff1a; 出版社&#xff08;第…

作者头像 李华
网站建设 2026/7/2 23:40:25

施工动画全解析:从技术选型到标杆案例,如何让复杂施工方案“看得懂、说得清、能预演”

2026年&#xff0c;施工动画已成为大型基建项目投标、方案评审和技术交底的标准配置。它不再是“效果图的动态版”&#xff0c;而是一份可预演、可验证的“可视化施工方案”。与一般的产品宣传动画不同&#xff0c;施工动画的核心价值不在于视觉有多华丽&#xff0c;而在于能否…

作者头像 李华
网站建设 2026/7/2 16:54:33

新疆公考培训机构怎么选?师资、效果、价格防坑攻略

备考新疆公务员和事业单位&#xff0c;“报班”几乎是绕不开的话题。但这两年公考培训行业经历了几轮洗牌&#xff0c;机构宣传天花乱坠&#xff0c;退费难、师资注水、服务缩水等问题频发。为了帮新疆考生少走弯路&#xff0c;我们结合2026年最新考情和学员反馈&#xff0c;整…

作者头像 李华
网站建设 2026/7/2 9:59:33

2026年7月国内充值 GPT:为什么我不再建议只找低价渠道?

2026年7月&#xff0c;国内用户充值GPT&#xff08;尤其是Plus/Pro/Codex&#xff09;时&#xff0c;不再建议只寻找最低价渠道的核心原因在于&#xff1a;低价渠道的稳定性风险已远超其价格优势&#xff0c;可能带来更高的综合成本。 低价渠道的主要风险 风险类别具体表现潜…

作者头像 李华
网站建设 2026/7/1 3:06:25

iOS自动化测试:WebDriverAgent配置与Appium集成实战指南

1. 项目概述&#xff1a;为什么我们需要WebDriverAgent&#xff1f;如果你是一名iOS或tvOS应用的开发者或测试工程师&#xff0c;那么“自动化测试”这个词对你来说一定不陌生。从单元测试到UI测试&#xff0c;自动化是保证应用质量、提升迭代效率的关键。而在iOS生态中&#x…

作者头像 李华