Detailed use of basic functions of ROS system (basic instructions / nodes / services / startup files / dynamic parameters)

Posted by youqing on Fri, 17 Sep 2021 02:30:54 +0200

1, Create workspace

1. Create a new folder
Create a new catkin_ws folder and create src subdirectory in it.

mkdir -p ~/dev/catkin_ws/src
cd ~/dev/catkin_ws/src

2. Initialize workspace
In the src subdirectory just created, use the following command to create a workspace, but there is no function package in the workspace at this time, only CMakeLists.txt.

catkin_init_workspace

3. Compile workspace
Go back to the top directory of the workspace, catkin_ws folder, using catkin_ The make command performs compilation. After compiling, you can see that the build and devel folders are generated by using the ll instruction.

cd ..
catkin_make

4. Complete the configuration
Reload the setup.bash file to complete the last step of workspace creation configuration

source devel/setup.bash

In fact, if you add this command line to ~ /. bashrc, you can get the same effect by restarting the terminal. The added command is as follows, where noetic is the version number of my ros system. If your version is different, you must change it.

echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc

2, Create and compile ROS function package

1. Create function package
Function packs can be created manually, but catkin is usually used for convenience_ create_ PKG command creates a function package. The format of this command is as follows

catkin_create_pkg [package_name] [depend1] [depend2] [depend3]

The dependent dependencies include:

  • std_msgs: contains common message types that represent basic data types and other basic message constructs.
  • roscpp: use C + + to write various functions of ROS.
Example:
cd ~dev/catkin_ws/src
catkin_create_pkg test_package std_msgs roscpp

2. Compile function package
Back to catkin_ws folder. If no error is reported, the function package is compiled successfully.

cd ..
catkin_make

3, Basic commands of ROS

3.1 nodes

1. rosnode instruction
The rosnode tool can print information about ROS nodes. The specific commands are as follows:

rosnode instructioneffect
rosnode ping NODETest connectivity of nodes
rosnode listList active nodes
rosnode info NODEOutput information for this node
rosnode machinePrint nodes running on a specific computer
rosnode kill NODEEnd node process
rosnode cleanupClear the registration information of inaccessible nodes

2. Operation node
First start the ros program with the roscore command, and then open a new terminal window to perform the next operation.

We can run a node using the rosrun instruction

Example:
rosrun turtlesim turtlesim_node

After the node runs successfully, you can use the rosnode list again to see the running node. You can use rosnode info / turnlesim to view the details of the node, including Publications, Subscriptions and Services of the node.

3.2 subject

1. rostopic instruction
Nodes can realize data transmission through publishing topics and subscribing topics. Message transmission through topics does not require direct connection of nodes. A topic can have multiple subscribers and publishers. To realize the interaction between topics and nodes, you can use the rostopic instruction.

rostopic instructioneffect
rostopic bw TOPICDisplays the bandwidth used by the topic
rostopic echo TOPICOutput the message of the subject to the screen
rostopic find TOPICfind topic
rostopic hz TOPICShow topic publishing frequency
rostopic info TOPICOutput topic details
rostopic list TOPICList activity topics
rostopic pubs TOPICPublish data to topics
rostopic type TOPICType of output topic

2. Release theme
You can list the topics of the current node through rostopic list. You can print messages sent by the node through the echo parameter, such as rostopic echo / turnle1 / CMD_ vel.

In addition, we can also publish topics directly through rostopic pub, as follows:

Example:
rostopic pub -r 10 /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '{linear: {x: 1, y: 0, z: 0}, angular: {x: 0, y: 0, z: 1}}'

3.3 services

1. rosservice instruction
Services are another way for nodes to communicate with each other. Services allow nodes to send requests and receive responses. You can use the rosservice directive to manipulate services.

  • roservice args /service: output service parameters
  • rosservice call /service: call the service according to the command line parameters
  • rosservice find msgtype: query services by service type
  • rosservice info /service: output service information
  • Ross service list: lists the active service list
  • rosservice type /service: output service type
  • rosservice uri /service: outputs the ROSRPC URI service

2. Use of services
Use rosservice list to list all services. Use rosservice call [service] [args] to call a service. For example, rosservice call /clear can clear the lines on the turtle map.

In addition, use rossrv show turnlesim / spawn to view the detailed parameters of the / spawn service.

With these parameters, you can call the / spawn service to create a second turtle.

rosservice call /spawn 3 3 0.5 "new_turtle"

3.4 parameter server

1. rosparam instruction
The parameter server stores the shared data that can be accessed by all nodes. The parameter server can be managed through the rosparam instruction.

rosparam instructioneffect
rosparam set parameter valueSet parameter value
rosparam get parameterGet parameter value
rosparam load fileLoad parameters from file
rosparam dump fileSave parameters to file
rosparam delete parameterDelete parameter
rosparam listList all parameter names

