Skip to main content

Temperature Sensor Example

A complete example showing how to publish and subscribe to sensor data.

Overview

This example demonstrates:

  • Defining a sensor data type in IDL
  • Publishing temperature readings at 10 Hz
  • Subscribing and processing sensor data
  • Using Best Effort QoS for high-frequency data

IDL Definition

SensorData.idl
module sensors {
@topic
struct SensorData {
@key uint32 sensor_id; // Unique sensor identifier
uint64 timestamp; // Nanoseconds since epoch
float temperature; // Celsius
float pressure; // Pascals
float humidity; // Percentage (0-100)
};
};

Generate the Rust types:

hdds-gen --input SensorData.idl --output src/

Publisher

src/publisher.rs
use hdds::prelude::*;
use sensors::SensorData;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create participant on domain 0
let participant = DomainParticipant::new(0)?;

// Create topic
let topic = participant.create_topic::<SensorData>("SensorTopic")?;

// Configure QoS for high-frequency sensor data
let qos = DataWriterQos::default()
.reliability(Reliability::BestEffort)
.history(History::KeepLast { depth: 1 })
.durability(Durability::Volatile);

// Create publisher and writer
let publisher = participant.create_publisher()?;
let writer = publisher.create_writer_with_qos(&topic, qos)?;

println!("Publishing sensor data at 10 Hz...");

let sensor_id = 1;
loop {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_nanos() as u64;

let sample = SensorData {
sensor_id,
timestamp: now,
temperature: 22.5 + (rand::random::<f32>() - 0.5),
pressure: 101325.0 + (rand::random::<f32>() - 0.5) * 100.0,
humidity: 45.0 + (rand::random::<f32>() - 0.5) * 5.0,
};

writer.write(&sample)?;

std::thread::sleep(Duration::from_millis(100)); // 10 Hz
}
}

Subscriber

src/subscriber.rs
use hdds::prelude::*;
use sensors::SensorData;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let participant = DomainParticipant::new(0)?;
let topic = participant.create_topic::<SensorData>("SensorTopic")?;

let qos = DataReaderQos::default()
.reliability(Reliability::BestEffort)
.history(History::KeepLast { depth: 10 });

let subscriber = participant.create_subscriber()?;
let reader = subscriber.create_reader_with_qos(&topic, qos)?;

println!("Listening for sensor data...");

loop {
// Non-blocking read
match reader.try_take() {
Ok(samples) => {
for sample in samples {
println!(
"Sensor {}: temp={:.2}C, pressure={:.0} Pa, humidity={:.1}%",
sample.sensor_id,
sample.temperature,
sample.pressure,
sample.humidity
);
}
}
Err(HddsError::NoData) => {
// No data available, sleep briefly
std::thread::sleep(std::time::Duration::from_millis(10));
}
Err(e) => return Err(e.into()),
}
}
}

Running the Example

Terminal 1 - Start the subscriber:

cargo run --bin subscriber

Terminal 2 - Start the publisher:

cargo run --bin publisher

Expected output:

Sensor 1: temp=22.43C, pressure=101312 Pa, humidity=44.8%
Sensor 1: temp=22.51C, pressure=101340 Pa, humidity=45.2%
Sensor 1: temp=22.48C, pressure=101298 Pa, humidity=44.9%
...

Multiple Sensors

The @key annotation on sensor_id enables tracking multiple sensors:

// Publish from multiple sensors
for sensor_id in 1..=4 {
let sample = SensorData {
sensor_id,
timestamp: now,
temperature: 20.0 + sensor_id as f32,
// ...
};
writer.write(&sample)?;
}

Each sensor_id creates a separate instance with independent:

  • History buffer
  • Deadline tracking
  • Liveliness monitoring

QoS Considerations

ScenarioRecommended QoS
High-rate sensors (>100 Hz)BestEffort, KeepLast(1), Volatile
Critical measurementsReliable, KeepLast(10), TransientLocal
Logging/recordingReliable, KeepAll, Persistent

Performance Tips

  1. Batch small samples: Group multiple readings if sending faster than 1 kHz
  2. Use BestEffort: For high-frequency non-critical data
  3. Keep history small: KeepLast(1) minimizes memory for streaming data
  4. Pre-allocate: Reuse SensorData struct to avoid allocations

Next Steps