반응형

1. Work Space 생성

   우선 Work Space를 생성해준다.

 

$ mkdir catkin_ws && mkdir catkin_ws/src

 

 

2. 패키지 다운로드

   위에서 생성한 src 디렉토리에서 rplidar 와 Hector_SLAM 패키지를 다운받아준다.

 

$ git clone github.com/robopeak/rplidar_ros

$ git clone github.com/tu-darmstadt-ros-pkg/hector_slam

 

그럼 src경로에 rplidar 디렉토리와 hector_slam 디렉토리가 생성된다.

이제 파일들을 수정해주자.

 

 

$ gedit catkin_ws/src/hector_slam/hector_mapping/launch/mapping_default.launch

 

 

 

 

$ gedit catkin_ws/src/hector_slam/hector_slam_launch/launch/tutorial.launch

 

 

 

 

3. Build

수정이 완료되었으면 catkin_ws 경로로 돌아와 catkin_make를 통해 빌드를 진행해주자.

 

$ cd ~/catkin_ws

$ catkin_make

 

위의 과정을 통해 catkin_make를 진행하면 catkin_ws 경로에 devel 폴더와 build폴더가 생성된다.

 

$ source /devel/setup.bash

 

 

4. Hector SLAM

그럼 이제 LIDAR센서를 통해 지도를 그려보자.

라이다 센서를 연결한 후 USB 포트에 권한을 설정해주는 과정을 진행한다.

 

$ ls /dev/ttyUSB*

위의 명령어를 통해 USB로 연결되어있는 LIDAR센서의 포트를 확인해보자.

(보통 USB0으로 검색되는 것 같다.)

 

USB0으로 검색되는 경우 아래 명령어를 통해 권한을 설정해주자.

 

$ sudo chmod 666 /dev/ttyUSB0

 

 

$ roslaunch rpldiar_ros rplidar_a3.launch

위의 명령어를 통해 라이다를 작동시키고

 

$ roslaunch hector_slam_launch tutorial.launch

위의 명령어를 통해 hector slam을 진행해보자.

 

반응형
반응형

선형회귀는 딥러닝의 기본이 되는 개념이지만 용어부터 굉장히 낯설어 접근하기 어렵게 생각할 수 있다.

 

선형회귀란 가장 훌륭한 예측선을 긋는 것으로 볼 수 있다.

 

예를들어 학생들의 시험 성적과 학생들이 공부한 시간과의 관계를 파악하기 위해

4명의 학생에 대해 조사하고 이를 그래프로 나타낸다고 생각해보자.

 

아래 그래프에서 x축 데이터는 공부한 시간, y축 데이터는 성적을 의미한다.

그럼 위의 그래프를 가장 잘 나타낼 수 있는 직선을 그어보자.

즉 추세선을 그어보자.

위와 같이 나타내어질 수 있을 것이다.

 

그럼 해당 데이터들을 가장 잘 나타낼 수 있는 추세선이 있다면 몇시간을 공부했을때 어느정도의 성적이 나올지

예측해볼 수 있다.

 

그럼 우리는 예측의 정확도를 향상시키기 위해 좋은 추세선을 그릴 수 있어야하고 좋은 추세선은 결국

해당되는 데이터들을 가장 잘 나타내는 선으라고 볼 수 있다.

 

즉 해당 데이터들을 가장 잘 나타낼 수 있는 좋은 선을 긋는 과정을 선형회귀라 볼 수 있다.

 

추세선을 식으로 나타내면 y=ax + b 로 표현할 수 있다.

 

그럼 좋은 추세선은 해당 데이터들을 가장 잘 나타내는 것이므로 오차가 가장 적은 선으로 볼 수 있고

이를 위해 최소제곱법을 사용하여 추세선 식을 나타낼 수 있다.

 

 

 

* 최소 제곱법

 

최소제곱법의 공식은 아래와 같고 이를 통해 추세선의 기울기값 a를 구할 수 있다.

 

즉 위의 과정을 통해 해당 데이터를 가장 잘 나타낼 수 있는 직선을 구할 수 있고 이를 통해

임의의 x데이터에 대한 출력을 예측할 수 있다.

 

 

 

 

* 평균제곱오차

 

위의 방식은 한가지의 x데이터 정보에 대해서만 예측이 가능하다는 단점이 있다.

다시말해 성적에는 공부한 시간 외에도 지출한 사교육 비용, 시험 당일 컨디션, 개개인의 집중도 등이

포괄적으로 적용되어 시험성적을 나타내게 되는데 최소제곱법을 통해서는 하나의 조건에 대해서만

