Create Turtlesim Controller Package

This guide walks you through creating a custom ROS 2 package containing a controller node for the turtlesim simulator.

1️⃣ Overview

In this tutorial, you will create a ROS 2 package called my_turtlesim_controller containing a node called node_turtle_controller.py that publishes velocity commands to control the turtle’s movement.

Note

Key Terminology:

  • Package (my_turtlesim_controller): The organizational unit that contains all related files, dependencies, and nodes

  • Node (node_turtle_controller.py): The executable Python script that performs the actual work (subscribing, publishing, processing data)

This package will demonstrate the basic structure of a ROS 2 Python package and how nodes communicate via topics.

3️⃣ Create the Package

Use the ros2 pkg create command to create the my_turtlesim_controller package:

ros2 pkg create

ros2 pkg create my_turtlesim_controller --build-type ament_python --dependencies rclpy
pkg create

4️⃣ Understand the Generated Files

The command creates the following structure:

my_turtlesim_controller/
├── CMakeLists.txt          # CMake build file (not used for Python packages)
├── package.xml             # Defines package metadata and dependencies
├── resource/               # Stores package-specific resources
│   └── my_turtlesim_controller  # Empty marker file for ament resource index
├── setup.py                # Python build script
└── my_turtlesim_controller/ # Directory for Python scripts

Open up the src in Visual Studio Code to view:

cd ~/turtlesim_ws/src
code .
file structure

5️⃣ Add Dependencies

Edit package.xml to declare the package dependencies. For controlling turtlesim, include rclpy and turtlesim:

<depend>turtlesim</depend>
package.xml dependency

Add your email to the maintainer email line in package.xml:

maintainer email

6️⃣ Colcon Build

Navigate back to the turtlesim_ws directory:

cd ~/turtlesim_ws

Use colcon build to build the new package. Note and explanation:

Note

The colcon build command:

  • Identifies the packages in the src/ directory based on the presence of package.xml files.

  • Resolves dependencies, determines build order, and invokes the appropriate build system (e.g., CMake for C++ or setuptools for Python).

colcon build

If you get the setup tools error, follow the instructions below:

setup tools error

pip3 install setuptools==58.2.0

7️⃣ Write the Python Node Code

Create a Python script for the turtle controller node. In the terminal navigate to the package’s python directory:

cd ~/turtlesim_ws/src/my_turtlesim_controller/my_turtlesim_controller

Create a file called node_turtle_controller.py:

Note

We prefix the filename with node_ to clearly indicate this is a ROS 2 node (an executable component) rather than a package or library module. This naming convention helps distinguish between:

  • Package: my_turtlesim_controller (the container/directory)

  • Node: node_turtle_controller.py (the executable script that runs)

touch node_turtle_controller.py

Make the file executable:

chmod +x node_turtle_controller.py

Go back to src and open it in vscode:

cd ../..
code .

Install the ROS extension in vscode:

ros extension

This is an example Python node (save as node_turtle_controller.py):

#!/usr/bin/env python3
import rclpy  # Import the ROS 2 Python client library
from rclpy.node import Node  # Import the Node base class for creating ROS 2 nodes
from geometry_msgs.msg import Twist  # Import the Twist message type for velocity commands

class TurtleController(Node):
    """
    A ROS 2 Node to control the turtle in turtlesim by publishing velocity commands.
    """
    def __init__(self):
        # Initialize the Node with the name 'turtle_controller'
        super().__init__('turtle_controller')

        # Create a publisher to the '/turtle1/cmd_vel' topic
        self.publisher = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)

        # set up a timer that calls the move_turtle method every 0.5 seconds
        self.timer = self.create_timer(0.5, self.move_turtle)

        # Log a message indicating the node has been started
        self.get_logger().info('Turtle Controller Node has started.')

    def move_turtle(self):
        """
        Publishes a velocity command to make the turtle move.
        """
        twist = Twist()
        twist.linear.x = 2.0
        twist.angular.z = 1.0
        self.publisher.publish(twist)
        self.get_logger().info('Published velocity command.')

def main(args=None):
    rclpy.init(args=args)
    node = TurtleController()
    try:
        node.move_turtle()
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

8️⃣ Update setup.py

Update the setup.py file to add an entry point so the script is runnable as a console script:

entry_points={
    'console_scripts': [
        'turtle_controller = my_turtlesim_controller.node_turtle_controller:main',
    ],
},

9️⃣ Build the Package

Navigate back to the root of the workspace and build your package:

cd ~/turtlesim_ws
colcon build --packages-select my_turtlesim_controller

Note

If you use --symlink-install when developing Python packages, you won’t need to re-run colcon build after every code change.

🔟 Source the Workspace

source ~/turtlesim_ws/install/setup.bash

Note

If you added the source line to your .bashrc, you can instead run source ~/.bashrc to load the workspace.

⏸️ Test the my_turtlesim_controller Node

ros2 run turtlesim turtlesim_node

In another terminal:

ros2 run my_turtlesim_controller turtle_controller

In another terminal:

ros2 topic echo /turtle1/cmd_vel

In another terminal:

rqt_graph

The turtle should move in a circular motion based on the linear and angular velocities you defined.

Summary

You have successfully created a custom ROS 2 package that controls the turtlesim simulator. This demonstrates the fundamental concepts of ROS 2 package creation, node development, and topic-based communication.