一、产品说明
本产品主要应用于 AGV 小车定位导航,通过 AGV 导航传感器采集图像,并通过内部算法处理,解析画面中的二维码所代表的。
产品特性:
- 内置读码算法,可高效读取 DM 码、码带和矩阵码
- 内置色带定位算法,可高效定位色带位置
- 算法鲁棒性强,可有效应对条码脏污、缺损、低对比度的情形
- 选用优秀的 Sensor,图像质量优异,图像数据高速采集
- 多指示灯用于调试和状态显示
- M12 低畸变镜头,支持大视野读码定位
- 优秀的光学设计,补光均匀,适应强反光场景
二、接口介绍与定义
设备接口为 12-pin P10 接口,提供供电、以太网和串口等功能,具体管脚信号定义如图 2-2、表 2-2 所示。
我使用的扫码器型号是MV-SC2005AM-02WBN AGV 导航读码器,他只能扫描地码,码带和色带是扫描不出来的。
三、相机的使用
本次实验就是使用扫码器识别地码,接线:(1)、用一根网线连接到电脑。(2)、接电源线,白色接24v,黑色接0v。
(1)、下载4.2.4版本的IDMVS软件
我第一次使用的版本是5.1版本的IDMVS软件,但是点击开始采集的时候会显示黑屏。就是相机识别不到图像。就像下边一样。
解决办法就是下载回4.2.4版本的IDMVS,但是有时后打开还是会黑屏,后面只需要重启一下设备就行了。
(2)、打开开始采集,就能看到图像了。
(3)、信息解读
右下角就的绿色部分就是扫描出来的关于码的信息了。
(3)、信息解读
<0007@(315.000x446.000)19.805@...@1-1-1>
这个就是相机的简单使用了,具体的参数调节可以看手册。
四、使用udp协议通讯接收相机的识别信息
(1)、IDMVS软件的设置
进入相机的设备树
(2)、找到传输控制
下面的这个就是数据传输的路径
(2)、编写py脚本接收并解析数据
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """海康 MV-SC2005AM-02WBN 地码读码器 UDP 接收测试。 配置相机(IDMVS -> Transport Layer Control): Result Transfer Prototal = UDP Smart Udp Enable = On UDP Dst Addr = 192.168.20.55 UDP Dst Port = 1024 启动: python hikrobot_udp.py 结束: Ctrl+C 仅使用 Python 标准库。 说明:按照用户提供的《AGV导航读码器-客户版》UDP示例解析: HKVS 头、命令码、128 字节 ASCII 识别结果区域;不同固件可能有差异。 物理坐标二进制字段暂不按固定偏移强行解码,保存原始包供核对。 """ import argparse import re import socket from datetime import datetime from pathlib import Path MAGIC = b"HKVS" # 示例帧中:magic(4)+packet_id(4)+reserved(4)+command(4)+length(4)+timestamp(4) # +algorithm_ms(4)+flags(4)+info_length(4) = 36 bytes,随后128字节文本区。 ASCII_OFFSET = 36 ASCII_SIZE = 128 PATTERN = re.compile( r"<([^@<>]+)@\(\s*([+-]?\d+(?:\.\d+)?)\s*x\s*" r"([+-]?\d+(?:\.\d+)?)\s*\)\s*([+-]?\d+(?:\.\d+)?)" r"@([^@<>]*)@([^@<>]*)@([01]-[01]-[01])>" ) def parse_packet(data: bytes): """返回 (metadata, result, ascii_text)。解析失败 result 为 None。""" meta = {"size": len(data), "magic_ok": data.startswith(MAGIC)} if len(data) < ASCII_OFFSET or not meta["magic_ok"]: return meta, None, "" meta.update( packet_id=int.from_bytes(data[4:8], "big"), command=int.from_bytes(data[12:16], "big"), length_field=int.from_bytes(data[16:20], "big"), algorithm_ms=int.from_bytes(data[24:28], "big"), flags=list(data[28:31]), ) raw_text = data[ASCII_OFFSET:ASCII_OFFSET + ASCII_SIZE].split(b"\x00", 1)[0] ascii_text = raw_text.decode("ascii", errors="replace") match = PATTERN.search(ascii_text) if not match: return meta, None, ascii_text code, x, y, angle, cost, timestamp, flags = match.groups() return meta, { "code": code, "x_px": float(x), "y_px": float(y), "angle_deg": float(angle), "cost": cost, "timestamp": timestamp, "status": flags, }, ascii_text def main(): parser = argparse.ArgumentParser(description="海康 AGV 地码读码器 UDP 接收测试") parser.add_argument("--bind", default="0.0.0.0", help="监听IP,默认0.0.0.0") parser.add_argument("--port", type=int, default=1024, help="监听端口,默认1024") parser.add_argument("--camera-ip", default="192.168.20.99", help="相机来源IP;仅做提示,仍打印其它来源") parser.add_argument("--hex", action="store_true", help="每包打印完整十六进制") parser.add_argument("--all", action="store_true", help="打印每个包,默认只打印识别变化和每隔50包状态") parser.add_argument("--save", default="hikrobot_udp_packets.bin", help="保存原始包的文件名(长度前缀)") args = parser.parse_args() save_path = Path(args.save) count = 0 last_state = None with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp, save_path.open("ab") as dump: udp.bind((args.bind, args.port)) udp.settimeout(2) print("=" * 60) print("海康 SC2005AM UDP 通信测试(Ctrl+C退出)") print(f"相机IP预期:{args.camera_ip}") print(f"监听地址:{args.bind}:{args.port}") print(f"原始报文保存:{save_path.resolve()}") print("=" * 60) try: while True: try: data, (src_ip, src_port) = udp.recvfrom(65535) except socket.timeout: if count == 0: print("尚未收到数据:请检查相机UDP使能、目的IP/端口、防火墙。") continue count += 1 dump.write(len(data).to_bytes(4, "big") + data) dump.flush() meta, result, text = parse_packet(data) if args.hex: print(f"\nHEX {src_ip}:{src_port}({len(data)}字节):\n{data.hex(' ').upper()}") if result is not None: state = (result["code"], result["x_px"], result["y_px"], result["angle_deg"], result["status"]) if args.all or state != last_state: print(f"\n[{datetime.now():%H:%M:%S}] 来自 {src_ip}:{src_port},共收到 {count} 包") print(f"地码编号: {result['code']}") print(f"图像中心坐标: X={result['x_px']:.3f} px, Y={result['y_px']:.3f} px") print(f"地码角度: {result['angle_deg']:.3f}°") print(f"算法耗时: {result['cost']} ms | 时间戳: {result['timestamp']}") print(f"状态(定位-译码-ROI): {result['status']}") last_state = state elif args.all or count == 1 or count % 50 == 0: print(f"[{datetime.now():%H:%M:%S}] 第{count}包 来自 {src_ip}:{src_port} " f"长度={len(data)},magic={meta['magic_ok']} " f"命令={meta.get('command', '未知')},未匹配地码文本") if text: print(f"ASCII: {text[:180]!r}") if not args.hex: print("前64字节HEX:", data[:64].hex(" ").upper()) if src_ip != args.camera_ip and (args.all or count == 1): print(f"提示:收到的来源IP {src_ip} 与预期相机IP {args.camera_ip} 不同。") except KeyboardInterrupt: print(f"\n退出,共收到 {count} 包。原始报文已保存:{save_path.resolve()}") except PermissionError as exc: print(f"保存报文权限不足:{exc}") if __name__ == "__main__": main()(3)、脚本运行结果
情况1:未识别到地码
[16:13:55] 第5600包 来自 192.168.20.99:8192 长度=268,magic=True 命令=1,未匹配地码文本 前64字节HEX: 48 4B 56 53 00 00 A7 9C 00 00 00 00 00 00 00 01 00 00 00 F8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [16:13:56] 第5650包 来自 192.168.20.99:8192 长度=268,magic=True 命令=1,未匹配地码文本 前64字节HEX: 48 4B 56 53 00 00 A7 CE 00 00 00 00 00 00 00 01 00 00 00 F8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [16:13:56] 第5700包 来自 192.168.20.99:8192 长度=268,magic=True 命令=1,未匹配地码文本 前64字节HEX: 48 4B 56 53 00 00 A8 00 00 00 00 00 00 00 00 01 00 00 00 F8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00情况2:识别到地码
[16:15:02] 来自 192.168.20.99:8192,共收到 359 包 地码编号: 0007 图像中心坐标: X=386.000 px, Y=427.000 px 地码角度: 62.071° 算法耗时: 06 ms | 时间戳: 001500ac 状态(定位-译码-ROI): 1-1-1 [16:15:02] 来自 192.168.20.99:8192,共收到 360 包 地码编号: 0007 图像中心坐标: X=387.000 px, Y=427.000 px 地码角度: 62.093° 算法耗时: 06 ms | 时间戳: 001500b8 状态(定位-译码-ROI): 1-1-1经过脚本测试,相机一上电就开始识别是否存在地码了(一上电就工作了),不需要去IDMVS软件上点击开始采集。