예측이 가능하다는 단점을 지니고 있다.

 

그리고 이를 위한 방법으로 평균제곱오차를 다뤄보겠다.

 

이 방법은 일단 추세선을 그리고 조금씩 변화시켜가며 정확한 추세선을 찾아가는 과정이라 볼 수 있다.

이러한 과정을 통해 입력데이터가 여러 종류일때에도 적용하여 출력값을 추정할 수 있다.

 

하지만 이 과정을 진행하기 위해선 나중에 조금 변화시킨 추세선이 이전의 추세선보다 우수한 선임을

판단할 수 있어야한다.

 

 

만약 위의 그래프에서 붉은색으로 나타낸 직선이 가장 우수한 추세선이라고 가정해보자.

 

평균제곱오차 방식을 사용하기 위해 임의의 직선을 하나 그어보자(이는 주황색으로 표시하였다).

 

그리고 어느정도의 오차가 발생하였는지 파악할 수 있어야 어떠한 직선이 더 우수한 직선인지 판단할 수 있으므로

위와 같이 해당 데이터에서의 실제 출력값과 추세선으로 추정된 값과의 차이를 확인한다

점선으로 표시된 직선들의 합이 클수록 잘못 그어진 추세선이고 작을수록 잘 그려진 추세선이라고 판단할 수 있다.

 

오차는 (예측값)-(실제값)으로 표현될 수 있지만 위의 경우를 보면 어떠한 경우는

예측값이 실제값보다 커서 오차가 양수를 갖지만 예측값이 실제값보다 작은 경우에는 오차가 음수를

갖게되어 무작정 오차를 합하게 되면 무의미한 오차값이 될 수 있고 따라서 부호를 없애주는 작업을

진행하여준다.

 

그리고 x데이터의 개수로 나누어 오차 합의 평균을 구하면 이를 평균 제곱 오차(Mean Squared Error, MSE)라

하고 다음과 같이 표시한다.

 

 

* 경사 하강법

 

그럼 평균제곱오차를 통해 두 직선에 대해 어느 직선이 더 우수한지 비교할 수 있는 과정을 진행하였다.

그리고 처음에는 임의의 값을 통해 진행할 수 있었다.

하지만 정말 터무니없는 직선들을 가져와 비교해보며 최적의 추세선을 찾기에는 굉장히 노가다스러움이

느껴지고 연산량도 굉장히 많아질 수 있을 것이다.

 

이를 해결하기 위해 초기 임의의 직선과 그 다음 직선을 선택하는 과정을 경사 하강법을 통해 살펴보자.

 

 

반응형
반응형

가장 먼저 Intel realsense sdk를 설치한다.

www.intelrealsense.com/sdk-2/

 

Intel RealSense SDK 2.0 – Intel RealSense Depth and Tracking cameras

Free Cross-platform SDK for depth cameras (lidar, stereo, coded light). Windows, Linux and other. 10+ wrappers including ROS, Python, C/C++, C#, unity. Try!

www.intelrealsense.com

 

$ export ROS_VER=melodic
$ sudo apt-get install ros-melodic-realsense2-camera

 

workspace를 만들기 위해 catkin_ws_d435i 라는 이름의 디렉터리를 생성한다.

$ mkdir -p ~/catkin_ws_d435i/src
$ cd ~/catkin_ws_d435i/src/

 

Intel RealSense 패키지를 다운받자.

git clone https://github.com/IntelRealSense/realsense-ros.git
cd realsense-ros/
git checkout `git tag | sort -V | grep -P "^2.\d+\.\d+" | tail -1`
cd ..

그리고 아래 과정을 통해 catkin_make를 설치하자.

catkin_init_workspace
cd ..  (catkin_ws_d435i 폴더로 이동)
catkin_make clean
catkin_make -DCATKIN_ENABLE_TESTING=False -DCMAKE_BUILD_TYPE=Release
catkin_make install

 

setup.bash 파일을 source한다.

echo "source ~/catkin_ws_d435i/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc

 

* 카메라 노드 실행

$ roslaunch realsense2_camera rs_camera.launch

관계를 살펴보기 위해 rqt_graph를 실행해보자.

 

* 포인트클라우드 생성

우선 위에서 실행한 roslaunch realsense2_camera 를 종료하고 아래 명령어를 실행한다.

$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud

상단의 Fixed Frame을 camera_color_frame으로 변경해야 좌표계를 맞게 설정하게 된다.

 

 

 

*imu 사용하기

 

rostopic list 를 실행하여 확인해보면 imu에 대한 topic이 확인되지 않는다.

 