2. Use parameter server
Taking the Little Turtle program as an example, we can see that the background is the parameter of the turnlesim node by listing the parameter list through the rosparam list. Therefore, we can obtain the parameter value through the get instruction.

rosparam list
rosparam get /turtlesim/background_g
rosparam set /turtlesim/background_g 200

4, Creation and operation of nodes

This part will take a specific experiment as an example to introduce the method of creating nodes by creating a talker and a listener and realizing the information exchange between them.

4.1 creating source files

First enter the workspace ~ / dev / catkin_ Feature pack test in WS folder_ In the package / SRC / folder, create two CPP files here as the sender and receiver of the message. Here I will talk about two source files named talker.cpp and listener.cpp respectively.

//talker.cpp
#include "ros/ros.h" 	// Contains the necessary files for the ROS node
#include "std_msgs/String.h" 	// Contains the message type to use
#include <sstream>

int main(int argc, char **argv){
        ros::init(argc, argv, "talker");	//Start the node and set the name
        ros::NodeHandle n;	//Sets the handle of the node process
        ros::Publisher chatter_pub = n.advertise<std_msgs::String>("message", 1000);
        //Set the node as the publisher, set the subject name as message, and buffer 1000 messages
        ros::Rate loop_rate(10);	//Data transmission frequency 10HZ
        while(ros::ok()){
                std_msgs::String msg;
                std::stringstream ss;
                ss << "I'm talker node~~~";
                msg.data = ss.str();		//A message variable was created
                ROS_INFO("%s", msg.data.c_str());	//Screen output message information
                chatter_pub.publish(msg);	//Release news
                ros::spinOnce();			//If a subscriber appears, all topics are updated
                loop_rate.sleep();
        }
        return 0;
}


//listener.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"

//Callback function. The node will call this function every time it receives a message
void messageCallback(const std_msgs::String::ConstPtr& msg){
        ROS_INFO("I am listener, I heard: [%s]",msg->data.c_str());
}

int main(int argc, char **argv){
        ros::init(argc, argv, "listener");
        ros::NodeHandle n;
        ros::Subscriber sub = n.subscribe("message", 1000, messageCallback);
        //Create a subscriber, get messages from the message topic, set 1000 messages in the buffer, and the callback function for processing messages is messageCallback
        ros::spin();	//Message callback processing, and it will not be returned after calling
        return 0;
}

4.2 modify CMakeLists.txt

Edit catkin_ ws/src/test_ CMakeLists.txt in package /. Add the following content at the end.

#include_directories(
        include
        ${catkin_INCLUDE_DIRS}
)

# Specifies the name of the compiled executable
add_executable(talker src/talker.cpp)
add_executable(listener src/listener.cpp)
# Define the dependent files for the target
add_dependencies(talker test_package_generate_messages_cpp)
add_dependencies(listener test_package_generate_messages_cpp)

target_link_libraries(talker ${catkin_LIBRARIES})
target_link_libraries(listener ${catkin_LIBRARIES})

4.3 compilation node

Go back to the workspace root directory and compile:

cd ~/dev/catkin_ws
catkin_make

If The dependency target does not exist. Error occurs, change the cmake version beginning with CMakeLists.txt to 2.8.3.

Environment variables need to be set after compilation

echo "source ~/ros/tr3_6/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc

4.4 operation node

Then start running the node, running roscore first

roscore

Then open two windows to run separately

rosrun test_package example1_a
rosrun test_package example1_b

You can see the acceptance and sending of messages.

5, Creation and use of services

In this section, two nodes will be created as server and client respectively. The data transmission of the two nodes and the function of digital summation will be realized through the call of services.

5.1 creating msg files

Before using the service, you first need to create msg and srv files, which are used to describe the data types and data values transmitted.
1. First create the msg file
In test_ Create the MSG folder under the package function package, and create a new file test in the MSG folder_ msg.msg. Enter the following in the file:

int32 num1
int32 num2
int32 num3

2. Edit the package.xml file
Find the following two lines in the package.xml file and uncomment them <! --- >

<!-- <build_depend>message_generation</build_depend> -->

<!-- <exec_depend>message_runtime</exec_depend> -->
<build_depend>message_generation</build_depend>

<exec_depend>message_runtime</exec_depend>

3. Edit the CMakeLists.txt file
Open the CMakeLists.txt file in the function pack directory.

find_package(), in which message is added_ Generation is as follows:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
  message_generation
)

Find the following two paragraphs, uncomment them, and delete the test you just created_ Message.msg the message name is added

