기술블로그

[초보탈출] ROS 를 이용한 다양한 실습

유미포 2021. 5. 18. 15:48

안녕하세요~ 아직도 졸업프로젝트를 하고있는 유미포입니다. 이제 구현은 다 끝나고 보고서 작성과 끊임없는 디버깅만 남았네요. 그래도 거의 다 끝났으니 모두 화이팅!!

제 블로그의 이전 글들을 보시면 아시겠지만, 혹시 안보셨을분들을 위해 다시한번 저희 프로젝트를 소개해드리겠습니다. 


저희 불사조는 컴퓨팅 계산 오프로딩 위해 ROS를 사용한 딥러닝 기반의 자율주행카트 를 제작하고있습니다.

'허걱 이게 뭐람 컴퓨팅계산? 오프로딩? ROS? 딥러닝? 자율주행카트???? 뭐야 이상한 단어 다 넣고 문장으로만든거 아니야??' 라고 생각하실수도 있지만, 하나씩 분해하여 살펴보면 개념은 그렇게 어렵지 않은것임을 아실 수 있을거예요! 이 포스트에 모든 내용을 다 담을수는 없지만, ( 자세한 내용은 저희의 발표를 참조해주세요~ 발표 요약은 추후에 이 블로그에 올라올 예정입니다. ) 그중 일부에 대해 설명해드리려고 합니다.

 

제가 이번학기에 맡은 부분은 Hardware인데요, 카트의 제작/ 카트의 운행 관련 개발을 하였습니다. 하드웨어 (로봇이자 카트) 중에서 어려운 부분이 많았지만, 하나의 포스팅으로 설명이 끝날만한건 ROS 기초에 대한 설명... 정도일것같습니다. 본 포스트의 내용에 질문이 있으시거나 실행에 어려움이 있으신 경우 언제든 댓글에 남겨주시면 최대한 빨리 답변 달도록 하겠습니다. (ROS 배우면서 난 에러만 몇백개여서... 어느 에러든 고쳐드릴 수 있습니다 하하 )

 

자 그럼 저희의 주제를 한번 분해해볼까요? 


컴퓨팅 계산 오프로딩 위해 ROS를 사용한 딥러닝 기반의 자율주행카트

 

  1. 우선, 컴퓨팅 계산, 컴퓨팅 계산은 영어로 computation입니다. 오히려 영어가 더 쉽죠? 그냥 컴퓨터가 각종 자원 (CPU, GPU등) 을 이용하여 연산/ 처리를 하는 것입니다.
  2. 두번째로 오프로딩, 오프로딩은 영어로  off + loading으로 한국어로는 하역 이라고 하네요? 쉽게 설명하자면 내가 하기 싫은걸 남에게 하라고 시키는것인데요, 저희의 경우 라즈베리파이를 이용하는 카트가 복잡한 계산을 하지 않기위해 다른 고성능 컴퓨터에게 '너가해!' 하고 떠넘기는 것입니다. 라즈베리파이입장에서는 너무 편하게 아무 노력도 들이지 않고 결과를 낼수 있겠죠? 반대로 고성능 컴퓨터는 뜬금없이 할일이 늘어나는겁니다. 그래도 4만원짜리 라즈베리파이보다 150만원 넘는 컴퓨터가 컴퓨팅 계산하게 하는게 효율적이고 현명하겠죠?
  3.  세번째로 ROS, 오늘 이 포스트는 바로 ROS에 관한 설명을 좀 해볼까 합니다. ROS를 들어보신분 혹시 계신가요? 대부분 많이들 모르시는 용어인것같습니다. 뒤에 나오는 딥러닝, 자율주행카트는 들어보신적은 있으실텐데 "ROS? 너는 뭐냐! " 하실까봐 준비했습니다.
  4. 나머지 단어들이 딥러닝과 자율주행카트에 대해 먼저 설명해드리자면,딥러닝이란, 인간의 개입이 최소화되게 하여 input에 대해 우리가 원하는 output을 내는 방법이며, 자율주행카트란, 인간이 밀고 끌지 않아도 알아서 자신의 경로를 파악하여  움직이는 카트입니다. 