$ roslaunch realsense2_camera rs_camera.launch filters:=pointcloud unite_imu_method:="linear_interpolation" enable_gyro:=true enable_accel:=true

위에서 실행시켰던 roslaunch 명령어에 몇가지 arguments를 추가해주자.

 

해당 arguments 는 rs_camera.launch 파일에 작성되어있는 부분을 수정해 준 것이다.

 

그럼 다음으로 imu값을 받아오기 위해 imu tools 패키지를 설치해주자.

 

$ sudo apt-get install ros-melodic-imu-tools

 

그럼 이제 rviz를 실행시켜 시각화해보자.

이때 "Global Option" 의 "Fixed Frame" 은 camera_accel_optical.. 로 설정하고

IMU 항목과 PointCloud2 항목에서 Topic을 설정해준다.

imu 센서의 값들을 확인해보고자 한다면 아래 명령어를 실행시키자.

 

$ rostopic echo /camera/imu
반응형

'ROS' 카테고리의 다른 글

VINS-MONO  (0) 2021.03.09
Realsense D435i Rtabmap  (0) 2021.03.09
RPLIDAR A3 실행(Hector SLAM In ROS)  (0) 2021.02.02
ROS에서 Realsense D435i 실행시키기  (0) 2020.12.28
ROS IP주소를 이용한 다른pc의 캠(CAM) 사용  (0) 2019.09.16
반응형

 

1. Service Node 작성

(앞의 게시물에서 다루었던 AddTwoInts.srv 과정을 진행하지 않았다면 이것부터 진행한다.)

 

 

1.1 The Code

 

패키지 경로로 이동한 후 src/add_two_server.cpp 파일을 생성하고 아래 코드를 붙여넣자.

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"

bool add(beginner_tutorials::AddTwoInts::Request  &req,
         beginner_tutorials::AddTwoInts::Response &res)
{
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  ROS_INFO("Ready to add two ints.");
  ros::spin();

  return 0;
}

 

 

1.2 The Code Explained

 

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"

srv파일을 통해 실행되는 헤더파일들을 선언한다.

 

bool add(beginner_tutorials::AddTwoInts::Request  &req,
         beginner_tutorials::AddTwoInts::Response &res)

함수 선언으로 srv파일에 정의된 대로 2개의 request를 통해 하나의 response를 갖고 최종적으로 boolean값을 return한다.

 

{
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;
}

response로 정의된 sum은 request되는 변수 a와 b의 합으로 정의된다.

ROS_INFO함수를 통해 request된 값과 reponse되는 값을 출력한다.

 

ros::ServiceServer service = n.advertiseService("add_two_ints", add);

NodeHandle을 통해 service를 발행하고 누가 쿼리를 날려주면 add함수를 실행하고

정해놓은 service 타입인 beginner_tutorials 패키지의 AddTwoInts.srv로 만들어진 AddTwoInts.h파일을 이용하여

서비스타입을 받아온다. 그 중 Request는 client에서 request하는 값들이고 Response는 client로 보내줄 값들이다.

 

 

2. Writing the Client Node

 

2.1 The Code

 

src/add_two_ints_client.cpp 파일을 생성하고 아래 코드를 붙여넣자.

 

#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_client");
  if (argc != 3)
  {
    ROS_INFO("usage: add_two_ints_client X Y");
    return 1;
  }

  ros::NodeHandle n;
  ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
  beginner_tutorials::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  if (client.call(srv))
  {
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
  }
  else
  {
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;
  }

  return 0;
}

 

 

2.2 The Code Explained

 

ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");

위의 과정을 통해 add_tow_ints 서비스의 client를 생성한다. ros::ServiceClient 객체는 나중에 서비스를 호출하기 위해 사용된다.

 

beginner_tutorials::AddTwoInts srv;
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);

argv[1], argv[2] 로 들어온 문자를 longlong 정수형으로 변환하여 request 변수인 a와 b에 저장한다.

 

if (client.call(srv))

이 부분이 실질적으로 서비스를 호출한다. 서비스 호출이 제대로 완료되면 call()함수가 True를 반환하고 값이 srv에 들어가고

reponse가 가능해진다.

 

 

 

3. Building your nodes

 

~/catkin_ws/src/beginner_tutorials/CMakeLists.txt 파일의 하단부에 아래 내용을 삽입하여 수정하도록 하자.

add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)

add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)

 

이제 catkin_make를 실행하자.

# In your catkin workspace
cd ~/catkin_ws
catkin_make

 

 

4. Running the nodes

 

4.1 Runnning the Server

 

