ROS basics

  • Axis Orientation

    Coordinate

    • x: forward
    • y: left
    • z: upward
  • SI Unit

    Quantity Unit
    angle radian
    length meter
    mass kilogram
    frequency hertz
    force newton
    power watt
    voltage volt
    current ampere
    time second
    temperature celsius
  • Coding Style

    Object Naming Rule Example
    Package under_scored first_ros_package
    Topic, Service under_scored raw_image
    File under_scored turtlebot3_fake.cpp
    Namespace under_scored ros_awesome_package
    Variable under_scored string_table_name
    Type CamelCased typedef int32_t PropertiesNumber
    Class CamelCased class UrlTable
    Structure CamelCased struct UrlTableProperties
    Enumeration CamelCased enum ChoiceNumber
    Function camelCased addTableEntry()
    Method camelCased void setNumEntries(int32_t num_entries)
    Constant ALL_CAPITALS const uint8_t DAYS_IN_A_WEEK = 7;
    Macro ALL_CAPITALS #define PI_ROUNDED 3.0

ROS Message Communications

  • Overall Diagram

    Message Communication

    • Topic
    • Service
    • Action
    • Parameter

ROS Package Creation

Create ROS Package for Topic Test
cw
cd src
catkin_create_pkg ros_tutorials_topic_josh message_generation std_msgs roscpp
<?xml version="1.0"?>
  <package format="2">
    <name>ros_tutorials_topic_josh</name>
    <version>0.1.0</version>
    <description>The ros_tutorials_topic_josh package</description>

    <maintainer email="coolwind@hotmail.co.kr">Jo, SeungHyeon</maintainer>

    <license>Apache 2.0</license>

    <author email="coolwind@hotmail.co.kr">Jo, SeungHyeon</author>

    <url type="website">http://www.robotis.com</url>
    <url type="repository">https://github.com/ROBOTIS-GIT/ros_tutorials.git</url>
    <url type="bugtracker">https://github.com/ROBOTIS-GIT/ros_tutorials/issues</url>

    <buildtool_depend>catkin</buildtool_depend>
    <depend>message_generation</depend>
    <depend>roscpp</depend>
    <depend>std_msgs</depend>

    <export>
    </export>
    </package>
cmake_minimum_required(VERSION 2.8.3)
project(ros_tutorials_topic_josh)

find_package(catkin REQUIRED COMPONENTS
message_generation
roscpp
std_msgs
)

add_message_files(
FILES
MsgTutorial.msg
)

generate_messages(
DEPENDENCIES
std_msgs
)

catkin_package(
LIBRARIES ros_tutorials_topic_josh
CATKIN_DEPENDS roscpp std_msgs
)

###########
### Build ##
###########

include_directories(
${catkin_INCLUDE_DIRS}
)

add_executable(topic_publisher_josh src/topic_publisher.cpp)
add_executable(topic_subscriber_josh src/topic_subscriber.cpp)