자, 그럼 다시 컴퓨팅 계산 오프로딩 위해 ROS를 사용한 딥러닝 기반의 자율주행카트를 정리해볼까요? 쉽게말해 

카트가 사용하는 라즈베리 파이가 성능이 좋지 않으니 자율주행에 필요한 계산과 판단을 고성능컴퓨터에게 떠넘긴 카트

라고 볼 수 있겠네요~ 여기서 ROS 는 이 라즈베리 파이와 컴퓨터 사이의 통신을 담당하고 있는 시스템이랍니다. (이렇게만 설명하면 누가 알아들어!! 라고 하실까봐 이제부터 ROS에 대해 설명해드리겠습니다)

 


ROS란? 

 

 

ROS의 공식적인 정의부터 살펴보도록하겠습니다. ROS의 공식 사이트에 따르면 

The Robot Operating System (ROS) is a set of software libraries and tools that help you build robot applications. From drivers to state-of-the-art algorithms, and with powerful developer tools, ROS has what you need for your next robotics project. And it's all open source.

직독직해를 하자면,

ROS 는 로봇 운영 체제로, 로봇 어플리케이션을 만들기 쉽게 해주는 소프트웨어 라이브러리와 도구를 제공합니다. 각종 드라이버부터 핫한 알고리즘, 강력한 개발자도구, ROS는 당신이 다음 로봇 프로젝트를 하기 위해 필요한 것들이 다 들어있습니다. 그리고 이것들은 모두 오픈소스입니다.

열심히 번역을 해봤는데....전달이 잘 되었나요? 더 쉽게 풀자면, 운영체제가 각자 다른 로봇을 한번에 제어할 수 있게하는 운영체제 입니다. (제 주관적인 번역과 해석입니다) 너무 이론적이였나요?

 

그래서 모두가 해볼 수 있는 간단한 ROS 체험을 준비해봤습니다. 


ROS 설치 및 setup

 

저는 일단 Ubuntu 18.04 운영체제를 사용하고있으며, ROS melodic을 깔것입니다. 현재 ROS2까지 나와있으며, 다양한 버전 kinetic, neotic 등이 있으므로, 다른걸 설치하셔도 좋습니다. 구체적인 설치방법은 공식 사이트를 참조해주세요.

https://www.ros.org/

 

ROS.org | Powering the world's robots

ROS in Education ROS is used by students of all ages, from kids interacting with robots in museum exhibits to graduate students learning about the latest solutions to common robotics problems. Because it supports such a wide variety of robots, including lo

www.ros.org

 

운영체제와 버전에 따라 설치법이 다루므로 잘 선택하셔서 따라하시면 됩니다. 저는 일단 ubuntu에 melodic을 설치하는 법을 간단히 보여드리겠습니다. 

 

# 기본 셋업
$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
$ sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

# ROS설치
$ sudo apt update
$ sudo apt install ros-melodic-desktop-full
$ echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc source ~/.bashrc
$ source /opt/ros/melodic/setup.bash

# 필요한 library설치
$ sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential
$ sudo apt install python-rosdep
$ source /opt/ros/melodic/setup.bash

# ROS작업환경 만들기 
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/
$ catkin_make
$ echo $ROS_PACKAGE_PATH

 

뭐야이게!! 라고 하시지 말고 차근차근 하나씩 터미널에 입력하시면 /home에 catkin_ws이라는 폴더 하나가 생긴것을 확인하실 수 있을겁니다. 저 위의 명령어들이 뭐고 각각 하는일이 뭔지가 궁금하시다면 오피셜 document를 참조해주세요! (그것까지 이야기하면 이 포스트 안끝납니다 ㅋㅋ)

 

자 여러분이 초보자로써 알아야하는것은 딱 두가지!

 

1. 각종 script들은 /home/catkin_ws/src 폴더 안에 넣는다

2. script들은 python 또는 c++로 작성한다. 

 

저는 개인적으로 python을 더 좋아해서 예시는 다 python으로 들겠습니다. (하지만, 더 복잡한 script들을 사용하고싶으시면 c++ 로 하시는걸 추천해드립니다.) 


ROS를 이용한 실습 