$ rosrun beginner_tutorials add_two_ints_server

그럼 아래와 같은 문구가 출력되게 된다.

4.2 Running the Client

$ rosrun beginner_tutorials add_two_ints_client 1 3

위의 명령어를 입력하면 client shell과 server shell에서 아래와 같이 각각 출력됨을 확인할 수 있다.

 

 

반응형
반응형

C++ 코드를 통해 publisher 노드와 subscriber 노드를 생성해보자.

 

1. Publisher 노드 작성

노드는 ROS 네트워크에서 실행가능한 하나의 요소로 publisher node(talker) 생성을 통해 메시지를 계속적으로 broadcast하는 노드를 생성해보도록 하겠다.

 

우선 앞의 과정에서 생성한 beginner_tutorials 패키지로 이동한다.

 

 

1.1 The Code

 

beginner_tutorials 패키지 경로에서 src 폴더를 생성한다.

이 폴더는 beginner_tutorials 패키지의 모든 소스파일을 저장할 곳이다.

src/talker.cpp 파일을 생성하고 다음의 코드를 붙여넣자.

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

#include <sstream>

/**
 * This tutorial demonstrates simple sending of messages over the ROS system.
 */
int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "talker");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * The advertise() function is how you tell ROS that you want to
   * publish on a given topic name. This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing. After this advertise() call is made, the master
   * node will notify anyone who is trying to subscribe to this topic name,
   * and they will in turn negotiate a peer-to-peer connection with this
   * node.  advertise() returns a Publisher object which allows you to
   * publish messages on that topic through a call to publish().  Once
   * all copies of the returned Publisher object are destroyed, the topic
   * will be automatically unadvertised.
   *
   * The second parameter to advertise() is the size of the message queue
   * used for publishing messages.  If messages are published more quickly
   * than we can send them, the number here specifies how many messages to
   * buffer up before throwing some away.
   */
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

  ros::Rate loop_rate(10);

  /**
   * A count of how many messages we have sent. This is used to create
   * a unique string for each message.
   */
  int count = 0;
  while (ros::ok())
  {
    /**
     * This is a message object. You stuff it with data, and then publish it.
     */
    std_msgs::String msg;

    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());

    /**
     * The publish() function is how you send messages. The parameter
     * is the message object. The type of this object must agree with the type
     * given as a template parameter to the advertise<>() call, as was done
     * in the constructor above.
     */
    chatter_pub.publish(msg);

    ros::spinOnce();

    loop_rate.sleep();
    ++count;
  }


  return 0;
}

 

 

1.2 The Code Explained

 

# include "ros/ros.h"

ros/ros.h 는 일반적으로 ROS 시스템에서 사용되는 많은 부분들에 대한 필수적인 헤더를 포함하고 있다.

 

# include "std_msgs/String.h"

std_msgs 패키지에서 사용되는 std_msgs/String 메시지를 사용하기 위한 과정으로 이는 자동으로 패키지 안의 String.msg 파일을 실행하게 된다. 자세한 정보는 링크를 참고 바란다.(wiki.ros.org/msg)

 

ros::init(argc, argv, "talker");

ROS를 초기화하는 과정으로 노드의 이름을 갖게되고 여기서 이름은 동작되는 시스템에서 유일하게 지정되어야한다.

 

ros::NodeHandle n;

해당 노드의 핸들러를 만든다. 처음 생성된 NodeHandle은 자동으로 노드를 초기화하고 마지막으로 제거될 때 해당 노드가 사용한 리소스를 정리(cleanup)한다.

 

ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

Topic "chatter"에 대한 std_msgs/String 타입의 메시지를 publish할 것을 Master에게 알리게 된다.

Master는 chatter 을 subscribe하기 원하는 노드를 찾아 이 둘이 직접 연결되게 다.

두번째 argument는 publish queue의 크기를 지정하게 된다.

만약 publishing이 너무 빠르게 되면 이전의 메시지를 버리기 전에 지정된 버퍼 1000을 새롭게 채우는 문제가 발생할 수 있다.

 

위의 코드를 통해 chatter_pub이라는 이름의 ros::Publisher 객체를 생성하게 되고 advertise()는 해당 토픽으로 publish 가능한 객체인 ros::Publisher 클래스를 반환하며 그 객체의 publish()를 이용하여 원하는 메시지를 발행할 수 있다.

 

ros::Rate loop_rate(10);

ros::Rate 객체는 반복하고자하는 주기를 설정하게 된다. 위의 경우 10Hz로 반복하게되고 하단의 Rate::sleep()을 통해 지정된 시간을 지키기위해 sleep을 수행한다.

 

