[ROS Mini Challenge] #1 – Make a robot rotate according to user input

[ROS Mini Challenge] #1 – Make a robot rotate according to user input

In this post, we will see how to write a ROS program (in Python) to make a robot rotate according to user input. We are going to fix an error in the code that prevents this program from working as we go on.

PS: This ROS project is part of our ROS Mini Challenge series, which gives you an opportunity to win an amazing ROS Developers T-shirt! This challenge is already solved. For updates on future challenges, please stay tuned to our Twitter channel.

Step 1: Grab a copy of the ROS Project that contains the almost-working Python code

Click here to get your own copy of the project. If you don’t have an account on the ROS Development Studio, you will be asked to create one. Once you create an account or log in, the project will be copied to your workspace. That done, open your ROSject using the Open button. This might take a few moments, please be patient.

You should now see a notebook with detailed instructions about the challenge. Please ignore the section that says “Claim your Prize!” because, well, the challenge is closed already 🙂

Step 2: Start the Simulation and run the program

  1. Click on the Simulations menu and then Choose launch file . In the dialog that appears, select rotw1.launchthen click the Launch button. You should see a Gazebo window popup showing the simulation: a robot standing in front of a very beautiful house!
  2. Keeping the Gazebo window in view, pick a Shell from Tools > Shell and run the following commands (input the same numbers shown):
user:~$ rosrun rotw1_code rotate_robot.py
Enter desired angular speed (degrees): 60
Enter desired angle (degrees): 90
Do you want to rotate clockwise? (y/n): y
[INFO] [1580744469.184313, 1044.133000]: shutdown time! Stop the robot

Did the robot rotate? I would be surprised if it did!

Step 3: Find out what the problem is (was!)

Fire up the IDE and locate the file named rotate_robot.py. You will find in the catkin_ws/src/rotw1_code/src directory.

#!/usr/bin/env python

import rospy
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
import time


class RobotControl():

    def __init__(self):
        rospy.init_node('robot_control_node', anonymous=True)
        self.vel_publisher = rospy.Publisher('/velocity', Twist, queue_size=1)
        self.cmd = Twist()
        self.ctrl_c = False
        self.rate = rospy.Rate(10)
        rospy.on_shutdown(self.shutdownhook)

    def publish_once_in_cmd_vel(self):
        """
        This is because publishing in topics sometimes fails the first time you publish.
        In continuous publishing systems, this is no big deal, but in systems that publish only
        once, it IS very important.
        """
        while not self.ctrl_c:
            connections = self.vel_publisher.get_num_connections()
            if connections > 0:
                self.vel_publisher.publish(self.cmd)
                break
            else:
                self.rate.sleep()

    def shutdownhook(self):
        self.stop_robot()
        self.ctrl_c = True

    def stop_robot(self):
        rospy.loginfo("shutdown time! Stop the robot")
        self.cmd.linear.x = 0.0
        self.cmd.angular.z = 0.0
        self.publish_once_in_cmd_vel()

    def get_inputs_rotate(self):
        self.angular_speed_d = int(
            raw_input('Enter desired angular speed (degrees): '))
        self.angle_d = int(raw_input('Enter desired angle (degrees): '))
        clockwise_yn = raw_input('Do you want to rotate clockwise? (y/n): ')
        if clockwise_yn == "y":
            self.clockwise = True
        if clockwise_yn == "n":
            self.clockwise = False

        return [self.angular_speed_d, self.angle_d]

    def convert_degree_to_rad(self, speed_deg, angle_deg):

        self.angular_speed_r = speed_deg * 3.14 / 180
        self.angle_r = angle_deg * 3.14 / 180
        return [self.angular_speed_r, self.angle_r]

    def rotate(self):

        # Initilize velocities
        self.cmd.linear.x = 0
        self.cmd.linear.y = 0
        self.cmd.linear.z = 0
        self.cmd.angular.x = 0
        self.cmd.angular.y = 0

        # Convert speed and angle to radians
        speed_d, angle_d = self.get_inputs_rotate()
        self.convert_degree_to_rad(speed_d, angle_d)

        # Check the direction of the rotation
        if self.clockwise:
            self.cmd.angular.z = -abs(self.angular_speed_r)
        else:
            self.cmd.angular.z = abs(self.angular_speed_r)

        # t0 is the current time
        t0 = rospy.Time.now().secs

        current_angle = 0

        # loop to publish the velocity estimate, current_distance = velocity * (t1 - t0)
        while (current_angle < self.angle_r):

            # Publish the velocity
            self.vel_publisher.publish(self.cmd)
            # t1 is the current time
            t1 = rospy.Time.now().secs
            # Calculate current angle
            current_angle = self.angular_speed_r * (t1 - t0)
            self.rate.sleep()

        # set velocity to zero to stop the robot
        #self.stop_robot()


