ExoStack / ROS 2 interfaces
External inputs
Your own nodes: estimators and sensors that feed ExoStack, and drivers that take its set-points.
ExoStack accepts signals from your own nodes and hands its set-points to any ROS 2 driver. Publish on the topic named in the YAML file, with the type and layout shown, and use best-effort QoS to match ExoStack.
| Topic | Description | Message type |
|---|---|---|
/<speed_topic> | walking speed for the lookup table → profile node | std_msgs/Float32estimator input layout |
/<intent_topic> | locomotion intent → profile node | std_msgs/Float32estimator input layout |
/<gait_phase_topic> | gait phase → planner | std_msgs/Float32estimator input layout |
/<external_sensors_topic> | metabolic, EMG or other signals → cost evaluator | std_msgs/Float32MultiArrayexternal sensors layout |
/<additional_gait_marker_topic> | in-cycle marker → cost evaluator | std_msgs/Int32gait marker layout |
Driving another actuator
A planner's output_topic is an ordinary std_msgs/Float32 set-point, so a ROS 2 driver of any actuator can subscribe to it instead of an actuation hub.
A minimal estimator
speed_estimator.py
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSProfile, QoSReliabilityPolicy
from std_msgs.msg import Float32
class SpeedEstimator(Node):
def __init__(self):
super().__init__("speed_estimator")
qos = QoSProfile(depth=10, reliability=QoSReliabilityPolicy.BEST_EFFORT)
self.pub = self.create_publisher(Float32, "/walking_speed", qos) # speed_topic in profile.yaml
self.create_timer(0.1, self.tick) # 10 Hz
def tick(self):
self.pub.publish(Float32(data=3.5)) # your estimate here
rclpy.init()
rclpy.spin(SpeedEstimator())