Skip to main content

A Zenoh-based robotics framework with opinionated namespacing

Project description

Tide

A lightweight, strongly-typed framework for robotics based on Zenoh, with opinionated namespacing.

Overview

Tide wraps Zenoh's key/value-based pub-sub-query model in a set of strongly-typed "robot nodes," each running in its own thread that talks over a shared Zenoh session.

The framework enforces an opinionated namespacing pattern:

/{robot_id}/{group}/{topic}

For example:

  • /frogbot/cmd/twist - Command velocity for the "frogbot" robot
  • /frogbot/state/pose2d - 2D pose state for the robot
  • /frogbot/sensor/lidar - Lidar data from the robot See docs/namespacing.md for a full list of reserved namespaces. The tide.namespaces module exposes enums for these topics so you don't have to hardcode strings.

Features

  • Opinionated namespacing: Clear, consistent naming pattern for all messages
  • Zero-config networking: Lean on Zenoh's peer discovery for automatic device connection
  • Strongly-typed messages: Uses Pydantic models for validation and serialization
  • Pythonic, thread-based architecture: Each node runs in its own thread to keep latency low
  • Callback-based: Register callbacks for specific topics
  • Command-line interface: Easily create and manage Tide projects

Installation

pip install tide-sdk

Or with uv (recommended):

uv add tide-sdk

Command-Line Interface

Tide comes with a powerful CLI to help you create and manage projects.

Creating a New Project

tide init my_robot_project --robot-id robot1

This creates a new project directory with the following structure:

my_robot_project/
├── config/
│   └── config.yaml     # Configuration for nodes
├── nodes/
│   ├── robot_node.py   # Main robot control node
│   ├── teleop_node.py  # Node for commanding the robot
│   └── monitor_node.py # Node for monitoring state
├── main.py             # Project entry point
├── README.md           # Project documentation
└── requirements.txt    # Dependencies

Running Your Project

To start your Tide project:

cd my_robot_project
tide up

This will:

  1. Load the configuration from config/config.yaml
  2. Start all the defined nodes
  3. Display a table of running nodes

You can specify a custom configuration file:

tide up --config path/to/custom_config.yaml

Checking Node Status

To discover running Tide nodes on the network:

tide status

This shows a list of all discovered Tide nodes. The discovery uses the */*/* wildcard so custom groups like the ping-pong example are also found. The output includes:

  • Robot ID
  • Group
  • Topic

For longer discovery times:

tide status --timeout 5.0

Programming API

Defining a Node

from tide.core.node import BaseNode
from tide.models import Twist2D, Pose2D, to_zenoh_value
from tide import CmdTopic, StateTopic

class MyRobotNode(BaseNode):
    ROBOT_ID = "myrobot"  # Your robot's unique ID
    GROUP = "controller"  # Group for this node
    
    def __init__(self, *, config=None):
        super().__init__(config=config)
        
        # Subscribe to command velocity using the reserved enum
        self.subscribe(CmdTopic.TWIST.value, self._on_cmd_vel)
    
    def _on_cmd_vel(self, data):
        # Process command velocity message
        # ...
    
    def step(self):
        # Called at the node's update rate
        # Publish robot state
        pose = Pose2D(x=1.0, y=2.0, theta=0.5)
        self.put(StateTopic.POSE2D.value, to_zenoh_value(pose))

Launching Nodes

import time
from tide.core.utils import launch_from_config
from tide.config import load_config

def main():
    # Load configuration
    config = load_config('config.yaml')

    # Launch nodes
    nodes = launch_from_config(config)

    try:
        print(f"Started {len(nodes)} nodes. Press Ctrl+C to exit.")
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Interrupted by user")
        for node in nodes:
            node.stop()

if __name__ == "__main__":
    main()

Configuration File

session:
  mode: peer  # Mesh network

nodes:
  - type: my_package.MyRobotNode
    params:
      robot_id: "robot1"
      
  - type: my_package.TeleopNode
    params:
      robot_id: "robot1"

See docs/config_spec.md for the formal configuration specification.

Complete Example

The generated project template includes a complete working example. Here's how the nodes work together:

  1. TeleopNode - Generates simple oscillating motion commands (simulating joystick)

    def step(self):
        # Create sinusoidal motion pattern
        t = time.time()
        self.linear_vel = 0.5 * math.sin(0.2 * t)
        self.angular_vel = 0.2 * math.cos(0.1 * t)
    
        # Create and publish the command
        cmd = Twist2D(
            linear=Vector2(x=self.linear_vel),
            angular=self.angular_vel
        )
        self.put(CmdTopic.TWIST.value, to_zenoh_value(cmd))
    
  2. RobotNode - Receives commands and simulates robot movement

    def _on_cmd_vel(self, data):
        cmd = from_zenoh_value(data, Twist2D)
        self.linear_vel = cmd.linear.x
        self.angular_vel = cmd.angular
    
    def step(self):
        # Simple motion model - integrate velocity
        dt = time.time() - self.last_update
        self.theta += self.angular_vel * dt
        self.x += self.linear_vel * math.cos(self.theta) * dt
        self.y += self.linear_vel * math.sin(self.theta) * dt
    
        # Publish the current pose
        pose = Pose2D(x=self.x, y=self.y, theta=self.theta)
        self.put(StateTopic.POSE2D.value, to_zenoh_value(pose))
    
  3. MonitorNode - Displays the robot's state

    def _on_pose(self, data):
        pose = from_zenoh_value(data, Pose2D)
        print(f"Robot pose: x={pose.x:.2f}, y={pose.y:.2f}, theta={pose.theta:.2f}")
    

This demonstrates:

  • Opinionated topic naming (cmd/twist, state/pose2d)
  • Callback-based architecture for handling messages
  • Strong typing with Pydantic models
  • Serialization/deserialization with Zenoh

Common Message Types

  • Twist2D: 2D velocity command (linear x, y and angular z)
  • Pose2D: 2D pose (x, y, theta)
  • Pose3D: 3D pose (position and orientation)
  • Acceleration3D: 3D acceleration (linear and angular)
  • LaserScan: 2D laser scan data

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tide_sdk-0.1.5.tar.gz (28.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tide_sdk-0.1.5-py3-none-any.whl (55.7 kB view details)

Uploaded Python 3

File details

Details for the file tide_sdk-0.1.5.tar.gz.

File metadata

  • Download URL: tide_sdk-0.1.5.tar.gz
  • Upload date:
  • Size: 28.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for tide_sdk-0.1.5.tar.gz
Algorithm Hash digest
SHA256 abc1392d8533e0f842ba26799778ee050087b34821637b51f7ef50770b4946f6
MD5 e4eb940548f68af32d8a6a2943a77c4c
BLAKE2b-256 1679d0d4e5c4d829567d12a9300aebe48ad564bd854c9f853b760ef47dc8986b

See more details on using hashes here.

Provenance

The following attestation bundles were made for tide_sdk-0.1.5.tar.gz:

Publisher: pypi.yaml on NorthCarolinaRivalRobotics/tide

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tide_sdk-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: tide_sdk-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 55.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for tide_sdk-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 88130280536a07d9629d44be09ad06bf4305f1b296a3aaffc2f051ba4fef83a8
MD5 9707a6604a58bdfb569d8875cf0cd2d5
BLAKE2b-256 4e8459b6527e042b21913ea49e0dbcef7a5b697a2b2f400df2d4da49d8a49d5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for tide_sdk-0.1.5-py3-none-any.whl:

Publisher: pypi.yaml on NorthCarolinaRivalRobotics/tide

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page