Skip to content

Commit 60c089a

Browse files
Merge pull request #8 from benjaminwp18/qos
Qos
2 parents 7983c3d + 52a6cb7 commit 60c089a

File tree

2 files changed

+57
-8
lines changed

2 files changed

+57
-8
lines changed

config/lampi.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ mqtt_ros_bridge:
44
topic: "devices/b827eb3d9134/lamp/set_config"
55
type: "lampi_msgs.msg:Lampi"
66
publish_on_ros: False
7+
ros_qos: 1
8+
mqtt_qos: 1

mqtt_ros_bridge/bridge_node.py

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import os
22
import sys
3-
from typing import Any, Callable, Generic, cast
3+
from enum import IntEnum
4+
from typing import Any, Callable, Generic, cast, Literal
45

56
import paho.mqtt.client as MQTT
67
import rclpy
78
from rclpy._rclpy_pybind11 import RMWError
89
from rclpy.node import Node
910
# TODO this breaks humble
11+
from rclpy.qos import QoSPresetProfiles
1012
from rclpy.parameter import Parameter, parameter_dict_from_yaml_file
1113
from rclpy.publisher import Publisher
1214

@@ -15,23 +17,63 @@
1517
from mqtt_ros_bridge.util import lookup_message
1618

1719

20+
class QoSPresetProfilesInt(IntEnum):
21+
UNKNOWN = 0
22+
DEFAULT = 1
23+
SYSTEM_DEFAULT = 2
24+
SENSOR_DATA = 3
25+
SERVICES_DEFAULT = 4
26+
PARAMETERS = 5
27+
PARAMETER_EVENTS = 6
28+
ACTION_STATUS_DEFAULT = 7
29+
BEST_AVAILABLE = 8
30+
31+
@staticmethod
32+
def to_qos_profile(enum: 'int | QoSPresetProfilesInt') -> QoSPresetProfiles:
33+
match enum:
34+
case QoSPresetProfilesInt.UNKNOWN:
35+
return QoSPresetProfiles.UNKNOWN
36+
case QoSPresetProfilesInt.DEFAULT:
37+
return QoSPresetProfiles.DEFAULT
38+
case QoSPresetProfilesInt.SYSTEM_DEFAULT:
39+
return QoSPresetProfiles.SYSTEM_DEFAULT
40+
case QoSPresetProfilesInt.SENSOR_DATA:
41+
return QoSPresetProfiles.SENSOR_DATA
42+
case QoSPresetProfilesInt.SERVICES_DEFAULT:
43+
return QoSPresetProfiles.SERVICES_DEFAULT
44+
case QoSPresetProfilesInt.PARAMETERS:
45+
return QoSPresetProfiles.PARAMETERS
46+
case QoSPresetProfilesInt.PARAMETER_EVENTS:
47+
return QoSPresetProfiles.PARAMETER_EVENTS
48+
case QoSPresetProfilesInt.ACTION_STATUS_DEFAULT:
49+
return QoSPresetProfiles.ACTION_STATUS_DEFAULT
50+
case QoSPresetProfilesInt.BEST_AVAILABLE:
51+
return QoSPresetProfiles.BEST_AVAILABLE
52+
case _:
53+
return QoSPresetProfiles.UNKNOWN
54+
55+
1856
class TopicMsgInfo(Generic[MsgLikeT]):
1957
"""Metadata about a single topic."""
2058

2159
def __init__(self, topic: str, msg_object_path: str,
22-
publish_on_ros: bool, use_ros_serializer: bool = True) -> None:
60+
publish_on_ros: bool, use_ros_serializer: bool = True,
61+
ros_qos: int | QoSPresetProfilesInt = QoSPresetProfilesInt.DEFAULT,
62+
mqtt_qos: Literal[0, 1, 2] = 0) -> None:
2363

2464
self.topic = topic
2565
self.msg_type: MsgLikeT = cast(MsgLikeT, lookup_message(msg_object_path))
2666
self.publish_on_ros = publish_on_ros
2767
self.serializer = ROSDefaultSerializer if use_ros_serializer else JSONSerializer
68+
self.ros_qos = QoSPresetProfilesInt.to_qos_profile(ros_qos).value
69+
self.mqtt_qos = mqtt_qos
2870

2971
def __str__(self) -> str:
3072
return (f"Topic: {self.topic}, Message Type: {self.msg_type}, Publish on ROS:"
3173
f"{self.publish_on_ros}, Serializer: {self.serializer}")
3274

3375

34-
MQTT_PORT = 1883
76+
MQTT_PORT = 50001
3577
MQTT_KEEPALIVE = 60
3678

3779
PARAMETER_TOPIC = "topic"
@@ -70,13 +112,14 @@ def __init__(self, args: list[str]) -> None:
70112

71113
for topic_info in self.topics.values():
72114
if topic_info.publish_on_ros:
73-
publisher = self.create_publisher(topic_info.msg_type, topic_info.topic, 10)
115+
publisher = self.create_publisher(topic_info.msg_type, topic_info.topic,
116+
topic_info.ros_qos)
74117
self.ros_publishers[topic_info.topic] = publisher
75-
self.mqtt_client.subscribe(topic_info.topic)
118+
self.mqtt_client.subscribe(topic_info.topic, qos=topic_info.mqtt_qos)
76119
else:
77120
callback = self.make_ros_callback(topic_info)
78-
# TODO proper QOS?
79-
self.create_subscription(topic_info.msg_type, topic_info.topic, callback, 10)
121+
self.create_subscription(topic_info.msg_type, topic_info.topic, callback,
122+
topic_info.ros_qos)
80123

81124
self.mqtt_client.on_message = self.mqtt_callback
82125

@@ -123,7 +166,8 @@ def make_ros_callback(self, topic_info: TopicMsgInfo[MsgLikeT]) -> Callable[[Msg
123166
"""
124167
def callback(msg: MsgLikeT) -> None:
125168
self.get_logger().info(f'ROS RECEIVED: Topic: "{topic_info.topic}" Payload: "{msg}"')
126-
self.mqtt_client.publish(topic_info.topic, topic_info.serializer.serialize(msg))
169+
self.mqtt_client.publish(topic_info.topic, topic_info.serializer.serialize(msg),
170+
topic_info.mqtt_qos)
127171

128172
return callback
129173

@@ -165,6 +209,9 @@ def main(args=None):
165209

166210
rclpy.spin(bridge_node)
167211

212+
bridge_node.mqtt_client.socket().shutdown()
213+
bridge_node.mqtt_client.socket().close()
214+
168215
bridge_node.destroy_node()
169216
rclpy.shutdown()
170217

0 commit comments

Comments
 (0)