우선 동기부여를 위해 저희가 할 간단한 프로젝트의 결과물을 먼저 보여드리겠습니다. 

house world

 

근사하죠? 이걸 내가 어떻게해! 싶으시겠지만, 저만 믿고 따라오시면 다 할 수 있게 되실거예요! 근데 그걸 하기 전에 먼제 이 귀여운 거북이로 ROS가 뭔지를 배워보겠습니다. (원을 그리려고한건데... 망했네요..;;)

 


이 친구는 turtlesim이라는건데, ROS 처음 배우는 모든 사람들의 hello world같은 친구입니다. 먼저 설치를 해볼게요. 

sudo apt-get install ros-$(rosversion -d)-turtlesim

설치 끝입니다. 간단하죠?

그럼 한번 실행시켜볼까요?

roscore
rosrun turtlesim turtlesim_node

이 화면이 다들 보이시죠? 귀여운 거북이친구가 화면에 떴습니다. 거북이의 모양은 실행할때마다 다를 수 있어요. TMI를 하나 말씀드리자면 저 거북이들은 ROS version마다 하나씩 있는 거북이로  melodic, kinetic, neotic, hydro 등 버전마다 한개씩 있습니다. 저는 우주거북이가 제일 귀엽더라고요 여러분도 여러번 실행시켜보시고 젤 귀여운 거북이를 댓글로 남겨주세요 ~

 

여튼 다시 본론으로 돌아오겠습니다. 

 

여러분이 

rosrun turtlesim turtlesim_node

 

이 커맨드 를 주시므로써 뭘 한것인지 설명해드리겠습니다.

 

참고로 rosrun/ roslaunch/ roscore 등 ros + 단어 로 구성된 이것들을 모두 커맨드 라고 표현하겠습니다. 

 

ROS 의 기본 구조는 Publisher과 Subscriber입니다. Publisher은 말 그대로 출판사? 출판 하는 녀석이며 subscriber은 "구독과 좋아요 눌러주세요~ "의 그 구독자 입니다. 

 

Publisher를 출판사로 Subscriber을 구독자로 대입해서 설명을 해보겠습니다. 

 

출판사는 각종 신문을 출판하고 구독자들은 자기가 구독하는 신문을 읽습니다. 출판사가 하나의 신문만 내는게 아니죠? 여러가지 신문을 원하는대로 출판할수 있습니다. 구독자도 출판사가 내는 신문들중 원하는걸 아무거나 구독할 수 있습니다. 출판사가 출판하는 신문을 하나의 topic이라고 하겠습니다. A 라는 topic을 구독하는 구독자는 계속 topic에 관한 새로운 뉴스를 받습니다. 그 뉴스를 받고 새로 투자를 하거나 주식을 사거나 할 수 있겠죠? 하지만 B topic의 내용은 알 수 없습니다. 구독을 하고 있지 않기 때문이죠. 여기서 이들이 그냥 막 출판과 구독을 할 수 없습니다. 전체적으로 배송과 전기 공급 등 기본적인 장을 만들어주는게 필요합니다. 이 장은 우리가 roscore이라는 커맨드를 줄때 만들어집니다.  

 

다시 돌아와서 전문적인 용어를 사용하자면, roscore을 켜줘서 장을 만들어주고 publisher을 통해 각종 rostopic을 publish하며 subscriber은 특정 rostopic에 subscribe(구독) 하여 또 다기가 할 일을 수행해 주는겁니다. 

 

다시, 

roscore
rosrun turtlesim turtlesim_node

 

은 장을 만들고 (roscore) turtlesim 폴더 안에 있는 turtlesim_node 스크립트를 실행시켜라(rosrun)입니다. 이 turtlesim_node 스크립트안에는 아마도 귀여운 거북이 를 화면에 띄우라는 publisher를 실행시키겠죠?  그래서 우리 화면에 이렇게 귀여운 거북이가 보이는겁니다. 

 

이 거북이가 띄워지며 각종 topic이 생겼을겁니다. 거북이에게 딸려오는 topic들이죠. 거북이에게 무슨 topic이 딸려왔는지를 확인해보겠습니다. 

이건