add_dependencies(topic_publisher_josh ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(topic_subscriber_josh ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(topic_publisher_josh
${catkin_LIBRARIES}
)
target_link_libraries(topic_subscriber_josh
${catkin_LIBRARIES}
)
Create ROS Package for Service Test
cw
cd src
catkin_create_pkg ros_tutorials_service_josh message_generation std_msgs roscpp
<?xml version="1.0"?>
  <package format="2">
    <name>ros_tutorials_service_josh</name>
    <version>0.1.0</version>
    <description>The ros_tutorials_service_josh package</description>

    <maintainer email="coolwind@hotmail.co.kr">Jo, SeungHyeon</maintainer>

    <license>Apache 2.0</license>

    <author email="coolwind@hotmail.co.kr">Jo, SeungHyeon</author>

    <url type="website">http://www.robotis.com</url>
    <url type="repository">https://github.com/ROBOTIS-GIT/ros_tutorials.git</url>
    <url type="bugtracker">https://github.com/ROBOTIS-GIT/ros_tutorials/issues</url>

    <buildtool_depend>catkin</buildtool_depend>
    <depend>message_generation</depend>
    <depend>roscpp</depend>
    <depend>std_msgs</depend>

    <export>
    </export>
    </package>
cmake_minimum_required(VERSION 2.8.3)
project(ros_tutorials_service_josh)

find_package(catkin REQUIRED COMPONENTS
message_generation
roscpp
std_msgs
)

add_service_files(
FILES
SrvTutorial.srv
)

generate_messages(
DEPENDENCIES
std_msgs
)

catkin_package(
LIBRARIES ros_tutorials_topic_josh
CATKIN_DEPENDS roscpp std_msgs
)

###########
### Build ##
###########

include_directories(
${catkin_INCLUDE_DIRS}
)

add_executable(service_server_josh src/service_server.cpp)
add_executable(service_client_josh src/service_client.cpp)

add_dependencies(service_server_josh ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(service_client_josh ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(service_server_josh
${catkin_LIBRARIES}
)
target_link_libraries(service_client_josh
${catkin_LIBRARIES}
)

Message File Creation

Create Message File for Topic Test
roscd ros_tutorials_topic_josh
mkdir msg
cd msg
vim MsgTutorial.msg
time stamp
int32 data
  • Message type can be not only time and int32, but also
    • built-in types: bool, int8, int16, float32, string, time, duration, etc.
    • common_msgs: common messages being used in ROS
    • Message reference
Create Launch File for Topic Test
roscd ros_tutorials_topic_josh
mkdir launch
cd launch
vim union.launch
<launch>
  <group ns="ns1">
    <node pkg="ros_tutorials_topic_josh" type="topic_publisher_josh" name="topic_publisher"/>
    <node pkg="ros_tutorials_topic_josh" type="topic_subscriber_josh" name="topic_subscriber"/>
  </group>
  <group ns="ns2">
    <node pkg="ros_tutorials_topic_josh" type="topic_publisher_josh" name="topic_publisher"/>
    <node pkg="ros_tutorials_topic_josh" type="topic_subscriber_josh" name="topic_subscriber"/>
  </group>
</launch>

roslaunch running diagram

Launch Tag Description
launch begin and end of the roslaunch statement
node configure the node running specification, such as package, type, name
machine configure the machine specification the node running on, such as machine name, address, ros-root, ros-package-path, etc.
include include the other launch files from the same or different packages to be run as one launch file
remap rename the ROS variables used in the running nodes, such as node’s name, topic’s name, etc.
env set path and IP, etc. (hardly used)
param set parameter’s name, type, value, etc.
rosparam check and modify parameters in the way how rosparam commands (load, dump, delete, etc.) do
group make groups of nodes
test test node running with additional specifications
arg set or change the value of parameters
<launch>
  <arg name="update_period" default="10" />
  <param name="timing" value="$(arg update_period)" />
</launch>
roslaunch my_package my_package.launch updaete_period:=30
Create Service File for Service Test
roscd ros_tutorials_service_josh
mkdir srv
cd srv
vim SrvTutorial.srv
int64 a
int64 b
---
int64 result
  • Messages are separated by “---” into the set for request and the others for response.
  • Message type can be not only time and int32, but also
    • built-in types: bool, int8, int16, float32, string, time, duration, etc.
    • common_msgs: common messages being used in ROS
    • Message reference

Source File Creation

Create Publisher and Subscriber Nodes for Topic Test
  • Publisher Node Creation

    roscd ros_tutorials_topic_josh/src
    vim topic_publisher.cpp
    
    #include "ros/ros.h" // ROS 기본 헤더파일
    #include "ros_tutorials_topic_josh/MsgTutorial.h"// MsgTutorial 메시지 파일 헤더(빌드 후 자동 생성됨)
    
    int main(int argc, char **argv) // 노드 메인 함수
    {
        ros::init(argc, argv, "topic_publisher_josh"); // 노드명 초기화
      ros::NodeHandle nh; // ROS 시스템과 통신을 위한 노드 핸들 선언
    
      // 퍼블리셔 선언, ros_tutorials_topic_josh 패키지의 MsgTutorial 메시지 파일을 이용한
      // 퍼블리셔 ros_tutorial_pub 를 작성한다. 토픽명은 "ros_tutorial_msg" 이며,
      // 퍼블리셔 큐(queue) 사이즈를 100개로 설정한다는 것이다
      ros::Publisher ros_tutorial_pub = nh.advertise<ros_tutorials_topic_josh::MsgTutorial>("ros_tutorial_msg", 100);
    
        // 루프 주기를 설정한다. "10" 이라는 것은 10Hz를 말하는 것으로 0.1초 간격으로 반복된다
        ros::Rate loop_rate(10);
    
        // MsgTutorial 메시지 파일 형식으로 msg 라는 메시지를 선언
        ros_tutorials_topic_josh::MsgTutorial msg;
    
        // 메시지에 사용될 변수 선언
        int count = 0;
        while (ros::ok())
        {
            msg.stamp = ros::Time::now(); // 현재 시간을 msg의 하위 stamp 메시지에 담는다
            msg.data = count; // count라는 변수 값을 msg의 하위 data 메시지에 담는다
            ROS_INFO("send msg = %d", msg.stamp.sec); // stamp.sec 메시지를 표시한다
            ROS_INFO("send msg = %d", msg.stamp.nsec); // stamp.nsec 메시지를 표시한다
            ROS_INFO("send msg = %d", msg.data); // data 메시지를 표시한다
            ros_tutorial_pub.publish(msg); // 메시지를 발행한다
            loop_rate.sleep(); // 위에서 정한 루프 주기에 따라 슬립에 들어간다
            ++count; // count 변수 1씩 증가
        }
        return 0;
    }
    
  • Subscriber Node Creation

    roscd ros_tutorials_topic_josh/src
    vim topic_subscriber.cpp
    
    #include "ros/ros.h" // ROS 기본 헤더파일
    #include "ros_tutorials_topic_josh/MsgTutorial.h"// MsgTutorial 메시지 파일 헤더(빌드 후 자동 생성됨)
    
    // 메시지 콜백 함수로써, 밑에서 설정한 ros_tutorial_msg라는 이름의 토픽
    // 메시지를 수신하였을 때 동작하는 함수이다
    // 입력 메시지로는 ros_tutorials_topic_josh 패키지의 MsgTutorial 메시지를 받도록 되어있다
    void msgCallback(const ros_tutorials_topic_josh::MsgTutorial::ConstPtr& msg)
    {
        ROS_INFO("recieve msg = %d", msg->stamp.sec); // stamp.sec 메시지를 표시한다
        ROS_INFO("recieve msg = %d", msg->stamp.nsec); // stamp.nsec 메시지를 표시한다
        ROS_INFO("recieve msg = %d", msg->data); // data 메시지를 표시한다
    }
    
    int main(int argc, char **argv) // 노드 메인 함수
    {
        ros::init(argc, argv, "topic_subscriber_josh"); // 노드명 초기화
        ros::NodeHandle nh; // ROS 시스템과 통신을 위한 노드 핸들 선언
    
        // 서브스크라이버 선언, ros_tutorials_topic_josh 패키지의 MsgTutorial 메시지 파일을 이용한
        // 서브스크라이버 ros_tutorial_sub 를 작성한다. 토픽명은 "ros_tutorial_msg" 이며,
        // 서브스크라이버 큐(queue) 사이즈를 100개로 설정한다는 것이다
        ros::Subscriber ros_tutorial_sub = nh.subscribe("ros_tutorial_msg", 100, msgCallback);
    
        // 콜백함수 호출을 위한 함수로써, 메시지가 수신되기를 대기,
        // 수신되었을 경우 콜백함수를 실행한다
        ros::spin();
        return 0;
    }
    
    Create Server and Client Nodes for Service Test
  • Server Node Creation

    roscd ros_tutorials_service_josh/src
    vim service_server.cpp
    
    #include "ros/ros.h" // ROS 기본 헤더 파일
    #include "ros_tutorials_service_josh/SrvTutorial.h" // SrvTutorial 서비스 파일 헤더 (빌드후 자동 생성됨)
    
    // 서비스 요청이 있을 경우, 아래의 처리를 수행한다
    // 서비스 요청은 req, 서비스 응답은 res로 설정하였다
    bool calculation(ros_tutorials_service_josh::SrvTutorial::Request &req, ros_tutorials_service_josh::SrvTutorial::Response &res)
    {
        // 서비스 요청시 받은 a와 b 값을 더하여 서비스 응답 값에 저장한다
        res.result = req.a + req.b;
    
        // 서비스 요청에 사용된 a, b 값의 표시 및 서비스 응답에 해당되는 result 값을 출력한다
        ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
        ROS_INFO("sending back response: %ld", (long int)res.result);
    
        return true;
    }
    
    int main(int argc, char **argv) // 노드 메인 함수
    {
        ros::init(argc, argv, "service_server_josh"); // 노드명 초기화
    
        ros::NodeHandle nh; // 노드 핸들 선언
    
        // 서비스 서버 선언, ros_tutorials_service_josh 패키지의 SrvTutorial 서비스 파일을 이용한
        // 서비스 서버 ros_tutorials_service_server를 선언한다
        // 서비스명은 ros_tutorial_srv이며 서비스 요청이 있을 때,
        // calculation라는 함수를 실행하라는 설정이다
        ros::ServiceServer ros_tutorials_service_server = nh.advertiseService("ros_tutorial_srv", calculation);
        ROS_INFO("ready srv server!");
        ros::spin(); // 서비스 요청을 대기한다
    
        return 0;
    }
    
  • Client Node Creation

    roscd ros_tutorials_service_josh/src
    vim service_client.cpp
    
    #include "ros/ros.h" // ROS 기본 헤더 파일
    #include "ros_tutorials_service_josh/SrvTutorial.h" // SrvTutorial 서비스 파일 헤더 (빌드후 자동 생성됨)
    #include <cstdlib> // atoll 함수 사용을 위한 라이브러리
    
    int main(int argc, char **argv) // 노드 메인 함수
    {
        ros::init(argc, argv, "service_client_josh"); // 노드명 초기화
    
        if (argc != 3) // 입력값 오류 처리
        {
            ROS_INFO("cmd : rosrun ros_tutorials_service_josh service_client_josh arg0 arg1");
            ROS_INFO("arg0: double number, arg1: double number");
            return 1;
        }
    
        ros::NodeHandle nh; // ROS 시스템과 통신을 위한 노드 핸들 선언
    
        // 서비스 클라이언트 선언, ros_tutorials_service_josh 패키지의 SrvTutorial 서비스 파일을 이용한
        // 서비스 클라이언트 ros_tutorials_service_client를 선언한다
        // 서비스명은 "ros_tutorial_srv"이다
        ros::ServiceClient ros_tutorials_service_client =
        nh.serviceClient<ros_tutorials_service_josh::SrvTutorial>("ros_tutorial_srv");
    
        // srv라는 이름으로 SrvTutorial 서비스 파일을 이용하는 서비스를 선언한다
        ros_tutorials_service_josh::SrvTutorial srv;
    
        // 서비스 요청 값으로 노드가 실행될 때 입력으로 사용된 매개변수를 각각의 a, b에 저장한다
        srv.request.a = atoll(argv[1]);
        srv.request.b = atoll(argv[2]);
    
        // 서비스를 요청하고, 요청이 받아들여졌을 경우, 응답 값을 표시한다
        if (ros_tutorials_service_client.call(srv))
        {
            ROS_INFO("send srv, srv.Request.a and b: %ld, %ld", (long int)srv.request.a, (long int)srv.request.b);
            ROS_INFO("receive srv, srv.Response.result: %ld", (long int)srv.response.result);
        }
        else
        {
            ROS_ERROR("Failed to call service ros_tutorial_srv");
            return 1;
        }
        return 0;
    }
    
Create Server and Client Nodes for Parameter Test
  • Server Node Creation

    roscd ros_tutorials_service_josh/src
    vim service_server.cpp
    
    #include "ros/ros.h" // ROS 기본 헤더 파일
    #include "ros_tutorials_service_josh/SrvTutorial.h" // SrvTutorial 서비스 파일 헤더 (빌드후 자동 생성됨)
    
    // 서비스 요청이 있을 경우, 아래의 처리를 수행한다
    // 서비스 요청은 req, 서비스 응답은 res로 설정하였다
    bool calculation(ros_tutorials_service_josh::SrvTutorial::Request &req, ros_tutorials_service_josh::SrvTutorial::Response &res)
    {
        // 서비스 요청시 받은 a와 b 값을 파라미터 값에 따라 연산자를 달리한다.
        // 계산한 후 서비스 응답 값에 저장한다
        switch(g_operator)
        {
            case PLUS:
                res.result = req.a + req.b; break;
            case MINUS:
                res.result = req.a - req.b; break;
            case MULTIPLICATION:
                res.result = req.a * req.b; break;
            case DIVISION:
                if(req.b == 0){
                    res.result = 0; break;
                }
                else{
                    res.result = req.a / req.b; break;
                }
            default:
                res.result = req.a + req.b; break;
        }
    
        // 서비스 요청에 사용된 a, b 값의 표시 및 서비스 응답에 해당되는 result 값을 출력한다
        ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
        ROS_INFO("sending back response: %ld", (long int)res.result);
    
        return true;
    }
    
    int main(int argc, char **argv) // 노드 메인 함수
    {
        ros::init(argc, argv, "service_server_josh"); // 노드명 초기화
    
        ros::NodeHandle nh; // 노드 핸들 선언
    
        // 서비스 서버 선언, ros_tutorials_service_josh 패키지의 SrvTutorial 서비스 파일을 이용한
        // 서비스 서버 ros_tutorials_service_server를 선언한다
        // 서비스명은 ros_tutorial_srv이며 서비스 요청이 있을 때,
        // calculation라는 함수를 실행하라는 설정이다
        ros::ServiceServer ros_tutorials_service_server = nh.advertiseService("ros_tutorial_srv", calculation);
        ROS_INFO("ready srv server!");
    
        ros::Rate r(10); // 10 hz
        while (1)
        {
            nh.getParam("calculation_method", g_operator); // 연산자를 매개변수로부터 받은 값으로 변경한다
            ros::spinOnce(); // 콜백함수 처리루틴
            r.sleep(); // 루틴 반복을 위한 sleep 처리
        }
    
        return 0;
    }
    
  • Client Node Creation

    roscd ros_tutorials_service_josh/src
    vim service_client.cpp
    
    • Use the same file as the one in the Service Test

Build and Run the Sample Packages

cm
Execute Publisher and Subscriber Nodes for Topic Test
rosrun ros_tutorials_topic_josh topic_publisher_josh
rosrun ros_tutorials_topic_josh topic_subscriber_josh
Execute Server and Client Nodes for Service Test
$ rosrun ros_tutorials_service_josh service_server_josh
[ INFO] [1608540574.728446500]: ready srv server!
$ rosrun ros_tutorials_service_josh service_client_josh 2 3
[ INFO] [1608540608.362758300]: send srv, srv.Request.a and b: 2, 3
[ INFO] [1608540608.364704800]: receive srv, srv.Response.result: 5
$ rosservice call /ros_tutorial_srv 10 2
result: 12
Execute Server and Client Nodes for Parameter Test
$ rosrun ros_tutorials_service_josh service_server_josh
[ INFO] [1608540574.728446500]: ready srv server!
$ rosparam list
/calculation_method
/rosdistro
/roslaunch/uris/host_localhost__42759
/rosversion
/run_id
$ rosservice call /ros_tutorial_srv 10 2
result: 12
$ rosparam set /calculation_method 3
$ rosservice call /ros_tutorial_srv 10 2
result: 20