qr_scanner_node.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import rospy
  4. import cv2
  5. import json
  6. import requests
  7. import sys
  8. from pyzbar.pyzbar import decode
  9. from sensor_msgs.msg import Image
  10. from cv_bridge import CvBridge
  11. from qr_vision.srv import ScanQRCodes, ScanQRCodesResponse
  12. sys.path.append('/home/ucar/ucar_ws/src/SparkTalk')
  13. from SparkMain import build_prompt, ask_xinghuo, clean_json_response, validate_result_structure
  14. class QRVisionNode:
  15. def __init__(self):
  16. self.bridge = CvBridge()
  17. self.product_names = []
  18. self.scanned_urls = set()
  19. rospy.init_node('qr_vision_node', anonymous=True)
  20. rospy.Subscriber('/ucar_camera/image_raw', Image, self.image_callback)
  21. rospy.Service('/scan_qrcodes', ScanQRCodes, self.handle_scan_request)
  22. rospy.loginfo("二维码视觉节点已启动")
  23. def image_callback(self, img_msg):
  24. if len(self.product_names) >= 3:
  25. return
  26. frame = self.bridge.imgmsg_to_cv2(img_msg, "rgb8")
  27. frame_bgr = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
  28. for obj in decode(frame_bgr):
  29. url = obj.data.decode('utf-8')
  30. if url in self.scanned_urls:
  31. continue
  32. rospy.loginfo("识别到二维码URL: %s", url)
  33. try:
  34. resp = requests.get(url, timeout=5)
  35. data = resp.json()
  36. if data.get("code") == 200:
  37. product = data["result"]
  38. self.product_names.append(product)
  39. self.scanned_urls.add(url)
  40. rospy.loginfo("货品: %s (%d/3)", product, len(self.product_names))
  41. except Exception as e:
  42. rospy.logwarn("请求URL失败: %s", str(e))
  43. def handle_scan_request(self, req):
  44. real_cat = req.real_category
  45. sim_cat = req.simulation_category
  46. timeout = rospy.Time.now() + rospy.Duration(15)
  47. while len(self.product_names) < 3 and rospy.Time.now() < timeout:
  48. rospy.sleep(0.5)
  49. if len(self.product_names) < 3:
  50. rospy.logwarn("只识别到%d个二维码", len(self.product_names))
  51. rospy.loginfo("识别到的货品: %s", str(self.product_names))
  52. prompt = build_prompt(real_cat, sim_cat, self.product_names)
  53. raw_response = ask_xinghuo(prompt)
  54. real_product = ""
  55. sim_product = ""
  56. try:
  57. cleaned = clean_json_response(raw_response)
  58. result = json.loads(cleaned)
  59. is_valid, errors = validate_result_structure(
  60. result, real_cat, sim_cat, self.product_names)
  61. if is_valid:
  62. real_product = result["real_task"]["matched_product"]
  63. sim_product = result["simulation_task"]["matched_product"]
  64. rospy.loginfo("决策成功: 真实=%s 仿真=%s", real_product, sim_product)
  65. else:
  66. rospy.logwarn("校验失败: %s", str(errors))
  67. except Exception as e:
  68. rospy.logerr("JSON解析失败: %s", str(e))
  69. saved_products = list(self.product_names)
  70. self.product_names = []
  71. self.scanned_urls = set()
  72. return ScanQRCodesResponse(
  73. product_names=saved_products,
  74. real_product=real_product,
  75. simulation_product=sim_product
  76. )
  77. if __name__ == '__main__':
  78. try:
  79. QRVisionNode()
  80. rospy.spin()
  81. except rospy.ROSInterruptException:
  82. pass