int count = 0;
while (ros::ok())
{

ros::ok()가 False가 될 경우는 아래와 같다.

 

  * Ctrl+C 의 입력을 받았을 경우

  * 동일한 이름의 다른 노드로 인해 충돌이 발생한 경우

  * 다른 부분에서 ros::shutdown() 이 호출된 경우

  * 모든 ros::NodeHandles 가 종료된 경우

 

ros::ok() 가 한번 False를 반환하면 다시 ROS를 사용할 수 없다.

 

std_msgs::String msg;
std::stringstream ss;
ss << "hello world" << count;
msg.data = ss.str();

우리는 msg 파일을 통해 실행된 message-adapted class를 통해 ROS에서 메시지를 broadcasting 한다.

더 복잡한 형태의 데이터타입도 가능하지만 "data" 멤버를 갖는 표준적인 String 메시지를 사용하도록 하겠다.

 

chatter_pub.publishing(msg);

이제 연결된 노드에게 실질적은 broadcast를 실행한다.

 

ROS_INFO("%s", msg.data.c_str());

ROS_INFO는 출력을 담당한다.

 

ros::spinOnce();

본 예제에서는 callback을 받지 않으므로 필수적인 요소는 아니다. 이는 큐에 요청된 콜백함수를 처리하게 된다.

ROS는 여러개의 노드가 비동기 환경에서 작동하는 운영체제이다. 비동기 방식의 경우 어떤 작업을 실행시키고 결과와 상관없이 다음 작업을 수행하게 된다. 즉 A함수를 실행하고 A가 끝나든 말든 B를 시작하는 방식이다. 다만 요청했던 것의 할 일이 끝난 후 처리 결과를 콜백이라는 함수와 함께 알려준다.

 

 

2.Writing the Subscriber Node

 

2.1 The Code

 

src/listener.cpp 파일을 생성하고 아래의 내용을 붙여넣자.

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

/**
 * This tutorial demonstrates simple receipt of messages over the ROS system.
 */
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "listener");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;

  /**
   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called chatterCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   *
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
   */
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

  /**
   * ros::spin() will enter a loop, pumping callbacks.  With this version, all
   * callbacks will be called from within this thread (the main one).  ros::spin()
   * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
   */
  ros::spin();

  return 0;
}

 

 

 

2.2 The Code Explained

 

위에서 설명한 부분은 생략하도록 하겠다.

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
	ROS_INFO("I heard: [%s]", msg->data.c_str());
}

chatter Topic에 대해 새로운 메시지를 수신하게 되면 호출되는 콜백 함수이다.

 

ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

chatter 토픽에 대한 메시지를 subscribe한다. ROS는 새로운 메시지가 도착할때마다 chatterCallback() 함수를 호출한다. 2번째 argument는 queue 크기로 queue에 1000 메시지가 가득 차게 되면 오래된 것부터 제거하게 된다.

 

NodeHandle::subscribe() 함수는 ros::Subscriber 객체를 반환하고 이는 토픽을 unsubscribe할때까지 유지되게 된다.

subscribe() 함수는 메시지를 받아 callback함수에 전달하게 되고 즉 전달받은 메시지를 통해 callback함수가 실행되어 처리되게 된다.

 

ros::spin();

반복적인 subscribe를 수행하고 callback을 지속적으로 요청한다. publisher의 경우 주기를 사용자가 지정하여 지정된 간격으로 메시지를 보내지만 subscriber는 메시지가 오는 즉시 callback을 요청하고 바로 그 다음 메시지를 기다리게 된다.

 

 

 

3. Building your nodes

 

CMakeLists.txt 파일을 아래와 같이 수정한다.

CMakeLists.txt 파일에는 패키지 빌드와 catkin에 관련된 설정 정보가 포함되어 있다. catkin 버전, file include경로, 노드 리스트, 라이브러리 의존성 등이 작성되어 있다.

cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)

## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)

## Declare ROS messages and services
add_message_files(FILES Num.msg)
add_service_files(FILES AddTwoInts.srv)

## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)

## Declare a catkin package
catkin_package()

## Build talker and listener
include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages_cpp)

이는 2개의 실행 가능한 노드를 생성하게 된다. (~/catkin_ws/devel/lib/<package name> 확인해보자.)

 

 

 

4. Examing the Simple Publisher and Subscriber

 

앞에서 publisher 노드와 Subscriber 노드를 생성하였으니 이제 본격적으로 생성한 노드를 테스트해보자.

 

우선 roscore 실행.

$ roscore

 

 

 

