[ROS in 5 mins] 024 – How to compile a ROS  Message

[ROS in 5 mins] 024 – How to compile a ROS Message

 

Hello ROS Developers!

In today’s video we are going to learn how to compile a ROS Message.

For that we are going to use Robot Ignite Academy, which is the best tool if you want Learn ROS Fast.

Before we start, if you are new to ROS and want to Learn ROS Fast, I highly recommend you to take any of the following courses on Robot Ignite Academy:

We love feedback, so, whether you like the video or not, please share your thoughts on the comments section below.

Step1. Create a project in Robot Ignite Academy(RIA)

We have the best online ROS course available in RIA. It helps you learn ROS in the easiest way without setting up ROS environment locally. The only thing you need is a browser! Create an account here and start to browse the trial course for free now! We’ll use the ROS Basic in 5 days course unit 4 as an example today.

Step2. Create a package

We’ll create a package for our code with the following command.

cd ~/catkin_ws/src
catkin_create_pkg financial_market rospy

We also need one folder for our message definition

cd financial_market
mkdir msg

Let’s call our message SharePrice.msg with the following definition

string name
float32 price

In the package.xml file, please uncomment the following part.

...
  <build_depend>message_generation</build_depend>
...
  <run_depend>message_runtime</run_depend>
...

In the CMakeLists.txt, change the following part to compile the message.

...
find_package(catkin REQUIRED COMPONENTS
  rospy
  std_msgs
  message_generation
)
...
add_message_files(
   FILES
   SharePrice.msg
#   Message2.msg
)
...
generate_messages(
   DEPENDENCIES
   std_msgs  # Or other packages containing msgs
)
...
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES my_sense_package
  CATKIN_DEPENDS rospy message_runtime
#  DEPENDS system_lib
)
...

Then we compile the message with the following command

cd ~/catkin_ws
catkin_make

Please source the file after compile.

source devel/setup.bash

You can then check the message with

rosmsg info financial_market/SharePrice

In your python code, you can then add from financial_market.msg import SharePrice  to use the message.

Want to learn more?

If you are interested in this topic, please check our ROS Basics In 5 Days (Python) course. You’ll learn how to create service and action message in ROS as well.

 

Edit by: Tony Huang

[ROS in 5 mins] 023 – Understanding ROS Coordinate Frame (Part 1)

[ROS in 5 mins] 023 – Understanding ROS Coordinate Frame (Part 1)

 

How does your robot know which way is forward? Is it in the x-axis, or y-axis? Positive or negative?

In this video we are going to look at the convention for coordinate frames. This convention is specified in REP 103 – Standard Units of Measure and Coordinate Conventions. In this part 1, we will look at the coordinate frame for linear motion.

RELATED LINKS

REP 103
ROS Development Studio (ROSDS)
Robot Ignite Academy

Step 1. Create a project in ROS Development Studio(ROSDS)

According to the REP03 standard, the positive x means forward, the positive y means left and positive z means up. Although you can check the REP03 standard with your hand, it’s better to see how it works in ROS. The ROSDS helps you follow our tutorial in a fast pace without dealing without setting up an environment locally. If you haven’t had an account yet, you can create a free account here. Let’s launch a AR Drone simulation from Simulations->AR.Drone.

Step 2. Check it with the command

You can publish to the cmd_vel topic to move the drone with the following command.

rostopic pub -1 /cmd_vel [TAB] [TAB]

When you press tab while typing the command, ROS will do auto-compilation for you. You can see that it directly find the message type is called geometry msgs/Twist and there are linear x y z and angular x y x value in this message. To check it, change the value of linear x to some positive value. The drone will move forward like the REP03 standard said. You can also send to the linear y and z to check if it’s true. In the next post. We will talk about the angular part.

Want to learn more?

If you want to learn more about ROS, please check our Robot Ignite Academy.

 

Edit by: Tony Huang


Feedback

Did you like this video? 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 on the comments area and we will do a video about it.

Movelt! Camp: Learning Movelt! with Sawyer robot in 5 weeks!

Movelt! Camp: Learning Movelt! with Sawyer robot in 5 weeks!

