Quick Start (Python)

Looking for Rust? See Quick Start (Rust)

This tutorial demonstrates building a temperature monitoring system with HORUS using Python. Estimated time: 10 minutes.

What We're Building

A system with two components:

  1. Sensor - Generates temperature readings
  2. Monitor - Displays the readings

They'll communicate using HORUS's ultra-fast shared memory.

Step 1: Create a New Project

# Create a new Python HORUS project
horus new temperature-monitor -p

cd temperature-monitor

This creates:

  • main.py - Your code (we'll customize this)
  • horus.toml - Project config (name, version, description)
  • .horus/ - Build cache (packages, virtualenv)

Step 2: Write the Code

Replace main.py with this complete example:

import horus

#===========================================
# SENSOR NODE - Generates temperature data
#===========================================

def make_sensor():
    temp = [20.0]  # mutable state via list

    def tick(node):
        temp[0] += 0.1
        node.send("temperature", temp[0])

    return horus.Node(name="TemperatureSensor", tick=tick, rate=1, order=0,
                      pubs=["temperature"])

#============================================
# MONITOR NODE - Displays temperature data
#============================================

def monitor_tick(node):
    temp = node.recv("temperature")
    if temp is not None:
        print(f"Temperature: {temp:.1f}\u00b0C")

monitor = horus.Node(name="TemperatureMonitor", tick=monitor_tick, rate=1, order=1,
                     subs=["temperature"])

#============================================
# MAIN - Run both nodes
#============================================

print("Starting temperature monitoring system...\n")

# Run forever (press Ctrl+C to stop)
horus.run(make_sensor(), monitor)

Step 3: Run It!

horus run

HORUS will automatically:

  • Detect Python from main.py
  • Set up the virtual environment if needed
  • Execute your program

You'll see:

Starting temperature monitoring system...

Temperature: 20.1\u00b0C
Temperature: 20.2\u00b0C
Temperature: 20.3\u00b0C
Temperature: 20.4\u00b0C
...

Press Ctrl+C to stop.

Understanding the Code

Topics - Communication Channels

# Sending data (in the tick function)
node.send("temperature", value)

# Receiving data (in the tick function)
temp = node.recv("temperature")

Both use the same topic name ("temperature"). HORUS manages all shared memory operations automatically. Same API as Rust, but Pythonic.

The Node - Component Definition

Each component is a horus.Node with a tick function:

def make_sensor():
    temp = [20.0]

    def tick(node):
        temp[0] += 0.1
        node.send("temperature", temp[0])

    return horus.Node(name="TemperatureSensor", tick=tick, rate=1,
                      pubs=["temperature"])

The tick function is your main logic, called every cycle. State lives in the closure (or as a plain class instance passed via tick=obj.tick).

Running Everything

# Create nodes with rate and order
sensor = make_sensor()
monitor = horus.Node(name="TemperatureMonitor", tick=monitor_tick,
                     rate=1, order=1, subs=["temperature"])

# Run all nodes (press Ctrl+C to stop)
horus.run(sensor, monitor)

Key configuration on horus.Node(...):

  • order=n - Set execution priority (lower = runs first)
  • rate=n - Set tick frequency in Hz
  • pubs / subs - Declare topic names

Running Nodes in Separate Processes

The example above runs both nodes in a single process. HORUS uses a flat namespace, so multi-process communication works automatically.

# Terminal 1: Run sensor
horus run sensor.py

# Terminal 2: Run monitor (automatically connects!)
horus run monitor.py

Both use the same topic name ("temperature") and communication just works.

Next Steps

Add More Features

1. Add a temperature alert:

def alert_tick(node):
    temp = node.recv("temperature")
    if temp is not None:
        print(f"Temperature: {temp:.1f}\u00b0C")

        if temp > 25.0:
            print("WARNING: Temperature too high!")

2. Integrate with NumPy:

import numpy as np
import horus

def array_tick(node):
    # Generate 100 sensor readings
    readings = np.random.normal(22.0, 0.5, 100)
    node.send("readings", readings.tolist())

sensor_array = horus.Node(name="SensorArray", tick=array_tick, rate=10,
                          pubs=["readings"])

Learn More

Core Concepts:

  • Nodes - Deep dive into the Node pattern
  • Topic - How ultra-fast communication works
  • Scheduler - Priority-based execution

Python-Specific:

See More Examples:

Common Questions

Can I use pip packages?

Yes! Add them to horus.toml:

horus add numpy --source pypi
horus add torch --source pypi

Can I use async/await?

Yes! HORUS supports async nodes in Python:

async def async_tick(node):
    data = await read_sensor_async()
    node.send("sensor_data", data)

sensor = horus.Node(name="AsyncSensor", tick=async_tick, pubs=["sensor_data"])

See Async Nodes for details.

How do I stop the application?

Press Ctrl+C. The scheduler handles graceful shutdown automatically.

Where does the data go?

Data is stored in shared memory, managed automatically by HORUS. You never need to configure paths — horus_sys handles platform differences internally.

Troubleshooting

"ModuleNotFoundError: No module named 'horus'"

Install the HORUS Python bindings:

pip install horus-robotics

Or if using a virtual environment:

horus run  # automatically installs dependencies

"Failed to create Topic"

Another program might be using the same topic name. Pick a unique name:

node.send("temperature_sensor_1", value)

Nothing prints

Make sure both nodes are passed to horus.run():

horus.run(make_sensor(), monitor)

What You've Learned

  • How to create a Python HORUS project with horus new -p
  • The functional horus.Node(tick=fn) pattern
  • Using node.send() and node.recv() for communication
  • Running multiple nodes with horus.run()
  • Sending and receiving messages in Python

Ready for More?

  1. Python API Reference for the full API
  2. Run the examples to see real applications
  3. Open the monitor to monitor your system visually

For issues, see the Troubleshooting Guide.

See Also