#!/usr/bin/env python3 import rospy import paho.mqtt.client as mqtt from std_msgs.msg import String import pkg_resources import json # 获取 paho-mqtt 版本 try: PAHO_VERSION = pkg_resources.get_distribution("paho-mqtt").version PAHO_MAJOR_VERSION = int(PAHO_VERSION.split('.')[0]) except Exception: PAHO_VERSION = "unknown" PAHO_MAJOR_VERSION = 1 # MQTT 配置 MQTT_BROKER = "211.154.252.186" # MQTT 代理地址 MQTT_PORT = 1883 # MQTT 代理端口 MQTT_CLIENT_ID = "ros_mqtt_bridge" MQTT_TOPIC_CONTROL = "head_servo/control/1" # 接收控制指令的 MQTT 主题 # MQTT_TOPIC_CONTROL = "robot/yuntai_control/+" MQTT_TOPIC_STATUS = "head_servo/status" # 发布状态的 MQTT 主题 # ROS 配置 ROS_TOPIC_CONTROL = "/head_servo/control_cmd" # 发布控制指令的 ROS 话题 ROS_TOPIC_STATUS = "/head_servo/status" # 接收状态的 ROS 话题 class MQTTROSBridge: def __init__(self): # 初始化 ROS 节点 rospy.init_node("mqtt_ros_bridge", anonymous=True) rospy.loginfo(f"MQTT-ROS 桥接器启动中 (paho-mqtt 版本: {PAHO_VERSION})") # 根据版本选择初始化方式 if PAHO_MAJOR_VERSION >= 2: # 版本 2.0+ 使用新 API self.mqtt_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, clean_session=True) else: # 版本 1.x 使用旧 API self.mqtt_client = mqtt.Client(client_id=MQTT_CLIENT_ID) self.mqtt_client.on_connect = self.on_connect self.mqtt_client.on_message = self.on_message # 连接 MQTT 代理 try: self.mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60) self.mqtt_client.loop_start() # 启动 MQTT 网络循环(非阻塞) rospy.loginfo(f"已连接到 MQTT 代理: {MQTT_BROKER}:{MQTT_PORT}") except Exception as e: rospy.logerr(f"MQTT 连接失败: {e}") exit(1) # 创建 ROS 发布者和订阅者 self.control_pub = rospy.Publisher(ROS_TOPIC_CONTROL, String, queue_size=10) rospy.Subscriber(ROS_TOPIC_STATUS, String, self.status_callback) rospy.loginfo("MQTT-ROS 桥接器已就绪") def on_connect(self, client, userdata, flags, rc, properties): """MQTT 连接成功回调""" rospy.loginfo(f"MQTT 连接成功,返回代码: {rc}") # 订阅 MQTT 控制主题 client.subscribe(MQTT_TOPIC_CONTROL) rospy.loginfo(f"已订阅 MQTT 主题: {MQTT_TOPIC_CONTROL}") # def on_message(self, client, userdata, msg): # """MQTT 消息到达回调""" # try: # # 解析 MQTT 消息 # payload = msg.payload.decode() # rospy.loginfo(f"收到 MQTT 消息: [{msg.topic}] {payload}") # # 将消息发布到 ROS 话题 # ros_msg = String() # ros_msg.data = payload # self.control_pub.publish(ros_msg) # except Exception as e: # rospy.logerr(f"处理 MQTT 消息时出错: {e}") # 修改 MQTT-ROS 桥接脚本中的消息处理部分 def on_message(self, client, userdata, msg): try: payload = msg.payload.decode() rospy.loginfo(f"收到 MQTT 消息: [{msg.topic}] {payload}") # 解析 JSON 命令 try: cmd_data = json.loads(payload) ros_msg = String() ros_msg.data = json.dumps(cmd_data) # 保持 JSON 格式 self.control_pub.publish(ros_msg) except json.JSONDecodeError: # 如果不是 JSON 格式,作为普通字符串处理 ros_msg = String() ros_msg.data = payload self.control_pub.publish(ros_msg) except Exception as e: rospy.logerr(f"处理 MQTT 消息时出错: {e}") def status_callback(self, msg): """ROS 状态消息回调""" try: # 将 ROS 状态消息发布到 MQTT 主题 self.mqtt_client.publish(MQTT_TOPIC_STATUS, msg.data) rospy.loginfo(f"已发布到 MQTT 主题 [{MQTT_TOPIC_STATUS}]: {msg.data}") except Exception as e: rospy.logerr(f"发布到 MQTT 时出错: {e}") def run(self): """运行桥接器""" rospy.spin() # 进入 ROS 循环 # 关闭 MQTT 连接 self.mqtt_client.loop_stop() self.mqtt_client.disconnect() rospy.loginfo("桥接器已关闭") if __name__ == "__main__": try: bridge = MQTTROSBridge() bridge.run() except rospy.ROSInterruptException: pass