movelt! camp

In this series of videos we are going to learn how to use MoveIt! package with industrial robots. In this series we are going to use the Sawyer robot by Rethink Robotics.

Remember that you can follow all the steps with us at the same time by using the ROS Development Studio, without having to install anything in your system, and by using any operating system (yes, you can learn ROS with Windows!!!). The instructions and steps provided here can be also made in your local computer with a proper installation of ROS.

[Movelt! Camp] Week 1: Get the Robot up and running.

In the first week of Movelt! Camp, we will learn how to get the Sawyer simulation up and running.

Step 0. Create a project in ROS Development Studio(ROSDS)

ROSDS helps you follow our tutorial in a fast pace without dealing without setting up an environment locally. If you haven’t had an account yet, you can create a free account here. Let’s create a new project and call it sawyer_simulation.

Step 1. Clone and compile the simulation

You can find the Sawyer simulation in this github repo. Inside ROSDS, we put all the packages related to simulation to the simulation_ws.  So, let’s clone the repo into it and compile.

cd ~/simulation_ws/src
git clone https://github.com/RethinkRobotics/sawyer_simulator.git
cd ~/simulation_ws/src
ws_tool init .
wstool merge sawyer_simulator/sawter_simulator.rosinstall
wstool updatecd
cd ~/simulation_ws
catkin_make

Step 2. Run the simulation

You can now launch the simulation from Simulations->select launch file->sawyer_pick_and_place_demo.launch. You should see the sawyer robot and a desk in the simulation window now.

 

RELATED LINKS

▸ You can launch the simulation at ROS Development Studio

▸ A git repo with the Sawyer simulation

Simulation installation instructions

Online course about how to learn to do ROS manipulation in 5 days

 

 

[Movelt! Camp] Week 2: Create the Movelt! package for Robot.

In the second week, you will learn how to create the MoveIt! configuration package for Sawyer the robot, using the moveit_setup_assistant

Step 3. Reconfigure the gripper

To use the gripper in our simulation, we need to modify the sawyer.urdf.xarco file under the ~/simulaiton_ws/src/sawyer_robot/sawyer_description/urdf folder. Please change both the gazebo and electric_gripper tags to true.

In this video, we’ll use another simulation called sawyer_world. We also need to configure it. You can find the launch file sawyer_world.launch under the ~/simulation_ws/src/sawyer_simulator/launch folder. Remember to change the electric_gripper  tag to true.

Then we can finally launch the simulation from Simulations->select launch file->sawyer_world.launch.

To check if the simulation works properly, let’s try to move the joint by sending a command to the /robot/right_joint_position_controller/joints/right_j1_controller/command topic with the following command.

rostopic pub -1 /robot/right_joint_position_controller/joints/right_j1_controller/command std_msgs/Float64 "data: 1.0"

You should see the robot moves a little, so the simulation is working properly.

It’s not practical if we need to send command ourselves everytime we want to move the robot. We can use the moveit package to simplify the process for us. To configure it, we can use a graphical tool provided by moveit with the following command.

rosrun moveit_setup_assistant moveit_setup_assistant

Then go tho the Tools->graphical tool and select the urdf file we just defined.

Then, in the next page, we generate the collision matrix using the default value.

In the planning group page, let’s click add group and fill the group name as right_arm and select kdl solver, then click add joint.

Then select the joints as the following image

We also need one additional group called right_gripper

In the robot pose page, please set up a pose called tesing_pose for testing. You can choose any value you want.

In the end_effector page, please select the links as following image.

The last step is to generate the moveit package, let’s put it in a new folder called sawyer_moveit_config under the catkin_ws/src

Step 4. Use the moveit package

Now you can launch the package with the following command

roslaunch sawyer_moveit_config demo.launch

In the graphical tool, you should see the moveit, but it’s on a weird position. Please type the following command in a new shell to recenter the window.

wmctrl -r :ACTIVE: -e 0,65,24,1500,550

Then we can test the moveit package with our testing_pose

