Create a package for TurtleBot 3 to stop when an obstacle is detected
Introduction
In this tutorial, we’ll explore how to leverage Lidar data to implement a simple yet effective wall-avoidance mechanism for a robot, specifically the TurtleBot 3. By understanding the ‘ranges’ array from the laser scans, we can program our robot to make informed decisions and navigate around obstacles.
In this course, you’ll cover the foundational concepts needed to start working with ROS 2, as well as more advanced topics, all while engaging in hands-on practice.
Understanding LiDAR Data:
The Lidar sensor provides an array of values, with the middle values representing distances directly in front of the robot. Visualize the laser’s scope as approximately 180 degrees from right to left. Values at the array’s start and end correspond to side readings (left and right), while those in the middle relate to front readings. This spatial arrangement is crucial for determining the presence of a wall in the robot’s path.
Opening the rosject
In order to follow this tutorial, we need to have ROS 2 installed in our system, and ideally a ros2_ws (ROS2 Workspace). To make your life easier, we have already prepared a rosject for that: https://app.theconstruct.ai/l/639b9a55/
Just by copying the rosject (clicking the link above), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject.
After pressing the Run button, you should have the rosject loaded. Now, let’s head to the next section to get some real practice.
In order to interact with ROS2, we need a terminal.
Let’s open a terminal by clicking the Open a new terminal button.
If we want to see data being published on /scan topic , we just have to write rostopic echo /scan
So for our application, we need the value of the array at the middle (index no 360).
Create a package for obstacle avoidance using lidar
Copy the rosject from the link attached at the starting of a tutorial as it already has TurtleBot package in it and write the below commands in web shell cd simulation_ws/src
catkin_create_pkg lidardata std_msgs rospy cd lidardata
mkdir launch mkdir src
cd launch
touch lidardata.launch cd ..
cd src
touch myscript.py chmod +x myscript.py cd
cd simulation_ws catkin_make
Logic of code
Let’s dive into the logic of our Python code. The goal is simple: if the distance directly in front of the robot is greater than 0.5 meters, it will continue moving forward; otherwise, it stops to avoid a collision. #! /usr/bin/env python
#Importing all the required Libraries and messages import rospy
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
# Create a Twist message to control robot movement
move_robot = Twist()
move_robot.linear.x = 0.5
move_robot.angular.z = 0
#Defining a call back function for the Subcriber. def callback(msg):
#Publish the movement command Pub1.publish(move_robot)
# Check distance directly in front of the robot (at the middle if(msg.ranges[360] > 0.5):
# If the distance is greater than 0.5 meters, move forward move_robot.linear.x = 0.1
move_robot.angular.z = 0.0
elif(msg.ranges[360] < 0.5):
# If the distance is less than 0.5 meters, stop to avoid collis move_robot.linear.x = 0.0
move_robot.angular.z = 0.0
# Initialize the ROS node rospy.init_node('lidar_data_node')
# Set up the robot movement publisher
Pub1 = rospy.Publisher('/cmd_vel',Twist,queue_size = 1)
# Set up the Lidar data subscriber
Sub1 = rospy.Subscriber('/scan',LaserScan,callback)
# Keep the node running and processing Lidar data rospy.spin()
Now we have created a node named ‘lidar_data_node’ which subscribes to topic ‘/scan’ and publishes velocity data to ‘/cmd_vel’.
How to create node in Python to spawn new object in Gazebo Simulation
Overview:
ROS (Robot Operating System) is a de facto standard for Robotics. In order to program Robots, simulation of Real world systems is very important to test and debug the systems. For simulations of Robotics systems, Gazebo is used commonly in ROS. In this post we will learn how to add new objects in simulation scene without terminating the simulation entirely.
In general, if we want to add new object in simulation scene, we have to terminate all running nodes in simulation, edit the World file (description file for simulation in Gazebo). In order to add new objects, without terminating nodes, we can use Gazebo API in Python to spawn new objects in simulation dynamically.
In this course, you’ll cover the foundational concepts needed to start working with ROS 2, as well as more advanced topics, all while engaging in hands-on practice.
In this course, you’ll cover the foundational concepts needed to start working with ROS 2, as well as more advanced topics, all while engaging in hands-on practice.
Opening the rosject
In order to follow this tutorial, we need to have ROS2 installed in our system, and ideally a ros2_ws (ROS2 Workspace). To make your life easier, we have already prepared a rosject for that: https://app.theconstructsim.com/l/5e01d324/
Just by copying the rosject (clicking the link above), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject ( see this example).
After pressing the Run button, you should have the rosject loaded. Now, let’s head to the next section to get some real practice.
In order to interact with ROS2, we need a terminal.
Let’s open a terminal by clicking the Open a new terminal button.
cd cpp_py_pkg/
touch src/cpp_node.cpp
touch include/cpp_py_pkg/cpp_header.hpp
In order to compile the package later, we need at least a main function in the C++ node. For this tutorial for simplicity, we can just add this minimal code to the cpp_node.cpp file:
#include “rclcpp/rclcpp.hpp”
// Include your header file to use it
#include “cpp_py_pkg/cpp_header.hpp”
int main(int argc, char **argv)
{
// Initiate ROS communications
rclcpp::init(argc, argv);
// Instantiate the node
auto node = std::make_shared<rclcpp::Node>(“my_node_name”);
// Make the node spin
rclcpp::spin(node);
// Shutdown ROS communications
rclcpp::shutdown();
return 0;
}
Add a Python node and module to import
For Python, we need to create additional folders first:
The CMakeLists.txt and package.xml will be shared by Python and C++, which is what we will edit in the next section to configure the package for both Python and C++.
Configure the package
package.xml
Add a buildtool_depend tag for ament_cmake_python:
# Install Python executables in the ros2_ws/install/cpp_py_pkg/lib/cpp_py_pkg/ folder
install(PROGRAMS
scripts/py_node.py
DESTINATION lib/${PROJECT_NAME}
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
Compile package, then run C++ node and Python node
cd ~/ros2_ws/
colcon build –packages-select cpp_py_pkg
Source ROS2 environment and start C++ node in one terminal:
source ~/ros2_ws/install/setup.bash
ros2 run cpp_py_pkg cpp_executable
Source ROS2 environment and start Python node in another terminal:
source ~/ros2_ws/install/setup.bash
ros2 run cpp_py_pkg py_node.py
That’s it! If there are no errors when you run the nodes then it means that it was successful (remember that our nodes do not do anything except spin).
Congratulations. You now know how to use C++ and Python in the same ROS 2 package.
To learn more about ROS 2, have a look at the course below:
In this course, you’ll cover the foundational concepts needed to start working with ROS 2, as well as more advanced topics, all while engaging in hands-on practice.
Opening the rosject
In order to follow this tutorial, we need to have ROS2 installed in our system, and ideally a ros2_ws (ROS2 Workspace). To make your life easier, we have already prepared a rosject for that: https://app.theconstructsim.com/l/5e6f9418/
Just by copying the rosject (clicking the link above), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject ( see this example).
After pressing the Run button, you should have the rosject loaded. Now, let’s head to the next section to get some real practice.
In order to interact with ROS2, we need a terminal.
Let’s open a terminal by clicking the Open a new terminal button.
Setup the package architecture
Create a standard ROS2 package using ament_python
With dependencies on rclpy:
cd ~/ros2_ws/src/
ros2 pkg create py_pkg –build-type ament_python –dependencies rclpy
Run the “tree .” command to see the folder structure. If you don’t have the command installed, you can install it using:
sudo apt-get update
sudo apt-get install -y tree
You should be able to see this structure which you are already familiar with:
Add custom Python module(s) that you want to import
You will need to add module files under the directory with the same name as the package (in this case py_pkg):
cd py_pkg/py_pkg
touch module_to_import.py
For this tutorial for simplicity, we can just add this minimal function to the module_to_import.py file that just prints “hello world”:
def function_to_import():
print(“hello world”)
Create a ‘scripts’ directory for your Python node(s)
Specify the directory as a Python package by creating an empty__init__.pyfile (essential for the folder to be recognized by Python as a package), then add a Python node:
cd ..
mkdir scripts
touch scripts/__init__.py
touch scripts/py_node.py
Here is a simple node implementation (to paste in py_node.py) that imports and uses the function from the module we just created:
import rclpy
from rclpy.node import Node
# Import a specific function/class from your module
from py_pkg.module_to_import import function_to_import
class MyPythonNode(Node):
def __init__(self):
super().__init__(“my_node_name”)
# Run the imported function
function_to_import()
def main(args=None):
# Initiate ROS communications
rclpy.init(args=args)
# Instantiate the node
node = MyPythonNode()
# Make the node spin
rclpy.spin(node)
# Destroy the node object
node.destroy_node()
# Shutdown ROS communications
rclpy.shutdown()
if __name__ == ‘__main__’:
main()
Final package architecture
Run the “tree.” command to see the folder structure inside py_pkg:
This is so that later when you build with colcon, ROS2 knows to put the Python packages here ~/<workspace_name>/install/<package_name>/lib/<python_version>/site-packages/<package_name> (in our case <workspace_name> is ros2_ws, <python_version> ispython3.10, and <package_name> is py_pkg).
If there is no warning then that’s great, but don’t worry if you get it as it is just a warning (not an error) and you will still be able to build successfully.
As of the time of writing this tutorial, the developers hope to have it fixed for Jazzy in May 2024, but for now, there are workarounds to remove the warning. The original workaround was to downgrade the version of setuptools that is currently installed by doing pip install setuptools==58.2.0 in the terminal. However, that is not recommended. Instead you should use the PYTHONWARNINGS environment variable to suppress that particular warning by adding this to the ~/.bashrc file:
PYTHONWARNINGS=”ignore:setup.py install is deprecated::setuptools.command.install”; export PYTHONWARNINGS
You could do this by entering this into the terminal:
echo “PYTHONWARNINGS=\”ignore:setup.py install is deprecated::setuptools.command.install\”; export PYTHONWARNINGS” >> ~/.bashrc
Don’t forget to source the .bashrc in the terminal before compiling the package to register the changes:
source ~/.bashrc # . ~/.bashrc
You should now be able to compile the package without the warning.
cd ~/ros2_ws/
colcon build –packages-select py_pkg
Run the node
In the terminal, source the ROS2 environment and start the Python node:
source ~/ros2_ws/install/setup.bash
ros2 run py_pkg py_node_executable
If you get the following output, that means it was successful!
hello world
Congratulations. You now know how to import custom Python3 modules in a ROS 2 package.
To learn more about ROS 2, have a look at the course below: