MQTT Tutorial

Introduction to MQTT and Its Use in Our Hardware Platform

MQTT (Message Queuing Telemetry Transport) is a lightweight, publish-subscribe network protocol that transports messages between devices. It is designed for constrained devices and low-bandwidth, high-latency, or unreliable networks, making it ideal for Internet of Things (IoT) applications. In our hardware platform, we utilize MQTT for efficient communication between various components of the robot.

MQTT Basics

Publish-Subscribe Model

MQTT uses a publish-subscribe model where devices (clients) can publish messages to topics and subscribe to topics to receive messages. This decoupling of publishers and subscribers allows for scalable and flexible communication.

Topics

Topics in MQTT are hierarchical strings that represent different channels of communication. For example, in our system, we use topics like robot/drive and robot/tof_map to organize different types of messages.

Implementation in Our Hardware Platform

MQTT Broker

We use a local MQTT broker running on the robot itself. The broker address is typically set to localhost or the robot's IP address.

Key Topics

Our system utilizes several MQTT topics for different functionalities:

  1. robot/drive: Used for sending movement commands to the robot.
  2. robot/tof_map: Publishes Time-of-Flight sensor data for mapping.
  3. robot/local_path: Communicates path planning information.
  4. robot/odometry: Broadcasts the robot's current position and orientation.
  5. robot/path_completed: Signals when a planned path has been completed.

Publishing Messages

To publish a message, we use the MQTT client's publish method. For example:

client.publish(MQTT_TOPIC_DRIVE, "forward")

This sends a "forward" command to the drive system.

Subscribing to Topics

Components subscribe to relevant topics to receive updates. For instance, the path planning node subscribes to the occupancy grid and odometry topics:

client.subscribe(MQTT_TOPIC_OCC_GRID)
client.subscribe(MQTT_TOPIC_ODOMETRY)

Message Handling

When a message is received on a subscribed topic, it's processed in a callback function:

def on_message(client, userdata, msg):
    if msg.topic == MQTT_TOPIC_OCC_GRID:
        on_occupancy_grid(msg)
    elif msg.topic == MQTT_TOPIC_ODOMETRY:
        on_odometry(msg)

Advantages of Using MQTT

  1. Decoupled Communication: Components can communicate without direct dependencies.
  2. Scalability: Easy to add new features or sensors by introducing new topics.
  3. Lightweight: Minimal overhead, suitable for resource-constrained devices.
  4. Reliability: Supports various quality of service levels for message delivery.

MQTT Basics Tutorial

This tutorial will guide you through the fundamental operations of MQTT in our robot platform: setting up a topic, publishing to a topic, and subscribing to a topic.

Setting Up an MQTT Client

First, you need to set up an MQTT client to interact with the broker. Here's how you can do it:

import paho.mqtt.client as mqtt

# Create an MQTT client instance
client = mqtt.Client()

# Connect to the MQTT broker
client.connect("localhost", 1883, 60)

# Start the MQTT network loop
client.loop_start()

Publishing to a Topic

To send messages to other components, you'll publish to specific topics. Here's an example of publishing a drive command:

# Define the topic
MQTT_TOPIC_DRIVE = "robot/drive"

# Publish a message to the topic
client.publish(MQTT_TOPIC_DRIVE, "forward")

You can publish different types of data, including JSON strings for more complex messages:

import json

# Create a dictionary with your data
data = {
    "linear_velocity": 0.5,
    "angular_velocity": 0.2
}

# Convert the dictionary to a JSON string
json_data = json.dumps(data)

# Publish the JSON string to the topic
client.publish(MQTT_TOPIC_DRIVE, json_data)

Subscribing to a Topic

To receive messages from other components, you'll need to subscribe to relevant topics. Here's how you can subscribe to the odometry topic:

# Define the topic
MQTT_TOPIC_ODOMETRY = "robot/odometry"

# Define a callback function to handle received messages
def on_message(client, userdata, msg):
    if msg.topic == MQTT_TOPIC_ODOMETRY:
        data = json.loads(msg.payload)
        print(f"Received odometry data: x={data['x']}, y={data['y']}, theta={data['theta']}")

# Set the message callback
client.on_message = on_message

# Subscribe to the topic
client.subscribe(MQTT_TOPIC_ODOMETRY)

Putting It All Together

Here's a complete example that demonstrates setting up a client, publishing to a topic, and subscribing to a topic:

import paho.mqtt.client as mqtt
import json
import time

# MQTT setup
client = mqtt.Client()
client.connect("localhost", 1883, 60)

# Define topics
MQTT_TOPIC_DRIVE = "robot/drive"
MQTT_TOPIC_ODOMETRY = "robot/odometry"

# Callback function for received messages
def on_message(client, userdata, msg):
    if msg.topic == MQTT_TOPIC_ODOMETRY:
        data = json.loads(msg.payload)
        print(f"Received odometry: x={data['x']:.2f}, y={data['y']:.2f}, theta={data['theta']:.2f}")

# Set the message callback
client.on_message = on_message

# Subscribe to the odometry topic
client.subscribe(MQTT_TOPIC_ODOMETRY)

# Start the MQTT network loop
client.loop_start()

try:
    while True:
        # Publish a drive command
        client.publish(MQTT_TOPIC_DRIVE, "forward")
        time.sleep(1)
        client.publish(MQTT_TOPIC_DRIVE, "stop")
        time.sleep(1)
except KeyboardInterrupt:
    print("Interrupted by user")
finally:
    client.loop_stop()
    client.disconnect()

This example sets up an MQTT client, subscribes to the odometry topic to receive position updates, and publishes alternating "forward" and "stop" commands to the drive topic every second. The received odometry data is printed to the console.

By understanding these basics, you can start building more complex interactions between different components of the robot system using MQTT.