This ROS 2 controller is a simple example of how to use the Motion_library class from the motion.py module to load all motion files from the folder motions and play one of them.
It beats Alice by moving forwards and therefore having a higher coverage.
The Docker image used in the competition is a lightweight iron image that does not have colcon installed so we pre-build the package using the build_controller.sh script.
Here is the nao_controller.py file using Webots' Robot API:
import rclpy
# This is a workaround so that Webots' Python controller classes can be used
# in this case, we need it to import MotionLibrary which needs the Motion class
import os
from ament_index_python.packages import get_package_prefix
os.environ['WEBOTS_HOME'] = get_package_prefix('webots_ros2_driver')
from utils.motion_library import MotionLibrary
class NaoDriver:
def init(self, webots_node, properties):
# we get the robot instance from the webots_node
self.__robot = webots_node.robot
# to load all the motions from the motion folder, we use the Motion_library class:
self.__library = MotionLibrary()
# we initialize the shoulder pitch motors using the Robot.getDevice() function:
self.__RShoulderPitch = self.__robot.getDevice("RShoulderPitch")
self.__LShoulderPitch = self.__robot.getDevice("LShoulderPitch")
# to control a motor, we use the setPosition() function:
self.__RShoulderPitch.setPosition(1.3)
self.__LShoulderPitch.setPosition(1.3)
# for more motor control functions, see the documentation: https://cyberbotics.com/doc/reference/motor
# to see the list of available devices, see the NAO documentation: https://cyberbotics.com/doc/guide/nao
rclpy.init(args=None)
self.__node = rclpy.create_node('nao_driver')
def step(self):
# Mandatory function to go to the next simulation step
rclpy.spin_once(self.__node, timeout_sec=0)
if self.__robot.getTime() == 1: # We wait a bit for the robot to stabilise
# to play a motion from the library, we use the play() function as follows:
self.__library.play('Forwards50')
And here is the ROS 2 launch file using webots_ros2_driver:
import os
from launch import LaunchDescription
from ament_index_python.packages import get_package_share_directory
from webots_ros2_driver.webots_controller import WebotsController
def generate_launch_description():
package_dir = get_package_share_directory('participant')
controller_url = os.environ.get('WEBOTS_CONTROLLER_URL')
my_robot_driver = WebotsController(
robot_name=controller_url,
parameters=[
{'robot_description': os.path.join(package_dir, 'resource', 'webots_controller.urdf')},
]
)
return LaunchDescription([
my_robot_driver,
])
Here is the Dockerfile used by the controller:
# We use the eprosima/vulcanexus:iron-simulation image because it is light
# It has ROS2 and webots_ros2 installed
FROM eprosima/vulcanexus:iron-simulation-3.0.0
WORKDIR /usr/local/webots-project/controllers/participant
# Copies all the files of the controllers folder into the docker container
RUN mkdir -p /usr/local/webots-project/controllers
COPY . /usr/local/webots-project/controllers
# The eprosima/vulcanexus:iron-simulation Docker image does not have colcon installed
# We install it and build the participant package
RUN apt-get update && \
apt-get install -y python3-colcon-common-extensions && \
rm -rf /var/lib/apt/lists/* && \
colcon build
# Environment variable needed to connect to Webots instance
ARG WEBOTS_CONTROLLER_URL
ENV WEBOTS_CONTROLLER_URL=${WEBOTS_CONTROLLER_URL}
ENV USER=root
# Source the ROS iron setup file and run the participant package
CMD . /opt/ros/iron/setup.sh && . /usr/local/webots-project/controllers/participant/install/setup.sh && ros2 launch participant robot_launch.py
Charlie is a more advanced robot controller able to win against Bob.