if __name__ == '__main__':
    robotcontrol_object = RobotControl()
    try:
        res = robotcontrol_object.rotate()
    except rospy.ROSInterruptException:
        pass

The problem was in the def __init__(self) function – we are publishing to the wrong topic – /velocity – instead of /cmd_vel.

Next, let’s see how we found the problem.

Step 4: Learn how the problem was solved

If you’re familiar with ROS, you’ll know that /cmd_vel is the most common name for the topic responsible for moving the robot. It’s not always that, but at least the /velocity topic instantly became suspect! Therefore, we went ahead to examine it to see if it was a proper topic:

user:~$ rostopic info /velocity
Type: geometry_msgs/Twist

Publishers:
 * /robot_control_node_5744_1580744450546 (http://rosdscomputer:45129/)

Subscribers: None

And our suspicions were confirmed: the topic had no subscribers. This was strange, as usually /gazebo would be one of the subscribers if it was connected to the simulation.

On the other hand, /cmd_vel was connected to /gazebo. So, maybe it’s the right topic after all, but let’s confirm that next.

Step 5: Replace /velocity with /cmd_vel and rotate the robot!

Replace /velocity with /cmd_vel in the def __init__(self) function and save.

Now run the program again:

user:~$ rosrun rotw1_code rotate_robot.py
Enter desired angular speed (degrees): 60
Enter desired angle (degrees): 90
Do you want to rotate clockwise? (y/n): y
[INFO] [1580744469.184313, 1044.133000]: shutdown time! Stop the robot

Now, the robot should rotate according to user input – try different numbers!

And that was it. Hope you found this useful.

Extra: Video of this post

We made a video showing how this challenge was solved. If you prefer “sights and sounds” to “black and white”, here you go:

Related Resources

Feedback

Did you like this post? Do you have questions about what was explained? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.

If you want to learn about other ROS or ROS2 topics, please let us know in the comments area and we will do a video or post about it.

[ROS Q&A] 197 – Error in Writing a tf2 broadcaster Tutorial (Python)

[ROS Q&A] 197 – Error in Writing a tf2 broadcaster Tutorial (Python)

Learn how to create a Python program (broadcaster) for broadcasting a tf2 between 2 frames. This video is an answer to the following question found on ROS Answers.


Related Resources


Step 1: Get your development environment ready

Either of the following will do:

  1. Use the ROS Development Studio (ROSDS), an online platform for developing for ROS within a PC browser. Easy-peasy. I’m using this option for this post
    1. Once you log in, click on the New ROSject button to create a project that will host your code. Then Click on Open ROSject to launch the development/simulation environment.
    2. To open a “terminal” on ROSDSpick the Shell app from the Tools menu.
    3. You can find the IDE app on the Tools menu.
  2. You have ROS installed on a local PC. Okay, skip to Step 2.

Next step!

Step 2: Create the TF ROS package for the tf2 broadcaster Python node

The tutorial the user tried to follow is at http://wiki.ros.org/tf2/Tutorials/Writing%20a%20tf2%20broadcaster%20%28Python%29. We will follow the same tutorial.

Open a terminal, browse to your catkin workspace source directory and create the package as indicated in the tutorial:

user:~$ cd catkin_ws/src/
user:~/catkin_ws/src$ catkin_create_pkg learning_tf2 tf2 tf2_ros roscpp rospy turtlesim
Created file learning_tf2/package.xml
Created file learning_tf2/CMakeLists.txt
Created folder learning_tf2/include/learning_tf2
Created folder learning_tf2/src
Successfully created files in /home/user/catkin_ws/src/learning_tf2. Please adjust the values in package.xml.
user:~/catkin_ws/src$ cd learning_tf2
user:~/catkin_ws/src/learning_tf2$ mkdir nodes
user:~/catkin_ws/src/learning_tf2$ touch nodes/turtle_tf2_broadcaster.py
user:~/catkin_ws/src/learning_tf2$ chmod +x nodes/turtle_tf2_broadcaster.py
user:~/catkin_ws/src/learning_tf2$ mkdir launch
user:~/catkin_ws/src/learning_tf2$ touch launch/start_demo.launch
user:~/catkin_ws/src/learning_tf2$

Step 3: Add Python code and launch file for launching the tf2 broadcaster Python node

Open the IDE, locate the file turtle_tf_broadcaster.py file and paste in the following code:

#!/usr/bin/env python  
import rospy

# Because of transformations
import tf_conversions

import tf2_ros
import geometry_msgs.msg
import turtlesim.msg


def handle_turtle_pose(msg, turtlename):
    br = tf2_ros.TransformBroadcaster()
    t = geometry_msgs.msg.TransformStamped()

    t.header.stamp = rospy.Time.now()
    t.header.frame_id = "world"
    t.child_frame_id = turtlename
    t.transform.translation.x = msg.x
    t.transform.translation.y = msg.y
    t.transform.translation.z = 0.0
    q = tf_conversions.transformations.quaternion_from_euler(0, 0, msg.theta)
    t.transform.rotation.x = q[0]
    t.transform.rotation.y = q[1]
    t.transform.rotation.z = q[2]
    t.transform.rotation.w = q[3]

    br.sendTransform(t)

if __name__ == '__main__':
    rospy.init_node('tf2_turtle_broadcaster')
    turtlename = rospy.get_param('~turtle')
    rospy.Subscriber('/%s/pose' % turtlename,
                     turtlesim.msg.Pose,
                     handle_turtle_pose,
                     turtlename)
    rospy.spin()

Also, find the start_demo.launch file and paste in the given code:

<launch>
      <node pkg="turtlesim" type="turtlesim_node" name="sim"/>
      <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>


    <node name="turtle1_tf2_broadcaster" pkg="learning_tf2" type="turtle_tf2_broadcaster.py" respawn="false" output="screen" >
      <param name="turtle" type="string" value="turtle1" />
    </node>
    <node name="turtle2_tf2_broadcaster" pkg="learning_tf2" type="turtle_tf2_broadcaster.py" respawn="false" output="screen" >
      <param name="turtle" type="string" value="turtle2" /> 
    </node>

  </launch>

Step 4: Compile and run the package

user:~/catkin_ws/src/learning_tf2$ cd
user:~$ cd catkin_ws/
user:~/catkin_ws$ catkin_make

After that is done, then:

user:~/catkin_ws$ roslaunch learning_tf2 start_demo.launch

You should now see the classical turtle. In order to see the Turtle on ROSDS, go to

  • Tools -> Graphical Tools. (PS: In case it does not appear well, you can use the Resize opened app button to resize the screen).

Now, use the tf_echo tool to check if the turtle pose is actually getting broadcast to tf2. Open another terminal and run:

user:~$ rosrun tf tf_echo /world /turtle1

This should show you the pose of the first turtle. Drive around the turtle using the arrow keys (make sure your terminal window is active, not your simulator window), and you should see these values change.

Ok now, we are done, right? No, we are not! We need to find out what was wrong with the user’s code.

Step 5: Break the Python code so that we can help the user find out the problem with their code!

Yes, really. If you haven’t broken something you probably haven’t learned much, they say! So now let’s break the Python code so we can find out why the user’s code did not run:

  • Remove the very first line of the turtle_tf_broadcaster.py file that reads #!/usr/bin/env python and save it.
  • Now try to launch the node again: stop the current launch command using Ctrl + C and then launch it again:
# Ctrl + C to stop the current one
user:~/catkin_ws$ roslaunch learning_tf2 start_demo.launch

Now we have the following ugly error that the user had:

“`

Unable to launch [turtle1_tf2_broadcaster-4].
If it is a script, you may be missing a ‘#!’ declaration at the top.
The traceback for the exception was written to the log file

“`

The moral: Don’t tamper with that “shebang” at the top of a python script – it’s what identifies it as an executable python script.

Yep, we are done now. I hope that you were able to learn one or two things from this post.

PS: Don’t forget to restore the shebang line 🙂

Extra: Video of this post

We made a video showing how we create a package for broadcasting tf2 between two frames and how we found out the problem with the user’s code. If you prefer “sights and sounds” to “black and white”, here you go:

Feedback

Did you like this post? Do you have any questions about the explanations? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.

If you want to learn about other ROS or ROS2 topics, please let us know in the comments area and we will do a video or post about it.

#ROStutorials #tf #TF #ROS #Robot #Broadcaster #Python


Edited by Bayode Aderinola

[ROS Beginner Mistakes] – 1. Missing execute permission on the Python file

[ROS Beginner Mistakes] – 1. Missing execute permission on the Python file

In this short post, we will show how to avoid a very common mistake most ROS beginners make: missing execute permission on the Python file.

Step 1: Create a Project (ROSject) on ROSDS

Head to http://rosds.online and create a project with a similar configuration as the one shown below. You can change the details as you like, but please make sure you select “Ubuntu 16.04 + ROS Kinetic + Gazebo 7” under “Configuration”.

Once done with that, open your ROSject. This might take a few moments, please be patient.

Step 2: Create a ROS package with a Python program

Pick a Shell from the Tools menu and create a Python package.

user:~$ cd catkin_ws/
user:~/catkin_ws$ cd src
user:~/catkin_ws/src$ catkin_create_pkg missing_permission
Created file missing_permission/package.xml
Created file missing_permission/CMakeLists.txt
Successfully created files in /home/user/catkin_ws/src/missing_permission. Please adjust the values in package.xml.
user:~/catkin_ws/src$ cd missing_permission/
user:~/catkin_ws/src/missing_permission$ mkdir -p src/
user:~/catkin_ws/src/missing_permission$ cd src
user:~/catkin_ws/src/missing_permission/src$ touch missing_perm.py
user:~/catkin_ws/src/missing_permission/src$

Fire up the IDE from the Tools menu, find the missing_perm.py file in the missing_permission package, open the file and paste the following code into it.

#! /usr/bin/env python
import rospy

rospy.init_node("Obiwan")
rate = rospy.Rate(2)
while not rospy.is_shutdown():
    print "Help me Obi-Wan Kenobi, you're my only hope"
    rate.sleep()

Save().

Step 3: Compile and source the workspace.

cd ~/catkin_ws
catkin_make
source devel/setup.bash

Step 4: Run the package with rosrun and roslaunch.

First, we check that the package has been recognized, with rospack list. Then we run it with rosrun.

user:~/catkin_ws$ rospack list | grep missing
missing_permission /home/user/catkin_ws/src/missing_permission
user:~/catkin_ws$ rosrun missing_permission missing_perm.py
[rosrun] Couldn't find executable named missing_perm.py below /home/user/catkin_ws/src/missing_permission
[rosrun] Found the following, but they're either not files,
[rosrun] or not executable:
[rosrun]   /home/user/catkin_ws/src/missing_permission/src/missing_perm.py
user:~/catkin_ws$

The program did not run! What’s that error? Surely that not what we expected. Maybe rosrun does not like us – let’s try roslaunch!

Create a launch file and use it to launch the python program:

user:~/catkin_ws$ cd src/missing_permission/
user:~/catkin_ws/src/missing_permission$ mkdir -p launch
user:~/catkin_ws/src/missing_permission$ cd launch
user:~/catkin_ws/src/missing_permission/launch$ touch missing_perm.launch
user:~/catkin_ws/src/missing_permission$

Open the launch file in the IDE and paste in the following code:

<launch>
    <node name="missing_permission_ex" pkg="missing_permission" type="missing_perm.py" output="screen" />
</launch>

Launch!

user:~/catkin_ws/src/missing_permission$ cd ~/catkin_ws
user:~/catkin_ws$ source devel/setup.bash
user:~/catkin_ws$ roslaunch missing_permission missing_perm.launch
... logging to /home/user/.ros/log/e3188a2e-e921-11e9-8ac1-025ee6e69cec/roslaunch-rosdscomputer-11105.log
...

NODES
  /
    missing_permission_ex (missing_permission/missing_perm.py)

auto-starting new master
process[master]: started with pid [11147]
ROS_MASTER_URI=http://master:11311

setting /run_id to e3188a2e-e921-11e9-8ac1-025ee6e69cec
process[rosout-1]: started with pid [11170]
started core service [/rosout]
ERROR: cannot launch node of type [missing_permission/missing_perm.py]: can't locate node [missing_perm.py] in package [missing_permission]

Oops! It didn’t run again. Now we have another error screaming:

ERROR: cannot launch node of type [missing_permission/missing_perm.py]: can't locate node [missing_perm.py] in package [missing_permission]

What do we do now?

Step 5: Fix the missing execute permission on the Python file and be happy!

user:~/catkin_ws$ cd src/missing_permission/src/
user:~/catkin_ws/src/missing_permission/src$ chmod +x missing_perm.py
user:~/catkin_ws/src/missing_permission/src$

Now let’s try again with both roslaunch and rosrun:

user:~/catkin_ws/src/missing_permission/src$ roslaunch missing_permission missing_perm.launch
...

NODES
  /
    missing_permission_ex (missing_permission/missing_perm.py)

auto-starting new master
process[master]: started with pid [13206]
ROS_MASTER_URI=http://master:11311

setting /run_id to eec6e306-e922-11e9-b72a-025ee6e69cec
process[rosout-1]: started with pid [13229]
started core service [/rosout]
process[missing_permission_ex-2]: started with pid [13242]
Help me Obi-Wan Kenobi, you're my only hope
Help me Obi-Wan Kenobi, you're my only hope
Help me Obi-Wan Kenobi, you're my only hope
...

Running fine with roslaunch. Press Ctrl + C on the roslaunch program and try rosrun:

user:~/catkin_ws/src/missing_permission/src$ rosrun missing_permission missing_perm.py
Unable to register with master node [http://master:11311]: master may not be running yet. Will keep trying.

If you get the error above, please spin another Shell from the Tools menu, and run the following to start the ROS master:

user:~$ roscore

After this, the roscore command should resume and you’ll get:

user:~/catkin_ws/src/missing_permission/src$ rosrun missing_permission missing_perm.py
Unable to register with master node [http://master:11311]: master may not be running yet. Will keep trying.
Help me Obi-Wan Kenobi, you're my only hope
Help me Obi-Wan Kenobi, you're my only hope
Help me Obi-Wan Kenobi, you're my only hope
...

And that was it. As it turned out, roscore had no ill-feeling towards us!

Related Resources

Feedback

Did you like this post? Do you have questions about what was explained? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.

If you want to learn about other ROS or ROS2 topics, please let us know in the comments area and we will do a video or post about it 🙂

 

[ROS Q&A] 196  – How to Output Odometry Data

[ROS Q&A] 196 – How to Output Odometry Data

In this post, you will learn how to access and output odometry data programmatically. More specifically, you will learn how to create a C++ program for subscribing to and printing different parts of the odometry message. This is useful for cases where you need to make a decision based on the robot’s current position.

This post is an answer to the following question found on ROS Answers: https://answers.ros.org/question/333391/way-to-output-odometry-info/.

Let’s get started!

Step 1: Grab the ROS Project (ROSject) on ROSDS

Click here to get a copy of the ROS project used in this post. Next, click open to load the project. Please be patient while the project loads.

Step 2: Launch the necessary tools

  1. Launch a simulation from the Simulations menu.
    • Click on the Simulations menu. A dropdown menu opens.
    • In the section “Launch a provided simulation”, leave the empty world selected and choose the Turtlebot 2 robot.
    • Click “Start simulation”.
  2. Pick a Shell tool from the Tools menu. We’re be firing some commands soon.
  3. Pick the IDE tool from the Tools menu. We’ll use this to examine the code used for solving this problem.

Step 3: Examine the structure of the Odometry message using the command line

Run the following command on the Shell tool to print the current odometry of the robot:

# The -n1 switch to the command to ensure it prints one command and exits. 
# Otherwise, it would print continuously until you press Ctrl + C.
user:~$ rostopic echo /odom -n1
header:
  seq: 4732
  stamp:
    secs: 236
    nsecs: 935000000
  frame_id: "odom"
child_frame_id: "base_footprint"
pose:
  pose:
    position:
      x: 0.00211759816401
      y: 4.81456536954e-05
      z: -0.000247189070632
    orientation:
      x: 0.000385225477218
      y: -0.00721104301471
      z: 0.000107238788561
      w: 0.99997392014
  covariance: [1e-05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-05, 0.0,0.0, 0.0, 0.0, 0.0, 0.0, 1000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.001]
twist:
  twist:
    linear:
      x: -0.000279472699265
      y: -4.17203978095e-05
      z: 0.0
    angular:
      x: 0.0
      y: 0.0
      z: -7.05905617719e-06
  covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
---

The command line output above shows the parts the make up an odometry message. The hottest part is pose, which tells us the current position of the robot. twist is also important, because it tells us the current message being published to move the robot.

Now let’s see how to access and output odometry data, considering the hottest part.

Step 4: See how to access and output odometry data in code

Switch to the IDE tool and locate the catkin_ws directory. You should find a C++ file in a package odom_subscriber. The full path to the file is catkin_ws/src/odom_subscriber/src/odom_sub.cpp.

Let’s see the content of this file:

#include <nav_msgs/Odometry.h> // Needed for accessing Odometry data
#include <ros/ros.h>           // Needed for creating the node, etc

// This functions get called when a new odometry message gets to the subscriber
// It automatically gets the odometry message as a parameter
// It prints out various parts of the message
void counterCallback(const nav_msgs::Odometry::ConstPtr &msg) {
  // ROS_INFO("%s", msg->header.frame_id.c_str());
  // ROS_INFO("%f", msg->twist.twist.linear.x);
  ROS_INFO("%f", msg->pose.pose.position.x);
}

int main(int argc, char **argv) {
  // Create a node to run the code
  ros::init(argc, argv, "odom_sub_node");
  ros::NodeHandle nh;

  // create a subscriber to the "/odom" topic so we can get the odometry message
  ros::Subscriber sub = nh.subscribe("odom", 1000, counterCallback);
  
  // Run program until manually stopped
  ros::spin();

  return 0;
}

I have added comments to the code to explain what each line or code block does, for better clarity.

The `counterCallback` function prints out the current x position of the robot. Observe how parts of the message are accessed in hierarchical format; using the structure in Step 3 as a guide, you can access and output any part of the Odometry message. 

You can uncomment the commented parts to print out parts of the header and twist messages or even write other statements that print out other parts of the message!

Step 5: Move the robot and see the odometry data printed in real-time!

Run the C++ program in the shell, to print out the current x position of the robot. We can see the robot is basically at the “origin” and is stationary. Leave this program running.

user:~$ rosrun odom_subscriber odom_sub_node
[ INFO] [1575339924.601377783, 49.183000000]: 0.000240
[ INFO] [1575339924.651682994, 49.233000000]: 0.000240
...

Pick another Shell tool from the tools menu and run a command to move the robot:

user:~$ rostopic pub /cmd_vel geometry_msgs/Twist "linear:
  x: 0.2
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0"
publishing and latching message. Press ctrl-C to terminate

Now you should see the robot moving. You should also see that the Odometry data being output in the other shell is changing.

In the second Shell, press Ctrl + C to stop the current program. Then publish the following message to stop the robot. After this, you should see the odometry position data become static again.

user:~$ rostopic pub /cmd_vel geometry_msgs/Twist "linear:
  x: 0.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0"
publishing and latching message. Press ctrl-C to terminate

Ant that was it!

Extra: Video

Prefer to watch a video demonstrating the steps above? We have one for you below!

Related Resources and Further Learning

If you are a ROS beginner and want to learn ROS basics fast, we recommend you take any of the following courses on Robot Ignite Academy:

Feedback

Did you like this post? Do you have questions about what is explained? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.

If you want to learn about other ROS topics, please let us know in the comments area and we will do a video or post about it.

Edited by Bayode Aderinola


#ROStutorials #Odometry #ROSsubscriber #ROS #Robot #C++

What is ROS?

What is ROS?

INTRODUCTION TO ROBOT OPERATING SYSTEM (ROS)

If you are reading this, it is because you either are or you want to become a ROS developer. Basically a ROS developer is somebody who wants to build programs for robots based on ROS. Yeah, but what is ROS? How can I learn ROS? How can I start developing with it? What is the most optimal development environment for it? All those questions will be answered in the following pages. But before we start with the practical things, let’s answer some basic questions about what ROS is and why it can be the door through which you can become a developer for robots.

WHY ARE THERE NOT ENOUGH DEVELOPERS FOR ROBOTICS?

In general, software developers do not like to deal with hardware. It is very likely that you are a developer and never thought about entering the robotics realm. You probably think that by programming for robots, you would need to know about electronics and maybe even mechanics. You probably think that hardware and software are too coupled in robots, and that you cannot touch one thing without touching the other. For example, some years ago, I had to make the navigation system for a robot. However, our navigation program was not working at all. We thought that it was something wrong with the program, but after extensive review, we found that it actually was a problem with the electronics of the laser scanner that we used to localize the robot. There were some micro-interruptions in the voltage level that made the laser reboot. In order to find that error, we had to go to the basics and find where the problem within the physical laser was. For that, you need to mess with the electronics. You have to take the laser out of the robot, put it on your table, and start experimenting. Different voltages, different interruptions to the power, all in order to try to reproduce the effect in a controlled environment. That is a lot of interaction with the hardware.
Interaction with hardware is something that many software developers don’t like. After all, they decided to become developers of software, not hardware!!

ROBOTICISTS PROGRAMMING ROBOTS

Due to that, the programming of robots has been done by roboticists, who are the people that build the robots. Maybe some of them are not directly involved in the creation of the robot, but definitely they have no problem getting into the hardware and trying to fix some hardware problems, in order to make their program work. But let’s face it, most roboticists are better developers than programmers. That is why robotics could benefit so much from having lots of expert programmers coming to the field. The good news is that getting developers into the field is more possible than ever. Thanks to the Robot Operating System, ROS, you can completely abstract the hardware from the software, so you can program a robot just by knowing the robot ROS API. By using the ROS API, you can forget about the hardware and just concentrate on the software that makes the robot do what you want.

WHAT IS THE ROBOT ROS API?

The ROS API is the list of ROS topics, services, action servers, and messages that a given robot is providing to give access to its hardware, that is, sensors and actuators. If you are not familiar with ROS, you may not understand what those terms mean. But simply put in the developers’ language, topics/services/messages are like the software functions you can call on a robot to get data from the sensors or make the robot take action. It also includes the parameters you can pass on to those functions. Most modern robot builders are providing off-the-shelf ROS APIs, like for example, ROS- Components shop that provides all its hardware running with a ROS API. If the robot you want to work with does not run ROS, you can still make the robot work with ROS by ROSifying it. To ROSify means to adapt your robot to work with ROS. To ROSify a robot usually requires knowledge to access the hardware. You need to learn how to communicate with the electronics that provide the sensor data or access the motors of the robot. In this series of ROS tutorials, we are not dealing with that subject because it gets out of scope for developers. But if you are interested in this topic, you can learn more about it in this Robot Creation Course.
So for the rest of the tutorials, we will assume that you have access (or are willing to have access) to a robot that is ROSified.

WHAT IS ROS ANYWAY?

ROS stands for Robot Operating System. Even if it says so, ROS is not a real operating system since it goes on top of Linux Ubuntu. ROS is a framework on top of the O.S. that allows it to abstract the hardware from the software. This means you can think in terms of software for all the hardware of the robot. And that’s good news for you because this implies that you can actually create programs for robots without having to deal with the hardware. Yeah!

ROS FOR SERVICE ROBOTS

ROS is becoming the standard in robotics programming, at least in the service robots sector. Initially, ROS started at universities, but quickly spread into the business world. Every day, more and more companies and startups are basing their businesses in ROS. Before ROS, every robot had to be programmed using the manufacturer’s own API. This means that if you changed robots, you had to start the entire software again, apart from having to learn the new API. Furthermore, you had to know a lot about how to interact with the electronics of the robot in order to understand how your program was doing. The situation was similar to that of computers in the 80s, when every computer had its own operating system and you had to create the same program for every type of computer. ROS is for robots like Windows is for PCs, or Android for phones. By having a ROSified robot, that is, a robot that runs on ROS, you can create programs that can be shared among different robots. You can build a navigation program, that is a program to make a robot move around without colliding, for a four-wheeled robot built by company A and then use the same exact code to move a two-wheeled robot built by company B… or even use it on a drone from company C.

SOME COMMONLY ASKED QUESTIONS

Which operating system should be used with ROS?

ROS works on Linux Ubuntu or Linux Debian. Experimental support already exists for OSX and Gentoo, and a version for Windows in underway, but we really don’t recommend for you to use them yet, unless you are an expert. Check this page for more information about how to use ROS on those systems. If you don’t know how to work with Linux, I recommend you start with this free Linux for Robotics course.

HOW TO DEVELOP FOR ROBOTS WITH ROS

Now, if you are convinced you want to become a robotics developer, in this series of ROS tutorials, you are going to find the steps that you can take to become a ROS developer. We have divided the tutorial series into the following sections that should cover the whole development process: • Setting Up • Learning • Coding • Testing Let’s go, one by one. [irp posts=”14751″ name=”ROS for Beginners: How to Learn ROS”] To access the full guide, click the orange button below, or go to RobotIgniteAcademy.com.
Download ROS Developers Guide
[ROS Q&A] 195 – How to know if robot has moved one meter using Odometry

[ROS Q&A] 195 – How to know if robot has moved one meter using Odometry

Learn how to know if the robot has moved one-meter using Odometry.  You’ll learn how to:

  • create a Python program for calculating the distance moved by the robot using the Odometry topic and publish it into a topic.
  • create a Python program for testing that we can move the robot depending on the Odometry data.

Let’s go!


Related Resources


Step 1: Get your development environment ready and grab a copy of the code

  1. Click here to grab a copy of the ROSject already containing the project. This requires an account on the ROS Development Studio (ROSDS), an online platform for developing for ROS within a PC browser. If you don’t have an account, you will be asked to create one.
  2. To open a “terminal” on ROSDSpick the Shell app from the Tools menu.
  3. You can find the IDE app on the Tools menu.

Step 2: Start a Simulation

We are going to use the TurtleBot 2 simulation.

  1. Click on Simulations from the main menu.
  2. Under Launch a provided simulation, leave “Empty world” selected and click on Choose a robot.
  3. Type “turtle” into the search box and select TurtleBot 2.
  4. Click Start Simulation.
  5. A window showing the TurtleBot 2 in an empty world should show up.

Launch a provided sim

Step 3: Examine the structure of Odometry messages

Let’s see the structure of an Odom message. Open a terminal and run:

user:~$ rostopic echo /odom -n1
header:
  seq: 14929
  stamp:
    secs: 748
    nsecs: 215000000
  frame_id: "odom"
child_frame_id: "base_footprint"
pose:
  pose:
    position:
      x: 0.00668370211388
      y: 0.00010960687178
      z: -0.000246865753431
    orientation:
      x: 0.000389068511716
      y: -0.00720626927928
      z: 0.000354481463316
      w: 0.999973895985
  covariance: [1e-05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1000000000000.0, 0.0, 0.0, 0.0, 0.0,0.0, 0.0, 1000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1000000000000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.001]
twist:
  twist:
    linear:
      x: 2.30945682841e-05
      y: 0.000390977104083
      z: 0.0
    angular:
      x: 0.0
      y: 0.0
      z: -0.000507764995516
  covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
---

The part of the message that stores the current position of the robot is the pose.pose.position:

user:~$ rostopic echo /odom -n1
# ...
pose:
  pose:
    position:
      x: 0.00668370211388
      y: 0.00010960687178
      z: -0.000246865753431
# ...

This part is what is used in the Python script that calculates the distance moved.

Step 4: Understand the Python scripts

1. Open the IDE and browse to the src folder. You will find two packages odom_movement_detector and test_movement. Each of these projects contains a Python script, each explained with comments in the code

odom_movement_detector/src/odom_movement_detector.py

#!/usr/bin/env python

import rospy
import math
from nav_msgs.msg import Odometry
from geometry_msgs.msg import Point
from std_msgs.msg import Float64

class MovementDetector(object):
    def __init__(self):
        """Initialize an object of the MovementDetector class."""
        # _mved_distance is for stored distance moved
        # create and initialize it here. Initial value is 0.0
        self._mved_distance = Float64()
        self._mved_distance.data = 0.0

        # Get the inital position. This will be a reference point for calculating
        # the distance moved 
        self.get_init_position()

        # Create a publisher for publishing the distance moved into the topic '/moved_distance'
        self.distance_moved_pub = rospy.Publisher('/moved_distance', Float64, queue_size=1)

        # create a subscriber for getting new Odometry messages
        rospy.Subscriber("/odom", Odometry, self.odom_callback)

    def get_init_position(self):
        """Get the initial position of the robot."""
        """
        Structure of the odom position message:
        user:~$ rostopic echo /odom -n1
        header:
        seq: 14929
        stamp:
            secs: 748
            nsecs: 215000000
        frame_id: "odom"
        child_frame_id: "base_footprint"
        pose:
        pose:
            position:
            x: 0.00668370211388
            y: 0.00010960687178
            z: -0.000246865753431
        """
        data_odom = None
        # wait for a message from the odometry topic and store it in data_odom when available
        while data_odom is None:
            try:
                data_odom = rospy.wait_for_message("/odom", Odometry, timeout=1)
            except:
                rospy.loginfo("Current odom not ready yet, retrying for setting up init pose")
        
        # Store the received odometry "position" variable in a Point instance 
        self._current_position = Point()
        self._current_position.x = data_odom.pose.pose.position.x
        self._current_position.y = data_odom.pose.pose.position.y
        self._current_position.z = data_odom.pose.pose.position.z

    def odom_callback(self, msg):
        """Process odometry data sent by the subscriber."""
        # Get the position information from the odom message
        # See the structure of an /odom message in the `get_init_position` function
        NewPosition = msg.pose.pose.position

        # Calculate the new distance moved, and add it to _mved_distance and 
        self._mved_distance.data += self.calculate_distance(NewPosition, self._current_position)
        
        # Update the current position of the robot so we have a new reference point
        # (The robot has moved and so we need a new reference for calculations)
        self.updatecurrent_positin(NewPosition)
        
        # If distance moved is big enough, publish it to the designated topic
        # Otherwise publish zero
        if self._mved_distance.data < 0.000001:
            aux = Float64()
            aux.data = 0.0
            self.distance_moved_pub.publish(aux)
        else:
            self.distance_moved_pub.publish(self._mved_distance)

    def updatecurrent_positin(self, new_position):
        """Update the current position of the robot."""
        self._current_position.x = new_position.x
        self._current_position.y = new_position.y
        self._current_position.z = new_position.z

    def calculate_distance(self, new_position, old_position):
        """Calculate the distance between two Points (positions)."""
        x2 = new_position.x
        x1 = old_position.x
        y2 = new_position.y
        y1 = old_position.y
        dist = math.hypot(x2 - x1, y2 - y1)
        return dist

    def publish_moved_distance(self):
        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()

if __name__ == '__main__':
    # create a node for running the program
    rospy.init_node('movement_detector_node', anonymous=True)

    # create an instance of the MovementDetector class and set the code
    # in motion
    movement_obj = MovementDetector()
    movement_obj.publish_moved_distance()

test_movement/src/test_movement.py

#!/usr/bin/env python

import rospy
from geometry_msgs.msg import Twist
from std_msgs.msg import Float64

def my_callback(msg):
    """Callback function that processes messages from the subscriber."""

    # get the distance moved from the message
    distance_moved = msg.data

    # If distance is less than 2, continue moving the robot
    # Otherwise, stop it (by pubishing `0`)
    if msg.data < 2:
        move.linear.x = 0.1

    if msg.data > 2:
        move.linear.x = 0

    pub.publish(move)

# create a node for running the program
rospy.init_node('test_movement')

# create a subscriber that gets the distance moved
sub = rospy.Subscriber('/moved_distance', Float64, my_callback)

# Create a publisher that moves the robot
pub = rospy.Publisher('/cmd_vel', Twist, queue_size="1")

# Create a global variable for publising a Twist ("cmd_vel") message 
move = Twist()

# Keep the program running
rospy.spin()

Step 5: See the Python scripts in action

Open a terminal and run the movement detector:

user:~$ rosrun odom_movement_detector odom_movement_detector.py

Open another terminal and check the distance being published to the /moved_distance:

user:~$ rostopic echo /moved_distance
data: 0.00280330822873
---
data: 0.00280530307334

You can see from above that the distance is not changing (more or less) because the robot is stationary. Now let’s move the robot:

user:~$ rosrun test_movement test_movement.py

Now you should see the robot moving and moved_distance increasing. It should stop when moved_instance > 2.0.

user:~$ rostopic echo /moved_distance
data: 0.00280330822873
---
data: 0.00280330822873
---
data: 0.00280330822873
---
data: 0.00280330822873
---
data: 0.00280330822873
---
# ...
data: 1.00280330822873
---
# ...
data: 2.00280330822873
---

And that’s it. I hope you had some fun!

Extra: Video of the post

Here below you have a “sights and sounds” version of this post, just in case you prefer it that way. Enjoy!

Feedback

Did you like this post? Do you have any questions about the explanations? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.

If you want to learn about other ROS or ROS2 topics, please let us know in the comments area and we will do a video or post about it.


Edited by Bayode Aderinola

Pin It on Pinterest