rostopic list

라는 커맨드를 통해 확인할 수 있습니다. 

rostopic list

여러가지 topic이 있네요. 그중 몇가지만 살펴볼까요? 

 

/turtle1/cmd_vel : 1번거북이의 가속도와 관련있는 topic 입니다. 이 Topic에 무언가를 publish하면 거북이 1의 가속도를 바꿀 수 있습니다. 

/turtle1/color_sensor : 뭔가 색 센서같죠?

/turtle1/pose :  아마 거북이 1 의 pose(위치)를 알려주는 topic인것같습니다. 

 

이 topic들은 거북이가 스스로 publish 하는 topic들입니다. 만약 우리가 이 정보를 써야한다면 이 topic을 구독하면 되곘죠? 

(여기서 포기하시면 안됩니다. 이제 이론은 다 끝났어요! 재밌는실습만 남았습니다) 


진짜 ROS 실습

자 그럼 거북이를 움직이게 해볼까요? 

 

어떻게하면 움직이게 할 수 있을까요? 바로 /turtle1/cmd_vel에 명령을 publish해주면 됩니다. 어떻게 publish 하나고요? 간단합니다. 

rosrun turtlesim move_turtle.py

/home/catkin_ws/src/turtlesim 에 move_turtle.py라는 파일을 만들고 아래의 코드를 복붙해보세요. 

 

#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist

def move():
    # Starts a new node
    rospy.init_node('robot_cleaner', anonymous=True)
    velocity_publisher = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
    vel_msg = Twist()

    #Receiveing the user's input
    print("Let's move your robot")
    speed = input("Input your speed:")
    distance = input("Type your distance:")
    isForward = input("Foward?: ")#True or False

    #Checking if the movement is forward or backwards
    if(isForward):
        vel_msg.linear.x = abs(speed)
    else:
        vel_msg.linear.x = -abs(speed)
    #Since we are moving just in x-axis
    vel_msg.linear.y = 0
    vel_msg.linear.z = 0
    vel_msg.angular.x = 0
    vel_msg.angular.y = 0
    vel_msg.angular.z = 0

    while not rospy.is_shutdown():

        #Setting the current time for distance calculus
        t0 = rospy.Time.now().to_sec()
        current_distance = 0

        #Loop to move the turtle in an specified distance
        while(current_distance < distance):
            #Publish the velocity
            velocity_publisher.publish(vel_msg)
            #Takes actual time to velocity calculus
            t1=rospy.Time.now().to_sec()
            #Calculates distancePoseStamped
            current_distance= speed*(t1-t0)
        #After the loop, stops the robot
        vel_msg.linear.x = 0
        #Force the robot to stop
        velocity_publisher.publish(vel_msg)

if __name__ == '__main__':
    try:
        #Testing our function
        move()
    except rospy.ROSInterruptException: pass

 

그리고 터미널에서

cd ~/catkin_ws/
catkin_make

를 하시고  

rosrun turtlesim move_turtle.py

를 해보세요. 아래의 창이 나오죠? 원하는 속력과 거리를 주고 앞으로가기는 True/False로 대답해주세요. 

rosrun turtlesim move_turtle.py

거북이친구가 움직이는것을 볼 수 있습니다. 이게 다입니다. ROS 의  hello world 를 해내셨습니다.

 

더 복잡하게 하려면 밑도 끝도 없지만, 일단 기본적인 ROS를 경험하신겁니다. 지금은 저 애니메이션같은 거라서 이게뭐지 하실 수도 있겠지만, 조금만 기다리시면 실제 로봇으로도 해보겠습니다. 하지만, 넘어가기 전에 좀더 터틀심으로 해보자면, 

 

이번에는 원하는 목적지로 가게 해볼까요?

 

 

다시 /home/catkin_ws/src/turtlesim에 들어가서 

go_to_goal.py를 열고

 

#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose
from math import pow, atan2, sqrt