4.1 Generate Publisher node

catkin을 사용하고 있다면 workspace의 setup.sh 파일이 catkin_make 이후에 source되었는지 확인해보자.

# In your catkin workspace
$ cd ~/catkin_ws
$ source ./devel/setup.bash

생성한 pulisher 노드를 실행시키자.

rosrun beginner_tutorials talker

그럼 아래와 같이 출력되는 것을 확인할 수 있다.

 

4.2 Generate Subscriber node

$ rosrun beginner_tutorials listener

그럼 아래와 같은 결과를 확인할 수 있다.

반응형

'ROS > ROS Wiki' 카테고리의 다른 글

C++로 Service와 Client 노드 생성  (0) 2021.01.06
Creating a ROS msg and srv  (0) 2021.01.05
Using rosed to edit files in ROS  (0) 2021.01.05
Using rqt_console and roslaunch  (0) 2021.01.05
Understanding ROS Services and Parameters  (0) 2021.01.05
반응형

msg와 srv 파일, rosmsg, rossrv, roscp commandline tools를 어떻게 생성하고 빌드하는지 다룬다.

메시지는 publish, subscribe되는 단방향성 데이터 전송을 나타낸다. 따라서 전송되는 데이터의 타입과 데이터 갯수 등을 정의해주게 되고 서비스는 request와 reponse의 양방향성 통신이므로 두 부분을 따로 정의해주게 된다.

 

1. Introduction to msg and srv

msg: msg파일은 ROS message를 나타내는 간단한 텍스트파일이다. 이는 다른 언어들의 소스코드들을 실행시키는데 사용된다.

 

srv: srv파일은 서비스를 나타내는 파일로 request와 response의 2가지로 분류된다.

(msg파일은 해당 패키지의 msg dictionary에 저장되고 srv는 srv dictionary에 저장된다.)

 

msg는 field type과 field name으로 구성된 한 줄로 구성된 텍스트파일로 field type은 다음과 같이 사용 가능하다.

 

ROS에는 header라는 특별한 타입이 있는데 헤더는 ROS에서 자주 사용되는 타임스탬프와 좌표 정보를 포함하게 된다.

다음은 Header, 문자열, 그리고 2개의 다른 msgs를 사용하는 msg를 나타내었다.

srv파일은 request와 reponse가 있는 것만 제외하고 msg와 거의 동일하다. 두 파트는 '--'로 구분되게 된다.

아래는 srv파일의 예이다.

여기서 request는 64bit integer 형태의 A, B 출력은 Sum 으로 A, B를 요청하여 값을 받으면 Sum이라는 결과를 reponse하게 된다.

 

2. Using msg

2.1 Create a msg

 

이전에 다룬 패키지의 새로운 msg를 정의한다.

위의 내용을 통해 msg디렉터리의 Num.msg 파일에 "int64 num" 이라는 문구가 적힌 파일이 생성된다.

아래와 같이 한 줄에 하나의 요소씩 추가하여 파일을 수정할 수 있다.

 

이제 이 msg파일을 C++이나 python 등의 코드로 변경하는 과정을 진행해야한다.

package.xml 파일을 열어 아래의 두 문장이 주석처리되지 않았음을 확인하자.

catkin_ws/src/beginner_tutorials/ 디렉터리로 이동하여 package.xml파일을 열어보자.

위와 같이 주석처리가 되어있으면 주석을 풀어주자.

(빌드를 진행할땐 message_generation이 필요하고 실행을 할땐 message_runtime이 필요하다.)

 

이제 CMakeLists.txt를 열어보자.

 

다음과 같이 message_generation을 dependency에 추가하여(find_package를 찾아 수정하자) 메시지를 시작할 수 있다.

가끔씩 find_package의 모든 dependencies를 호출(call)하지 않아도 잘 빌드될때가 있는데 이는 catkin이 모든 프로젝트를 한번에 묶어 이전에 find_package를 호출한 적이 있다면 같은 값이 들어가기 때문이다. 하지만 이를 독립적으로 실행하게 되면 문제가 발생할 수 있다.

 

그리고 아래와 같이 catkin_package부분에 message runtime dependency를 추가하도록 하자.

 

다음으로 아래 부분을 수정하도록 하자.

.msg파일을 직접 추가해줌으로써 다른 .msg파일들이 추가될때 CMake가 확실히 이를 적용시킬 수 있도록 한다.

 

이제 generate_message() 함수가 확실히 호출될 수 있도록 하자.

이제 msg정의를 통해 source 파일을 실행시킬 준비가 되었다.

 

 

 

