Tutorial Creating a Custom Python Plugin - cyberbotics/webots_ros2 GitHub Wiki

Since webots_ros2 1.1.1 one can create Python plugins with webots_ros2_driver package.

See the Creating a Custom C++ Plugin tutorial for C++ plugins.

The following example assumes you have a ROS 2 Python package created. On how to create a ROS 2 Python package please visit the official tutorial.

webots_ros2_driver Architecture

Please take a look at the picture below to get a better idea of the plugin system architecture.

webots_ros2_driver architecture

Plugin File Structure

The plugin should be saved under the Python module of your package. For example:

.
├── package_name_example
│   ├── __init__.py
│   └── plugin_example.py
├── resource
│   ├── package_name_example
│   └── your_robot_description.urdf
├── package.xml
└── setup.py

Plugin File

A simple plugin plugin_example.py publishing time can be implemented as follows:

from rosgraph_msgs.msg import Clock
import rclpy


class PluginExample:
    # The `init` method is called only once the driver is initialized.
    # You will always get two arguments in the `init` method.
    # - The `webots_node` argument contains a reference on a Supervisor instance.
    # - The `properties` argument is a dictionary created from the XML tags.
    def init(self, webots_node, properties):
        # Unfortunately, we cannot get an instance of the parent ROS node.
        # However, we can create a new one.
        rclpy.init(args=None)
        self.__node = rclpy.create_node('plugin_node_example')

        # This will print the parameter from the URDF file.
        #
        #     `{ 'parameterExample': 'someValue' }`
        #
        self.__node.get_logger().info('  - properties: ' + str(properties))

        # The robot property allows you to access the standard Webots API.
        # See: https://cyberbotics.com/doc/reference/robot
        self.__robot = webots_node.robot
        self.__node.get_logger().info('  - robot name: ' + str(self.__robot.getName()))
        self.__node.get_logger().info('  - basic timestep: ' + str(int(self.__robot.getBasicTimeStep())))

        # The robot property allows you to access the Supervisor Webots API
        # only if the robot is a Supervisor.
        # The function "self.__robot.getSupervisor()" will return "true" in case the robot is a Supervisor.
        # See: https://cyberbotics.com/doc/reference/supervisor
        self.__node.get_logger().info('  - is supervisor? ' + str(self.__robot.getSupervisor()))

        # The robot property also allows you to access the Driver Webots API
        # in case the robot is based on a Car.
        # See: https://cyberbotics.com/doc/automobile/driver-library

        # Create a simple publisher, subscriber and "Clock" variable.
        self.__node.create_subscription(Clock, 'clock', self.__clock_callback, 1)
        self.__publisher = self.__node.create_publisher(Clock, 'custom_clock', 1)
        self.__clock = Clock()

    def __clock_callback(self, msg):
        self.__clock = msg

    # The `step` method is called at every step.
    def step(self):
        # The self.__node has to be spinned once in order to execute callback functions.
        rclpy.spin_once(self.__node, timeout_sec=0)

        self.__publisher.publish(self.__clock)

Register the Plugin in the URDF File

Then, in the robot description file (e.g. your_robot_description.urdf), under the <webots> tag, you should include the plugin as following:

<?xml version="1.0" ?>
<robot name="Your Robot">
    <webots>
        <plugin type="package_name_example.plugin_example.PluginExample">
            <parameterExample>someValue</parameterExample>
        </plugin>
    </webots>
</robot>

Examples

You can found python plugins examples for the Mavic scenario and the Tesla scenario.

⚠️ **GitHub.com Fallback** ⚠️