You should see the shadow of the robot move in the rviz tool. Then you can click plan to plan the trajectory move from the current state to the goal state- testing pose. Then you can click execute to execute the planned trajectory. How ever, this won’t move the robot in the gazebo simulation. We’ll talk about this in then next video.

 

RELATED LINKS

▸ You can launch the simulation at ROS Development Studio

Online course about how to learn to do ROS manipulation in 5 days, including grasping.

ROS Manipulation is the term used to refer to any robot that manipulates something in its environment.
The main goal of this Course is to teach you the basic tools you need to know in order to be able to understand how ROS Manipulation works, and teach you how to implement it for any manipulator robot.

 

 

[Movelt! Camp] Week 3: How to connect your MoveIt Setup with a Real/ Simulated Robot.

For this week, we will be looking at how you can connect your MoveIt Setup from “MoveIt Camp: Week 2” to a Real/ Simulated Robot running ROS.

Step 5. Controller configuration

In order to move the robot in the gazebo simulation, we have to configure the controller. We can create a controller config file called controller.yaml file under the catkin_ws/src/sawyer_moveit_config folder with the following content

controller_list:
    - name: /robot/limb/right
      avtion_ns: follow_joint_trajectory
      type: FollowJointTrajectory
      default: true
      joints:
        - right_j0
        - right_j1
        - right_j2
        - right_j3
        - right_j4
        - right_j5
        - right_j6

We also need one launch file to launch the controller and one for the connection. We can use the sawyer_moveit_controller_manager.launch.xml file that moveit prepared for us in the sawyer_moveit_config/launch folder and modify the content as the following.

