#!/usr/bin/env python3 # -*- coding: utf-8 -*- import rospy import cv2 import json import requests import sys from pyzbar.pyzbar import decode from sensor_msgs.msg import Image from cv_bridge import CvBridge from qr_vision.srv import ScanQRCodes, ScanQRCodesResponse sys.path.append('/home/ucar/ucar_ws/src/SparkTalk') from SparkMain import build_prompt, ask_xinghuo, clean_json_response, validate_result_structure class QRVisionNode: def __init__(self): self.bridge = CvBridge() self.product_names = [] self.scanned_urls = set() rospy.init_node('qr_vision_node', anonymous=True) rospy.Subscriber('/ucar_camera/image_raw', Image, self.image_callback) rospy.Service('/scan_qrcodes', ScanQRCodes, self.handle_scan_request) rospy.loginfo("二维码视觉节点已启动") def image_callback(self, img_msg): if len(self.product_names) >= 3: return frame = self.bridge.imgmsg_to_cv2(img_msg, "rgb8") frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) for obj in decode(frame_bgr): url = obj.data.decode('utf-8') if url in self.scanned_urls: continue rospy.loginfo("识别到二维码URL: %s", url) try: resp = requests.get(url, timeout=5) data = resp.json() if data.get("code") == 200: product = data["result"] self.product_names.append(product) self.scanned_urls.add(url) rospy.loginfo("货品: %s (%d/3)", product, len(self.product_names)) except Exception as e: rospy.logwarn("请求URL失败: %s", str(e)) def handle_scan_request(self, req): real_cat = req.real_category sim_cat = req.simulation_category timeout = rospy.Time.now() + rospy.Duration(15) while len(self.product_names) < 3 and rospy.Time.now() < timeout: rospy.sleep(0.5) if len(self.product_names) < 3: rospy.logwarn("只识别到%d个二维码", len(self.product_names)) rospy.loginfo("识别到的货品: %s", str(self.product_names)) prompt = build_prompt(real_cat, sim_cat, self.product_names) raw_response = ask_xinghuo(prompt) real_product = "" sim_product = "" try: cleaned = clean_json_response(raw_response) result = json.loads(cleaned) is_valid, errors = validate_result_structure( result, real_cat, sim_cat, self.product_names) if is_valid: real_product = result["real_task"]["matched_product"] sim_product = result["simulation_task"]["matched_product"] rospy.loginfo("决策成功: 真实=%s 仿真=%s", real_product, sim_product) else: rospy.logwarn("校验失败: %s", str(errors)) except Exception as e: rospy.logerr("JSON解析失败: %s", str(e)) saved_products = list(self.product_names) self.product_names = [] self.scanned_urls = set() return ScanQRCodesResponse( product_names=saved_products, real_product=real_product, simulation_product=sim_product ) if __name__ == '__main__': try: QRVisionNode() rospy.spin() except rospy.ROSInterruptException: pass