## Generate messages in the 'msg' folder
add_message_files(
  FILES
  test_msg.msg
)
## Generate added messages and services with any dependencies listed here
generate_messages(
  DEPENDENCIES
  std_msgs
)

4. Compilation test
After the above steps, compile with the following command:

cd ~/dev/catkin_ws/
catkin_make

After compilation, to check whether the msg file just created is successfully compiled, use the rosmsg show command:

rosmsg show test_package/test_msg

If the output is the same as test_ The contents in the msg.msg file are consistent, indicating that the compilation is correct.

5.2 creating srv files

1. Create srv file
In test_ Create an SRV folder under the package function package, and create a new file test in the SRV folder_ srv.srv. Enter the following in the file:

int32 num1
int32 num2
int32 num3
---
int32 sum

2. Edit the package.xml file
The package.xml file has been edited when the msg file is created. No additional modification is required here.

3. Edit CMakeLists.txt
Find catkin_package, uncomment it and add correct data as follows:

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES test_package
#  CATKIN_DEPENDS roscpp std_msgs
#  DEPENDS system_lib
  CATKIN_DEPENDS message_runtime
)

Cancel add_service_files and add the name of the service file just created.

## Generate services in the 'srv' folder
add_service_files(
  FILES
  test_srv.srv
)

4. Compilation test
After the above files are created and modified, use the following command to compile:

cd ~/dev/catkin_ws
catkin_make

After compilation, to check whether the service file is compiled correctly, you can use the rossrv show command:

rossrv show test_package/test_srv.srv

If the print content is different from test_ The contents in the srv.srv file are consistent, indicating that the compilation is correct.

5.3 creating. cpp source files

1. Create source file
In the src directory in the function pack folder, click catkin_ws/test_package/src, create two. CPP files, server.cpp and client.cpp, as the server and client respectively.

#include "ros/ros.h"
#include "test_package/test_srv.h" 	// Contains the created SRV file

//Sum the three variables and send the calculation results to other nodes
bool add(test_package::test_srv::Request &req, test_package::test_srv::Response &res){
        res.sum = req.num1 + req.num2 + req.num3;
        ROS_INFO("request: num1=%ld, num2=%ld, num3=%ld", (int)req.num1, (int)req.num2, (int)req.num3);
        ROS_INFO("sending back response: [%ld]", (int)res.sum);
        return true;
}       

int main(int argc, char **argv){
        ros::init(argc, argv, "add_3_ints_server");
        ros::NodeHandle n;
        //Create the server side of the service "add_3_ints" and broadcast it in ROS
        ros::ServiceServer service = n.advertiseService("add_3_ints", add);
        ROS_INFO("Ready to add 3 ints!");
        ros::spin();
        return 0;
} 
#include "ros/ros.h"
#include "test_package/test_srv.h"
#include <cstdlib>

int main(int argc, char **argv){
        ros::init(argc, argv, "add_3_ints_client");
        if(argc != 4){
                ROS_INFO("usage: add_3_ints_client num1 num2 num3");
                return 1;
        }

        ros::NodeHandle n;
        //Create a client with the name "add_3_ints"
        ros::ServiceClient client = n.serviceClient<test_package::test_srv>("add_3_ints");
        
        //Create an instance of the srv file and add the data value to be sent
        test_package::test_srv srv;
        srv.request.num1 = atoll(argv[1]);
        srv.request.num2 = atoll(argv[2]);
        srv.request.num3 = atoll(argv[3]);
        
        //Call the service and send data. If the call is successful, the server will return true; otherwise, it will return false
        if(client.call(srv)){
                ROS_INFO("Sum: %ld", (long int)srv.response.sum);
        }
        else{
                ROS_ERROR("Failed to call service add_3_ints");
                return 1;
        }

        return 0;

} 

2. Edit CMakeLists.txt

add_executable(server src/server.cpp)
add_executable(client src/client.cpp)

add_dependencies(server test_package_generate_messages_cpp)
add_dependencies(client test_package_generate_messages_cpp)

target_link_libraries(server ${catkin_LIBRARIES})
target_link_libraries(client ${catkin_LIBRARIES})

5.4 test procedure

Back to catkin_ws workspace, compile.

cd ~/dev/catkin_ws
catkin_make

After compiling, open a terminal and run roscore, then open two new terminal windows and run the following code respectively

rosrun test_package server
rosrun test_package client 6 4 2

It can be seen that the server and client have realized message communication and completed the sum calculation of three numbers.

6, Configuration of startup file

Previously, we have realized the creation and use of nodes, but each node needs to open different command line windows for execution. If there are more nodes, it will be very troublesome to start nodes.

Through the startup file, we can start multiple nodes in the command line window. We only need to run the file with the suffix. launch to start multiple nodes.

6.1 creating a. launch file

First, create a folder called launch in the function package, and create the test.launch file in it.