class TurtleBot:

    def __init__(self):
        # Creates a node with name 'turtlebot_controller' and make sure it is a
        # unique node (using anonymous=True).
        rospy.init_node('turtlebot_controller', anonymous=True)

        # Publisher which will publish to the topic '/turtle1/cmd_vel'.
        self.velocity_publisher = rospy.Publisher('/turtle1/cmd_vel',
                                                  Twist, queue_size=10)

        # A subscriber to the topic '/turtle1/pose'. self.update_pose is called
        # when a message of type Pose is received.
        self.pose_subscriber = rospy.Subscriber('/turtle1/pose',
                                                Pose, self.update_pose)

        self.pose = Pose()
        self.rate = rospy.Rate(10)

    def update_pose(self, data):
        """Callback function which is called when a new message of type Pose is
        received by the subscriber."""
        self.pose = data
        self.pose.x = round(self.pose.x, 4)
        self.pose.y = round(self.pose.y, 4)

    def euclidean_distance(self, goal_pose):
        """Euclidean distance between current pose and the goal."""
        return sqrt(pow((goal_pose.x - self.pose.x), 2) +
                    pow((goal_pose.y - self.pose.y), 2))

    def linear_vel(self, goal_pose, constant=1.5):
        """See video: https://www.youtube.com/watch?v=Qh15Nol5htM."""
        return constant * self.euclidean_distance(goal_pose)

    def steering_angle(self, goal_pose):
        """See video: https://www.youtube.com/watch?v=Qh15Nol5htM."""
        return atan2(goal_pose.y - self.pose.y, goal_pose.x - self.pose.x)

    def angular_vel(self, goal_pose, constant=6):
        """See video: https://www.youtube.com/watch?v=Qh15Nol5htM."""
        return constant * (self.steering_angle(goal_pose) - self.pose.theta)

    def move2goal(self):
        """Moves the turtle to the goal."""
        goal_pose = Pose()

        # Get the input from the user.
        goal_pose.x = float(input("Set your x goal: "))
        goal_pose.y = float(input("Set your y goal: "))

        # Please, insert a number slightly greater than 0 (e.g. 0.01).
        distance_tolerance = input("Set your tolerance: ")

        vel_msg = Twist()

        while self.euclidean_distance(goal_pose) >= distance_tolerance:

            # Porportional controller.
            # https://en.wikipedia.org/wiki/Proportional_control

            # Linear velocity in the x-axis.
            vel_msg.linear.x = self.linear_vel(goal_pose)
            vel_msg.linear.y = 0
            vel_msg.linear.z = 0

            # Angular velocity in the z-axis.
            vel_msg.angular.x = 0
            vel_msg.angular.y = 0
            vel_msg.angular.z = self.angular_vel(goal_pose)

            # Publishing our vel_msg
            self.velocity_publisher.publish(vel_msg)

            # Publish at the desired rate.
            self.rate.sleep()

        # Stopping our robot after the movement is over.
        vel_msg.linear.x = 0
        vel_msg.angular.z = 0
        self.velocity_publisher.publish(vel_msg)

        # If we press control + C, the node will stop.
        rospy.spin()

if __name__ == '__main__':
    try:
        x = TurtleBot()
        x.move2goal()
    except rospy.ROSInterruptException:
        pass

를 넣어보세요. 그리고 다시 터미널에서

cd ~/catkin_ws/
catkin_make

를 하시고  

rosrun turtlesim go_to_goal.py

를 누르시면, 골을 주라고 나요죠? 적절한 골을 주면 거북이가 잘 움직이는것을 확인 할 수 있습니다. 

코드는 굉장히 직관적이라서 궁금하시면 한번 보시는걸 추천해드려요. 질문이 있으시거나 더 알고싶으시면 다른 포스트로 찾아오겠습니다. 


Turtlesim에서 할수 있는 다른 재밌는 실험들

 

1. 여러 거북이 생성하기

서로 다른 여러종류의 거북이를 볼 수 있습니다. (거북이는 랜덤입니다) 

rosservice call /spawn 1 7 0.2 "another_turtle1"
rosservice call /spawn 2 6 0.2 "another_turtle2"
rosservice call /spawn 2 9 0.2 "another_turtle3"
rosservice call /spawn 3 4 0.2 "another_turtle4"
rosservice call /spawn 5 4 0.2 "another_turtle5"
rosservice call /spawn 8 5 0.2 "another_turtle6"
rosservice call /spawn 8 6 0.2 "another_turtle7"
rosservice call /spawn 9 9 0.2 "another_turtle8"
rosservice call /spawn 9 1 0.2 "another_turtle9"

 