<launch>
    <!-- Set the param that trajectory_execution_manager needs to find the controller plugin -->
    <arg name="moveit_controller_manager" default="moveit_simple_controller_manager/MoveItSimpleController"
    <param name="moveit_controller_manager" value="$(arg moveit_controller_manager)" />
    <!-- The rest of the params are specific to this plugin -->
    
    <!-- If a controller manager is running (the generic one, not the MoveIt! one>
    <arg name="controller_manager_name" default="simple_controller_manager" />
    <param name="controller_manager_name value="$(arg controller_manager_name)" />
    
    <!-- Flag indicating whether the controller manager should be used or not -->
    <arg name="use_controller_manager" default="true" />
    <param name="use_controller_manager" value="$(arg use_controller_manager)" />
    
    <!-- load controller_list and controller_manager_ns -->
    <rosparam file="$(find sawyer_moveit_config)/config/controllers.yaml"/>
</launch>

Another launch file we need is for the connection. We name it my_connect.launch with the following content

<launch>
    <arg name="config" default="true"/>
    <arg name="rviz_config" default="$(find sawyer_moveit_config)/launch/moveit.rviz" />
    
    <arg name="electric_gripper" default="true" />
    <arg name="tip_name" if="$(arg electric_gripper)" default="right_gripper_tip"/>
    <arg name="tip_name" unless="$(arg electric_gripper)" default="right_hand"/>
    
    <!-- Add planning context launch file -->
    <include file="$(find sawyer_moveit_config)/launch/planning_context.launch">
        <arg name="load_robot_description" value="false"/>
        <arg name="electric_gripper" value="true"/>
        <arg name="tip_name" value="$(arg tip_name"/>
    </include>
    
    <include file="$(find sawyer_moveit_config)/launch/move_group.launch">
        <arg name="allow_trajectory_execution" value="true"/>
        <arg name="fake_execution" value="false"/>
        <arg name="info" value="$(arg electric_gripper)"/>
    </include>
    
    <include file="$(find sawyer_moveit_config)/config/launch/moveit_rviz.launch">
        <arg name="config" value="$(arg config)" />
        <arg name="rviz_config" value="$(arg rviz_config)" />
    </include>
    
</launch>

Step 6. Bring up the controller

Let’s start by lanch the trajectory action server of the robot with the following command

source ~/simulation_ws/devel/setup.bash
rosrun rosrun intera_interface joint_trajectory_action_server.py

Then run the moveit package again with the controller.

roslaunch sawyer_moveit_config my_connect.launch

Try to plan the trajectory and execute again, you should see the robot move while executing the trajectory.

Then you should go to the moveit interface from Tools->Graphical tool. Please use the following commend to reconfigure the window.

wmctrl -r :ACTIVE: -e 0,65,24,1500,550

 

 

[Movelt! Camp] Week 4: MoveIt Planning Interface: Obstacles in the robot workspace and how to avoid them.

The Robot workspace can get cluttered and it most certainly is 90% of the time. As a result, it is necessary for the Robot to know its workcell in order to allow it to effect and or plan reachable goals.  This week, we will focus on the MoveIt Planning Interface and how to send goal(s) and also make and execute a calculated plan(s).

Step 7. Some changes

We’ll start using the demo.launch file to launch the project. Please change the following part.

line 32: <rosparam param=”/source_list”>[/robot/joint_states]</rosparam>

line 41: <arg name=”fake_execution” value=”false”/>

<launch>

  <!-- By default, we do not start a database (it can be large) -->
  <arg name="db" default="false" />
  <!-- Allow user to specify database location -->
  <arg name="db_path" default="$(find sawyer_moveit_config)/default_warehouse_mongo_db" />

  <!-- By default, we are not in debug mode -->
  <arg name="debug" default="false" />

  <!--
  By default, hide joint_state_publisher's GUI

  MoveIt!'s "demo" mode replaces the real robot driver with the joint_state_publisher.
  The latter one maintains and publishes the current joint configuration of the simulated robot.
  It also provides a GUI to move the simulated robot around "manually".
  This corresponds to moving around the real robot without the use of MoveIt.
  -->
  <arg name="use_gui" default="false" />

  <!-- Load the URDF, SRDF and other .yaml configuration files on the param server -->
  <include file="$(find sawyer_moveit_config)/launch/planning_context.launch">
    <arg name="load_robot_description" value="true"/>
  </include>

  <!-- If needed, broadcast static tf for robot root -->
  

  <!-- We do not have a robot connected, so publish fake joint states -->
  <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
    <param name="/use_gui" value="$(arg use_gui)"/>
    <rosparam param="/source_list">[/robot/joint_states]</rosparam>
  </node>

  <!-- Given the published joint states, publish tf for the robot links -->
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" respawn="true" output="screen" />

  <!-- Run the main MoveIt executable without trajectory execution (we do not have controllers configured by default) -->
  <include file="$(find sawyer_moveit_config)/launch/move_group.launch">
    <arg name="allow_trajectory_execution" value="true"/>
    <arg name="fake_execution" value="false"/>
    <arg name="info" value="true"/>
    <arg name="debug" value="$(arg debug)"/>
  </include>

  <!-- Run Rviz and load the default config to see the state of the move_group node -->
  <include file="$(find sawyer_moveit_config)/launch/moveit_rviz.launch">
    <arg name="config" value="true"/>
    <arg name="debug" value="$(arg debug)"/>
  </include>

  <!-- If database loading was enabled, start mongodb as well -->
  <include file="$(find sawyer_moveit_config)/launch/default_warehouse_db.launch" if="$(arg db)">
    <arg name="moveit_warehouse_database_path" value="$(arg db_path)"/>
  </include>

</launch>

The you can source the file and run the following script to enable the robot

source simulation_ws/devel/setup.bash
rosrun intera_interface enable_robot.py -e
rosrun intera_interface joint_trajectory_action_server.py

Then you can finally launch the demo.launch with

roslaunch sawyer_moveit_config_2 demo.launch

At this point, your simulation should working properly as before.

Step 8. Motion planning with code(in C++)

Let’s start by creating a package for the planning code in catkin_ws.

cd ~/catkin_ws/src
catkin_create_pkg planning roscpp

We’ll create a file called planning.h under the include folder with the following content.

#include <moveit/move_group_interface/move_group_interface.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <string>
#include <vector>
#include <geometry_msgs/Pose.h>
#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/CollisionObject.h>

namespace my_planning
{
    class MyPlanningClass
    {
        public:
            MyPlanningClass(): move_group(PLANNING_GROUP)
            {
                target_pose1.orientation.w = 1.0;
                target_pose1.position.x = 0.38;
                target_pose1.position.y = -0.2;
                target_pose1.position.z = 0.65;

                move_group.allowReplanning(true);
                move_group.setNumPlanningAttempts(10);
            }

            void goToPoseGoal();
            void goToPoseGoal(geometry_msgs::Pose &pose);
            void goToJointState();
            void cartesianPath();
            void resetValues();
            void addObjects();
            void makeBox(std::string blk_name, double *pose);
            void removeObjects();

        private:
            const std::string PLANNING_GROUP = "right_arm";

            moveit::planning_interface::MoveGroupInterface move_group;
            moveit::planning_interface::PlanningSceneInterface virtual_world;
            const robot_state::JointModelGroup* joint_model_group;
            moveit::planning_interface::MoveGroupInterface::Plan my_plan;

            geometry_msgs::Pose target_pose1;
    };
}

This file includes the packages that we need for planning and create several objects. Then we create a planning.cpp file under the src folder with the following content.

#include <planning.h>

namespace my_planning
{
        void MyPlanningClass::goToPoseGoal()
        {
            move_group.setPoseTarget(target_pose1);
            bool success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
            if(!success) //execute
                throw std::runtime_error("No plan found");

            move_group.move(); //blocking
        }
        
        void MyPlanningClass::goToPoseGoal(geometry_msgs::Pose &pose)
        {
            move_group.setPoseTarget(pose);
            ros::Duration(0.5).sleep();
            bool success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
            /*while (!success) //keep trying until a plan is found
            {
                
                success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
            }*/
            
            if(!success) //execute
                throw std::runtime_error("No plan found");

            move_group.move(); //blocking
        }

        void MyPlanningClass::goToJointState()
        {
            robot_state::RobotState current_state = *move_group.getCurrentState();
            //moveit::core::RobotStatePtr current_state = move_group.getCurrentState();
            std::vector<double> joint_positions;
            joint_model_group = current_state.getJointModelGroup(PLANNING_GROUP);
            current_state.copyJointGroupPositions(joint_model_group, joint_positions);
            //joint_positions = move_group.getCurrentJointValues();

            joint_positions[0] = -1.0;
            joint_positions[3] = 0.7;

            move_group.setJointValueTarget(joint_positions);
            bool success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
            if(!success)
                throw std::runtime_error("No plan found");

            move_group.move(); //blocking
        }

        void MyPlanningClass::cartesianPath()
        {
            std::vector<geometry_msgs::Pose> waypoints;
            waypoints.push_back(target_pose1);

            geometry_msgs::Pose target_pose2 = target_pose1;

            target_pose2.position.z -= 0.2;
            waypoints.push_back(target_pose2);

            target_pose2.position.y -= 0.2;
            waypoints.push_back(target_pose2);

            target_pose2.position.z += 0.2;
            target_pose2.position.y += 0.2;
            target_pose2.position.x -= 0.2;
            waypoints.push_back(target_pose2);

            move_group.setMaxVelocityScalingFactor(0.1);

            // We want the Cartesian path to be interpolated at a resolution of 1 cm
            // which is why we will specify 0.01 as the max step in Cartesian
            // translation.  We will specify the jump threshold as 0.0, effectively disabling it.
            // Warning - disabling the jump threshold while operating real hardware can cause
            // large unpredictable motions of redundant joints and could be a safety issue
            moveit_msgs::RobotTrajectory trajectory;
            const double jump_threshold = 0.0;
            const double eef_step = 0.01;
            double fraction = move_group.computeCartesianPath(waypoints, eef_step, jump_threshold, trajectory);

            move_group.move();
            ROS_INFO_STREAM("Percentage of path followed: " << fraction);
        }

        void MyPlanningClass::resetValues()
        {
            //set the start state and operational speed
            move_group.setStartStateToCurrentState();
            move_group.setMaxVelocityScalingFactor(1.0);
        }

         void MyPlanningClass::makeBox(std::string blk_name, double *pose)
         {
             moveit_msgs::CollisionObject box;
            //set the relative frame
            box.header.frame_id = move_group.getPlanningFrame();
            box.id = blk_name;

            shape_msgs::SolidPrimitive primitive;
            primitive.type = primitive.BOX;
            primitive.dimensions.resize(3);
            primitive.dimensions[0] = 0.2;
            primitive.dimensions[1] = 0.2;
            primitive.dimensions[2] = 1.0;

            geometry_msgs::Pose box_pose;
            box_pose.orientation.w = 1.0;
            box_pose.position.x = pose[0];
            box_pose.position.y = pose[1];
            box_pose.position.z = pose[2];

            box.primitives.push_back(primitive);
            box.primitive_poses.push_back(box_pose);
            box.operation = box.ADD;

            std::vector<moveit_msgs::CollisionObject> collisionObjects;
            collisionObjects.push_back(box);
            ros::Duration(2).sleep();
            virtual_world.addCollisionObjects(collisionObjects);
            ROS_INFO_STREAM("Added: " << blk_name);
         }

        void MyPlanningClass::addObjects()
        {
            double box_pose1[3] = {0.60, -0.67, 0.0,};
            makeBox("block_1", box_pose1);

            double box_pose2[3] = {0.0, 0.77, 0.0,};
            makeBox("block_2", box_pose2);
        }

        void MyPlanningClass::removeObjects()
        {
            std::vector<std::string> object_ids;
            object_ids.push_back("block_1");
            object_ids.push_back("block_2");
            virtual_world.removeCollisionObjects(object_ids);
        }
}

Let’s create another file called run.cpp under the src folder with the following content

#include <planning.h>

int main(int argc, char **argv)
{
    ros::init(argc, argv, "custom_interfacing");
    ros::NodeHandle node_handle;
    ros::AsyncSpinner spinner(2);
    spinner.start();

    if(argc != 2)
    {
        ROS_INFO(" ");
        ROS_INFO("\tUsage:");
        ROS_INFO(" ");
        ROS_INFO("\trosrun planning run  n");
        return 1;
    }

    my_planning::MyPlanningClass my_planning_;

    int selection = atoi(argv[1]);
    switch(selection)
    {
        my_planning_.resetValues();

        case 1:
            my_planning_.goToPoseGoal();
            break;
        case 2:
            my_planning_.goToJointState();
            break;
        case 3:
            my_planning_.cartesianPath();
            break;
        case 4:
            my_planning_.addObjects();
            break;
        case 5:
            my_planning_.removeObjects();
    }


    spinner.stop();
    return 0;
}

In order to compile the code, we have to change some parts in the CMakeLists.txt

...
add_definitions(-std=c++11)
...
find_package(catkin REQUIRED COMPONENTS
  roscpp moveit_ros_planning_interface
)
...
catkin_package(
  INCLUDE_DIRS include
  CATKIN_DEPENDS roscpp
)
...
add_executable(run src/run.cpp src/planning.cpp include/planning.h)
target_link_libraries(run ${catkin_LIBRARIES})
...
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

Then you can run compile with

cd ~/catkin_ws
catkin_make
source devel/setup.bash
rospack profile

Then we can run the executable with

rosrun planning run 3

[Movelt! Camp] Week 5: 3D Perception with MoveIt.

So you might have read about or thought of incorporating Point Cloud data into MoveIt. With this being the fifth and final week on MoveIt Camp, let’s do just that. We are going to integrate 3D Perception into MoveIt and also look at some related applications.

 

Tutorial by: Epshon Guakro

Video’s Cover by: Yuhong Lim

Edit by: Tony Huang

[ROS in 5 mins] 022 – What is a ROS publisher?

[ROS in 5 mins] 022 – What is a ROS publisher?

In this post, we will see what a ROS publisher is all about in just about five minutes! We’ll also see how it relates to ROS nodes and topics.

Let’s go!

Step 1: Grab a copy of the Project (ROSject) on ROSDS

Get it here: http://www.rosject.io/l/18f83296-0e7e-4c5c-95a7-2d3e3d6430d4/.

Once you have copied the project, open it up.

Step 2: Run the obiwan_pub.py program

Pick a Shell from the Tools menu and run the following commands.

First, start the ROS master – we need this to run any ROS commands. We’re starting this program in the background:

user:~$ nohup roscore &
[1] 1501
user:~$ nohup: ignoring input and appending output to 'nohup.out'
user:~$

Before we proceed, let’s check the ROS topics currently available:

user:~$ rostopic list
/rosout
/rosout_agg

Now start the obiwan_pub.py program:

user:~$ cd catkin_ws/src
user:~/catkin_ws/src$ ./obiwan_pub.py

Again, check the list of available ROS topics. Pick another Shell from the Tools menu and run:

user:~$ rostopic list
/help_msg
/rosout
/rosout_agg

Now we have a new topic /help_msg, obviously created by the obiwan_pub.py program. Running it is the only thing we have done since the last time we checked the list of messages, right?

Okay, do not take my word for it; let’s spy on the /help_msg topic to confirm:

user:~$ rostopic info /help_msg
Type: std_msgs/String

Publishers:
 * /sos_2 (http://rosdscomputer:38619/)

Subscribers: None

Now we know that that topic uses a message of type std_msgs/String and has a Publisher named /sos_2.

But what has this got to with the obiwan_pub node? Everything – let’s see that in the next step.

Step 3: Unravel the mysterious “Publisher” /sos_2

In the previous step, we saw that /sos_2 was listed as a Publisher on the topic /help_msg, and we suspected that this has to do with the obiwan_pub.py program. Now, let’s examine the obiwan_pub.py code to see if we have some clues.

obiwan_pub.py

#! /usr/bin/env python

import rospy
from std_msgs.msg import String

rospy.init_node("sos_2")
rate = rospy.Rate(2)
help_msg = String()
help_msg.data = "help me Obi-Wan Kenobi, you're my only hope"
pub = rospy.Publisher('/help_msg', String, queue_size = 1)
while not rospy.is_shutdown():
    pub.publish(help_msg)
    rate.sleep()

On line 6, we have the statement rospy.init_node("sos_2"), so we now know that:

  • /sos_2 was created by this program!
  • /sos_2 is a ROS node, because it says rospy.init_node...

Also on line 10, we have this statement: pub = rospy.Publisher('/help_msg', String, queue_size = 1), confirming that:

  • The code actually creates a Publisher on the /help_msg topic. Bingo!

Step 4: Master the Concept – What is a ROS Publisher?

Combining all the points in the previous steps, we can see that a ROS Publisher…

  • is a ROS node (program).
  • creates a particular type of ROS message. In this case, it’s std_msgs/String, as can be seen on lines 4,7-8 of the code.
  • sends (publishes) a message over a channel called “topic”, as can be seen on lines 10 then 12 of the code.

In short, a ROS publisher is a ROS node that publishes a specific type of ROS message over a given ROS topic. “Interested” nodes (Subscribers) can access messages so published.

And that was it!

Extra: Video

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

Related Resources

  • A previous video about ROS nodes: [irp posts=”10305″ name=”ROS in 5 mins – 005 – What is a ROS Node?”]

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? Whatever the case, please leave a comment in 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 post or video about it.

Thank you!

[ROS in 5 mins] 021 – What is a ROS Subscriber

[ROS in 5 mins] 021 – What is a ROS Subscriber

 

Hello ROS Developers!

In today’s video we are going to see what is ROS Subscriber and how to see a list of them in a ROS Topic.

Before we start, if you are new to ROS and want to Learn ROS Fast, I highly recommend you to take any of the following courses on Robot Ignite Academy:

We love feedback, so, whether you like the video or not, please leave a comment on the comments section below so that we can interact and learn from each other.

Step1. Create a project in Robot Ignite Academy(RIA)

We have the best online ROS course available in RIA. It helps you learn ROS in the easiest way without setting up ROS environment locally. The only thing you need is a browser! Create an account here and start to browse the trial course for free now! We’ll use the ROS Basics in 5 Days course unit 0 as an example today.

Step2. What is ROS Subscriber?

Let’s start by visualizing the relationship between nodes with

rqt_graph

You can see that the nodes are communicating using the topics. A node can be a publisher publishing some topic or a subscriber to some topic. A topic can even have as many subscribers as you want.

For example, if you use the following command

rostopic echo /camera/rgb/image_raw __name:=subscriber1 > /dev/null

You can add a new subscriber called subscriber1 to the /camera/rgb/image_raw topic and you can add more subscribers if you want.

 

Edit by: Tony Huang

[ROS in 5 mins] 020 – What is a ROS message? Part#2

[ROS in 5 mins] 020 – What is a ROS message? Part#2

In this post, we will see how to check the structure of ROS messages so we can properly use them in our programs.

This is the second part of this series, you can find the last one here: https://www.theconstruct.ai/ros-5-mins-018-ros-message-part1/

Let’s go!

Step 1: Grab a copy of the Project (ROSject) on ROSDS

We will use the project used in Part 1 of this series. Get it here: http://www.rosject.io/l/18f83296-0e7e-4c5c-95a7-2d3e3d6430d4/.

Once you have copied the project, open it up.

Step 2: Examine the structure of the String message type

In the code, we used a ROS message type called String. Let’s examine the structure of this message.

Pick a Shell from the Tools menu and run the following command:

user:~$ rosmsg show String
[std_msgs/String]:
string data

[roseus/String]:
string data

Pick the IDE from the Tools menu, navigate to catkin_ws/src and open the obiwan_pub.pyprogram. You should see something like:

obiwan_pub.py

#! /usr/bin/env python

import rospy
from std_msgs.msg import String

rospy.init_node("sos_2")
rate = rospy.Rate(2)
help_msg = String()
help_msg.data = "help me Obi-Wan Kenobi, you're my only hope"
pub = rospy.Publisher('/help_msg', String, queue_size = 1)
while not rospy.is_shutdown():
    pub.publish(help_msg)
    rate.sleep()

We see that the String message is defined in two different packages (roseus and std_msgs), but we used the one defined in the std_msgs package, as can be seen on line 4 of the code block.

We also see that the String message has a single attribute named data, which should be a string. So, when creating a message of type String, we need to set a value for data, and the value must be a string (lines 8-9).

Now also take a look at the obiwan_sub.py program:

obiwan_sub.py

#! /usr/bin/env python
 
import rospy
from std_msgs.msg import String
 
def callback(msg):
    print "SOS received: '%s'!" %(msg.data)
    
rospy.init_node('help_desk')
sub = rospy.Subscriber('/help_msg', String, callback)
rospy.spin()

We see that on lines 6-7 when accessing a message of type String, we take it for granted that it has an attribute data, therefore we could reference msg.data.

Step 3: Determine the proper ROS message type to use for a given topic

In the obiwan_pub  program above, we created a new topic called /help_msg. What if you are trying to publish to an existing topic and you are not sure the kind of message to send over it or you’re trying to subscribe to the topic and want to know what to expect? PS: every topic has a message type you must publish over it, or things will not work properly.

Let’s pretend we didn’t know the kind of message /help_msg uses – we just know the name of the topic. Let’s see how we can find out:

  • Start the obiwan_pub node, so that the help_msg topic is created.
user:~$ cd catkin_ws/src
user:~/catkin_ws/src$ ./obiwan_pub.py
  • Now pick another Shell from the Tools menu and run rostopic info /help_msg to find out the type of message it uses:
ser:~$ rostopic info /help_msg
Type: std_msgs/String

Publishers:
 * /sos_2 (http://rosdscomputer:34691/)

Subscribers: None
  • So now we see that it uses the message std_msgs/String, and we can know about this message by running. Here, we are specifying the package name (std_msgs) also, since we know it for sure:
user:~$ rosmsg show std_msgs/String
string data

Step 4: Wrapping it up

In summary, in order to use a ROS message properly, you need to know its structure. If you are working with an existing ROS topic, you can check what kind of message it uses and then check the structure of that message.

Extra: Video

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

Related Resources

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? Whatever the case, please leave a comment in 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 post or video about it.

Thank you!

Pin It on Pinterest