3. Using rosmsg

msg가 생성되어있다면 rosmsg 명령을 통해 이를 확인할 수 있다.

그럼 다음의 결과를 확인할 수 있다.

메시지 타입은 크게 2개의 파트로 분류된다.

   * beginner_tutorials -- the package where the message is defined

   * Num -- The name of the msg Num

 

혹시 어떤 msg가 있는 패키지가 생각나지 않는다면 다음의 코드를 통해 msg파일이 있는 패키지를 확인할 수 있다.

 

 

4. Using srv

4.1 Creating a srv

 

앞에서 사용한 패키지에 srv를 만들어보자.

새로운 srv 정의를 직접 작성하는 대신 다른 패키지에 존재하는 내용을 복사하여 사용하겠다.

다른 패키지에서 파일을 복사하여 사용하기 위해선 roscp 명령어를 사용할 수 있다.

 

그리고 아래와 같이 package.xml 파일을 수정한다(이 부분은 위에서 다룬 내용으로 이미 진행하였으면 넘어간다).

CMakeLists.txt파일도 아래와 같이 수정하는데 위에서 진행하였다면 넘어가도록 하자.

추가적으로 아래의 부분도 수정하도록 하자.

 

4.2 Using rossrv

 

rossrv show 명령어를 통해 해당 파일의 내용을 살펴볼 수 있다.

그럼 다음과 같은 결과를 확인할 수 있다.

그리고 rosmsg와 같이 패키지 이름 없이 service file을 찾을 수 있다.

 

 

5. Common step for msg and srv

CMakeLists.txt 파일을 아래와 같이 수정한다(이전에 완료했으면 하지않아도 된다).

이제 새로운 메시지를 생성하였으므로 패키지를 다시 make하자.

 

 

6. Getting help

 

대부분의 ROS 명령어는 -h라는 help 옵션이 존재하여 사용법을 잊었을 때 유용하게 사용할 수 있다.

 

반응형
반응형

1. Using rosed

rosed는 rosbash의 일부로 패키지 전체의 경로를 입력하지 않고 패키지의 이름을 통해 내부 파일을 직접적으로 설정할 수 있도록 한다.

 

예제를 통해 roscpp 패키지 안에 있는 Logger.msg 파일을 수정하는 과정을 나타낸다.

 

2. Using rosed with tab completion

이 방법을 통해 파일의 정확한 이름을 몰라도 패키지의 모든 파일을 쉽게 보고 수정할 수 있다.

 

3. Editor

rosed의 기본 에디터는 vim을 사용한다.

$ sudo apt-get update
$ sudo apt-get install vim
$ vi ~/.vimrc

위의 과정까지 진행하면 vi 편집기 창이 열리게 되는데 해당 창에서 i를 입력하면 쓰기 모드로 이동하게 된다.

편집기 창에서 쓰기 모드로 전환이 되면 아래의 설정들을 복사하여 해당 편집기 창에 붙여넣자.

(글 복사는 Ctrl+Insert, 붙여넣기는 Shift+Insert)

set number    " line 표시
set ai    " auto indent
set si " smart indent
set cindent    " c style indent
set shiftwidth=4    " 자동 공백 채움 시 4칸
set tabstop=4    " tab을 4칸 공백으로
set ignorecase    " 검색 시 대소문자 무시
set hlsearch    " 검색 시 하이라이트
set nocompatible    " 방향키로 이동 가능
set fileencodings=utf-8,euc-kr    " 파일 저장 인코딩 : utf-8, euc-kr
set fencs=ucs-bom,utf-8,euc-kr    " 한글 파일은 euc-kr, 유니코드는 유니코드
set bs=indent,eol,start    " backspace 사용가능
set ruler    " 상태 표시줄에 커서 위치 표시
set title    " 제목 표시
set showmatch    " 다른 코딩 프로그램처럼 매칭되는 괄호 보여줌
set wmnu    " tab 을 눌렀을 때 자동완성 가능한 목록
syntax on    " 문법 하이라이트 on
filetype indent on    " 파일 종류에 따른 구문 강조
set mouse=a    " 커서 이동을 마우스로 가능하도록

위의 코드에서 " 표시는 C언어의 // 와 같이 한 줄 주석을 의미한다.

 

그럼 이제 esc를 눌러 입력모드를 빠져나오고 ":"를 입력하여 마지막 라인으로 이동한다.

그럼 ":____" 부분에 "wq"를 입력하여 저장 후 종료한다.

반응형
반응형

ROS에서 디버깅하고 많은 노드들을 동시에 시작하기 위한 rqt_console과 rqt_logger_level을 알아보자.

 