2. teleop key 

키보드 화살표를 이용하여 거북이를 움직이게 할 수 있어요. 제가 처음에 원을 그린 방법이기도 합니다. 

rosrun turtlesim turtle_teleop_key

TurtleBot3를 이용한 실습 

 

이제 turtlesim말고 저희 프로젝트에 사용한 turtlebot3 로 ROS 실습을 해볼까요? 

 

잠시만요! 저는 터틀봇이 없어요! 하시는 분들을 위해... Tmi...  저도 없습니다. ㅋㅋㅋㅋ 너무 비싸요 ㅋㅋㅋㅋ 저희 팀도 실제 환경에서 테스트 할때 빌려서 사용했습니다.   

 

실제 터틀봇은 이렇게 생겼는데요, 가격이 아주 사악합니다.. (약 40만원) 저희는 그냥 시뮬레이션속에서 사용해볼건데요, 실제에서와 똑같은 행동을 합니다. 

실제 터틀봇 사진

 

저도 터틀봇이 실제로는 없었어서 계속 시뮬레이션으로 코드 작성하고 테스트 하고 했습니다! ㅋㅋ 막상 테스트하려고 실물을 보니 너무 신기하더라구요! (tmi)

시뮬레이션 속의 터틀봇 버거


시뮬레이션의 정확한 설치 방법은 이 사이트를 참고해주시고 저는 간단히만 적어보도록 하겠습니다. 

https://emanual.robotis.com/docs/en/platform/turtlebot3/simulation/

 

ROBOTIS e-Manual

 

emanual.robotis.com

cd ~/catkin_ws/src/
git clone -b melodic-devel https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
cd ~/catkin_ws && catkin_make

 

이후에 

export TURTLEBOT3_MODEL=waffle_pi
# 아님 
export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_gazebo turtlebot3_house.launch

 

를 커미널에 입력해 주세요. 

또 다른 터미널을 실행해서 

 

roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

 

 

를 입력해주세요. 자 이제 키보드를 이용해서 ( w a s d ) 터틀봇을 움직여보세요! 잘 움직여지나요? 

house에서의 실행

만약에 너무 오랜 시간 검은 화면이 나오면 (계속 기다리다보면 위와 같은 화면이 뜨긴 합니다. 다만 컴퓨터 사양에 따라 그냥 렉을 먹는 경우도 있더라고요)  터미널을 끄시고 다시 

 

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_gazebo turtlebot3_world.launch
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

 

를 실행해주세요. 그럼 이런 환경에서 실행할 수 있답니다. 

world

 

이것도 안뜬다! (그럼 컴터를 바꾸실때가 다 되었다는 의미일 수 있...)  그럼 이걸 해보세요! 

 

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch

 

이것도 안뜨면 컴퓨터 바꾸셔야합니다. 정말로.... 제가 도와드릴 수 없어요 ㅋㅋㅋㅋㅋ 아마 이건 뜨셨을거예요..! 

 

empty_world

 

여러분 오해하시면 안되는게, 이 로봇들이 원래 이렇게 이상하게 움직이는건 아닙니다 ㅋㅋㅋ 제가 조종을 잘 못하는거예요! 여러분은 더 잘 조종하셔서 장애물 사이사이를 피해가시길 바랍니다! 


막 적다보니 튜토리얼이 너무 길어진것같아요 ㅋㅋㅋ 어디서부터 어디까지 알려드려야할지 감이 안와서 일단 가장 기본적인것만 알려드렸습니다. 혹시 이 분야에 관심이 있으시거나 더 알고싶으신게 있으면 댓글에 남겨주세요! 

 

제 포스트를 보시고 ROS가 뭔지에 대해 조금이나마 전달이 되었으면 좋겠네요!

 

그럼 저는 이만 이정도에서 인사드리도록하겠습니다! 다들 앞으로 남은 2021년 알차게 보내시길 바랄게요! 화이팅!