Decorator Reference

The core of "The Genesys Way" is its declarative API, which uses Python decorators to define ROS 2 components. This page serves as a complete reference for all available decorators, their parameters, and how to use them effectively.

All decorators are imported from framework_core.decorators.


@node

This is the most fundamental decorator. It transforms a standard Python class into a runnable ROS 2 node.

Signature

@node(name: str)

Usage Apply this decorator to a class definition.

Parameters

Parameter
Type
Required
Description

name

str

Yes

The executable name for the ROS 2 node. This is the name you will use with genesys run.

Behavior

  • Node Registration: Marks the class as a ROS 2 node, enabling the framework to automatically register it as an executable in your package's setup.py.

  • Logger Injection: Automatically creates and injects a pre-configured rclpy logger instance into your class, accessible via self.logger.

  • Launch File Generation: Triggers the auto-generation of a launch file in the workspace's launch/ directory to make the node runnable.

Full Example

from genesys.decorators import node
from genesys.helpers import spin_node

@node(name="my_simple_node")
class MyNode:
    def __init__(self):
        # self.logger is automatically available here
        self.logger.info("My simple node has started!")

def main(args=None):
    spin_node(MyNode, args)

if __name__ == '__main__':
    main()

@publisher

Creates a ROS 2 publisher and links it to a method. The method's return value is automatically published.

Signature

@publisher(topic: str, msg_type: MsgType, qos_profile: int = 10)

Usage Apply this decorator to a method inside a @node-decorated class. This decorator is often combined with @timer.

Parameters

Parameter
Type
Required
Description

topic

str

Yes

The name of the topic to publish messages to (e.g., "chatter").

msg_type

ROS Message Type

Yes

The message type class (e.g., std_msgs.msg.String).

qos_profile

int or QoSProfile

No

The Quality of Service profile for the publisher. Defaults to a depth of 10.

Behavior

  • Publisher Creation: Creates an rclpy publisher instance when the node is initialized.

  • Automatic Publishing: When the decorated method is called, its return value is automatically published to the specified topic. You do not need to call .publish() yourself.

  • The decorated method must return an instance of the specified msg_type.

Full Example

from genesys.decorators import node, timer, publisher
from genesys.helpers import spin_node
from std_msgs.msg import String

@node(name="my_talker_node")
class MyTalker:
    def __init__(self):
        self.counter = 0

    @timer(period_sec=1.0)
    @publisher(topic="chatter", msg_type=String)
    def publish_message(self):
        self.counter += 1
        msg = String()
        msg.data = f"Message #{self.counter}"
        # The returned 'msg' object will be published automatically
        return msg

# ... main function ...

@subscriber

Creates a ROS 2 subscriber and registers the decorated method as its callback.

Signature

@subscriber(topic: str, msg_type: MsgType, qos_profile: int = 10)

Usage Apply this decorator to a method inside a @node-decorated class.

Parameters

Parameter
Type
Required
Description

topic

str

Yes

The name of the topic to subscribe to.

msg_type

ROS Message Type

Yes

The message type class to listen for.

qos_profile

int or QoSProfile

No

The Quality of Service profile for the subscription. Defaults to a depth of 10.

Behavior

  • Subscription Creation: Creates an rclpy subscription when the node is initialized.

  • Callback Registration: The decorated method is automatically set as the callback function for the subscription.

  • Argument Passing: When a message is received, it is automatically passed as the first argument to the decorated method.

Full Example

from genesys.decorators import node, subscriber
from genesys.helpers import spin_node
from std_msgs.msg import String

@node(name="my_listener_node")
class MyListener:
    @subscriber(topic="chatter", msg_type=String)
    def message_callback(self, msg: String):
        # The received 'msg' object is passed in as an argument
        self.logger.info(f'I heard: "{msg.data}"')

# ... main function ...

@timer

Creates a ROS 2 timer that periodically calls the decorated method.

Signature

@timer(period_sec: float)

Usage Apply this decorator to a method inside a @node-decorated class.

Parameters

Parameter
Type
Required
Description

period_sec

float

Yes

The interval in seconds at which to call the method.

Behavior

  • Timer Creation: Creates an rclpy timer that calls the decorated method at the specified frequency. The timer starts when the node is initialized.

Full Example

from genesys.decorators import node, timer
from genesys.helpers import spin_node

@node(name="my_periodic_node")
class MyPeriodicTask:
    @timer(period_sec=5.0)
    def do_work(self):
        self.logger.info("This message prints every 5 seconds.")

# ... main function ...

@service

Creates a ROS 2 service server that automatically handles incoming requests and returns a response.

Signature

@service(topic: str, srv_type)

Usage

Apply this decorator to a method within a

@node-decorated class. The method signature should accept the request message as its single argument.

Parameters

  • topic: str. The name of the service topic.

  • srv_type: str. The ROS 2 service type (e.g.,

    example_interfaces.srv.AddTwoInts).

Behavior

Service Server Creation: Creates an rclpy service server that listens for requests on the specified topic.

Automatic Handling: The decorated method is called automatically when a request is received, with the request object passed as an argument. The value returned by the method is used as the service response.


@action_server

Creates a ROS 2 action server that handles goals, feedback, and results.

Signature

@action_server(topic: str, action_type)

Usage

Apply this decorator to a method that will handle the incoming action goals. This method should act as a generator, yielding feedback and returning a final result.

Parameters

  • topic: str. The name of the action topic.

  • action_type: str. The ROS 2 action type (e.g.,

    example_interfaces.action.Fibonacci).

Behavior

Action Server Creation: Registers a new ActionServer for the specified topic and type.

Generator-based Logic: The decorated method should yield feedback messages during execution and return the final result message.

Automatic Handling: The send_goal callback is automatically handled, and the user's decorated method is executed when a goal is received.


@action_client

Creates a ROS 2 action client to send goals to an action server.

Signature

@action_client(topic: str, action_type)

Usage

Apply this decorator to a method to register an action client. The

_initialize_action_clients method in the GenesysNodeWrapper is responsible for handling this.

Parameters

  • topic: str. The name of the action topic.

  • action_type: str. The ROS 2 action type (e.g.,

    example_interfaces.action.Fibonacci).

Behavior

Action Client Creation: A new ActionClient is created and configured to connect to the specified topic.

Asynchronous Goal Sending: The client is ready to send goals to a server on the specified topic.


@lifecycle_node

Designates a class as a ROS 2 Lifecycle Node, automatically wrapping it and handling state transitions.

Signature

@lifecycle_node(name: str)

Usage

Apply this decorator to a class to enable lifecycle functionality. The class should contain methods for the various state callbacks (e.g.,

on_configure, on_activate, on_deactivate, on_cleanup, on_shutdown, and on_error).

Parameters

  • name: str. The name of the lifecycle node.

Behavior

Automatic Wrapping: The decorator wraps the user-provided class with the core LifecycleNode logic from rclpy.

Callback Handling: The spin_node helper function automatically detects that the node is a lifecycle node and uses a MultiThreadedExecutor to handle state transitions.

Simplified Management: This provides a clean, declarative way to implement lifecycle nodes without needing to manually extend LifecycleNode or manage the executor.

Last updated

Was this helpful?