1. Prerequisites rqt and turtlesim package

이번 과정은 rqt와 turtlesim 패키지를 모두 사용하므로 둘 다 설치를 진행한다.

 

<distro>는 ROS버전(kinetic, melodic, ...)을 입력한다.

2. Using rqt_console and rqt_logger_level

rqt_console은 ROS의 rogging 프레임워크를 통해 노드들의 결과를 표시해준다.

rqt_logger_level 은 노드들이 실행되면서 동시에 verbosity level(DEBUG, WARN, INFO and ERROR)을 변경할 수 있도록 한다.

 

rqt_console의 turtlesim의 출력을 확인해보고 rqt_logger_level을 turtlesim으로 변경해보자.

turtlesim을 시작하기 전에 새로운 터미널창을 열고 rqt_console과 rqt_logger_level을 실행하자.

 

그럼 아래와 같은 창이 팝업되게 된다.

 

 

그럼 이제 아래 명령어를 통해 turtlesim_node를 실행시키자.

 

기본으로 설정된 logger level이 INFO이므로 turtlesim 이 publish하는 정보들을 확인할 수 있게 된다.

 

이제 logger level을 WARN으로 변경해보자.

 

그리고 아래 코드를 입력하여 보면

콘솔에 아래와 같은 Warn 메시지들이 출력되는 것을 확인할 수 있다.

 

2.1 Quick Note about logger levels

Logging levels는 다음의 순서로 우선순위가 정해지게 된다.

Fatal은 가장 높은 우선순위를 갖고 Debug는 가장 낮은 우선순위를 갖는다. logger level을 설정함으로써 priority level 이상의 메시지들을 받게 된다. 예를들어, logger level을 WARN으로 설정하면 모든 Warn, Error, Fatal logging messages를 받게 된다.

 

그럼 이제 turtlesim 노드를 종료하고 다수의 turtlesim 노드들을 실행하기 위해 roslaunch를 사용해보자.

 

2.2 Using roslaunch

roslaunch는 launch file에 정의된대로 노드들을 실행하게 된다.

우선 앞에서 생성하고 빌드했던 beginner_tutorials 패키지의 경로로 이동하자.

만약 위의 명령에서 "roscd:No such package/stack 'beginner_tutorials'" 라는 에러가 출력되면 setup파일의 설정을 source하여 저장해야한다.

(참고: wiki.ros.org/catkin/Tutorials/create_a_workspace)

 

다음 launch 폴더를 생성한다.

2.3 The Launch File

이제 turtlemimic.launch 라는 파일을 생성하고 아래 내용을 복붙하자.

$ gedit turtlemimic.launch


<launch>

  <group ns="turtlesim1">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <group ns="turtlesim2">
    <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
  </group>

  <node pkg="turtlesim" name="mimic" type="mimic">
    <remap from="input" to="turtlesim1/turtle1"/>
    <remap from="output" to="turtlesim2/turtle1"/>
  </node>

</launch>

2.4 The Launch File Explained

 

위의 코드에서 가장 위에 <launch> 는 해당 파일이 launch file임을 나타낸다.

 

그리고 첫번째, 두번째 문단을 통해 sim이라는 이름의 2가지 노드(turtlesim1, turtlesim2)를 정의하고

이는 충돌없이 두개의 시뮬레이터가 잘 작동할 수 있도록 해준다.

 

마지막 문단은 각각의 노드들의 입/출력을 설정하는 과정으로 turtlesim2가 turtlesim1을 따라하도록 설정한 것이다.

 

마지막 </launch>는 launch file의 xml을 닫도록 하는 것이다.

 

 

2.5 roslaunching

이제 해당 파일을 roslaunch 해보자.

그럼 거북이 창이 2개 뜨는 것을 확인할 수 있다.

 

하나의 명령을 통해 2개의 거북이가 동시에 움직이는 것을 확인할 수 있다.

그럼 rqt_graph를 통해 관계를 조금 더 자세히 알아보자.

 

turtlesim1이 움직임의 메시지를 subscribe하고 mimic 노드를 통해 turtlesim2가 turtlesim1을 따라가는 관계임을 볼 수 있다.

반응형

'ROS > ROS Wiki' 카테고리의 다른 글

Creating a ROS msg and srv  (0) 2021.01.05
Using rosed to edit files in ROS  (0) 2021.01.05
Understanding ROS Services and Parameters  (0) 2021.01.05
Understanding ROS Topics  (0) 2021.01.04
Understanding ROS Nodes  (0) 2021.01.03

+ Recent posts