roscd test_package
mkdir launch
cd launch
vim test.launch

Enter the following in the test.launch file:

<?xml version="1.0"?>
<launch>
	<node name="talker" pkg="test_package" type="talker" />
	<node name="listener" pkg="test_package" type="listener" />
</launch>

6.2 startup node

The startup file written above can start the talker and listener nodes of the previous experiment. The startup commands are as follows:

roslaunch test_package test.launch

The system will output the following information, indicating that the startup is successful.

Use the rosnode list to list the active nodes. You can see that we have successfully started the talker and listener nodes.

If you want to see the information passed by two nodes, you can use rqt_console

7, Use of dynamic parameters

Generally, when writing a node, we can only initialize the variables in the node with data. If we want to change the values of these variables, we can use the subject, service or parameter server, but this method cannot be updated dynamically online. If the listener does not actively query, we cannot know whether the parameters are updated. Sometimes we need to dynamically update parameters online, so we need to use dynamic parameters.

7.1 creating a profile

First, create a new folder named CFG in the function package, and create a test.cfg file in it.

roscd test_package
mkdir cfg
cd cfg
vim test.cfg

Add the following code in test.cfg:

# Initialize ROS and import parameter generator
#!/usr/bin/env python
PACKAGE = "test_package"
from dynamic_reconfigure.parameter_generator_catkin import *

# Initialize the parameter generator. We can add parameters through gen
gen = ParameterGenerator()

# Add different parameter types and set default values, descriptions, value ranges, etc
# gen.add(name, type, level, description, default, min, max)
gen.add("double_param", double_t, 0, "A double parameter", .1, 0, 1)
gen.add("str_param", str_t, 0, "A string parameter", "test_default_string")
gen.add("int_param", int_t, 0, "An Integer parameter", 1, 0, 100)
gen.add("bool_param", bool_t, 0, "A Boolean parameter", True)

size_enum = gen.enum([gen.const("Low", int_t, 0, "Low is 0"), gen.const("Medium", int_t, 1, "Medium is 1"), gen.const("High", int_t, 2, "High is 2"), gen.const("Exlarge", int_t, 3, "Exlarge is 3")], "Select from the list")

gen.add("size", int_t, 0, "Select from the list", 1, 0, 3, edit_method=size_enum)

# Generate the necessary files and exit the program
exit(gen.generate(PACKAGE, "test_package", "test_"))



Since test.cfg is an executable file executed by ROS, we need to change the file permissions:

chmod a+x test.cfg

7.2 modify CMakeLists.txt to add the compilation of the configuration file

Open CMakeLists.txt and find_package, add dynamic at the end_ The reconfigure is as follows:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
  message_generation
  dynamic_reconfigure
)

Find generate_dynamic_reconfigure_options, uncomment and change the internal configuration file to the newly created configuration file.

## Generate dynamic reconfigure parameters in the 'cfg' folder
generate_dynamic_reconfigure_options(
  cfg/test.cfg
)

7.3 creating nodes

Next, you need to create a new node with dynamic configuration support.

Create a new file in the src folder as follows:

roscd test_package
vim src/dynamic_param.cpp

Write the following code in the file:

#include <ros/ros.h>
#include <dynamic_reconfigure/server.h>
#include <test_package/test_Config.h>

//The callback function will output the new value of the parameter, and the parameter name must be the same as the test.cfg configuration file
void callback(test_package::test_Config &config, uint32_t level){
        ROS_INFO("Reconfigure Request: %d %f %s %s %d", config.int_param, config.double_param, config.str_param.c_str(), config.bool_param?"True":"False", config.size);
}

int main(int argc, char **argv){
        ros::init(argc, argv, "test_dynamic_reconfigure");
        //initialize server
        dynamic_reconfigure::Server<test_package::test_Config> server;
		//Send a callback function to the server. When the server gets a reconfiguration request, it will call the callback function        
        dynamic_reconfigure::Server<test_package::test_Config>::CallbackType f;
        f = boost::bind(&callback, _1, _2);
        server.setCallback(f);

        ros::spin();
        return 0;
}   

7.4 modify CMakeLists.txt to add node compilation

add_executable(dynamic_param src/dynamic_param.cpp)
add_dependencies(dynamic_param test_package_gencfg)
target_link_libraries(dynamic_param ${catkin_LIBRARIES})

7.5 operation configuration

Open three terminal command line windows and run the following commands respectively:

roscore
rosrun test_package dynamic_param
rosrun rqt_reconfigure rqt_reconfigure

When the execution is complete, you will see an rqt_reconfigure window, in which you can dynamically configure node parameters, and you can see the changes of command line printing parameters when adjusting parameters.

Topics: C++ Ubuntu ROS Robot