uleroboticsgroup / yasmin

YASMIN (Yet Another State MachINe)
GNU General Public License v3.0
130 stars 25 forks source link

Subscription and Publishing to Topic from State (Python) #9

Closed lars-nagel closed 9 months ago

lars-nagel commented 9 months ago

Hello!

I am trying to understand how I can subscribe and publish to (multiple & different) ROS topics from a single State. I had a look at the monitor_demo.py, but how could I subscribe to multiple topics and also publish messages? Would this even be possible with a similar structure as it is shown in yasmin_demo.py with the imports from yasmin import State and from yasmin import StateMachine?

Thanks!

mgonzs13 commented 9 months ago

Hi @lars-nagel, on the side of the publishers, you can have several publishers created in your node and then use them in a state or even you can create the publishers in the state. An example of this could be:

import rclpy
from std_msgs.msg import String
from simple_node import Node
from yasmin import State
from yasmin import Blackboard

class FooState(State):
    def __init__(self, node) -> None:
        super().__init__(["outcome1"])
        self.counter = 0
        self.pub1 = node.create_publisher(String, 'topic_1', 10)
        self.pub2 = node.create_publisher(String, 'topic_2', 10)

    def execute(self, blackboard: StateMachine) -> str:
        print("Executing state FOO")
        msg1 = String()
        msg1.data = f"{Counter: self.counter}"
        self.pub1.publish(msg1)

        msg2 = String()
        msg2.data = "Hello"
        self.pub2.publish(msg2)

        return "outcome1"

On the other hand, subscribing to multiple topics is different. Do you want something similar to message_filters?

lars-nagel commented 9 months ago

Thank you for your quick answer @mgonzs13!

Basically, I want to monitor the system status within a state via topic subscriptions and publish messages from the same state according to the received messages and also change the state based on the received system status.

I think the solution to the problem for me was the initialization of the state class with

class FooState(State):
    def __init__(self, node) -> None:
        super().__init__(["outcome1"])

compared to

class FooState(MonitorState):
    def __init__(self, node: Node, times: int) -> None:
        super().__init__(node,  # node
                         ["outcome1"])

from the monitor_demo.py example, which throws an exception for me when I pass the self argument in

sm.add_state("FOO", FooState(self),
             transitions={"outcome1": "BAR"})