Tnote

ROS, turtlesim 활용해 python 기초 코딩 본문

ROS

ROS, turtlesim 활용해 python 기초 코딩

jfl 2022. 2. 6. 17:57

#0 기본 설정

Ubuntu에 ROS, vscode 다운 받은 상태라 가정

새로 만든 폴더에 catkin 빌드 한 상태라 가정 (참고 : https://jfl2dh.tistory.com/8)

 

#1 turtlesim 실행 (참고 : https://jfl2dh.tistory.com/7)

1) 새 터미널 열고 roscore 입력 후 실행

2) 1번과 다른 터미널 열고 rosrun turtlesim turtlesim_node 입력 후 실행

 

#2 원하는 데이터(topic) 찾기

1) 새 터미널 열고 rostopic list 입력 후 실행

- /turtle1으로 시작 것이 turtlesim과 관련된 topic

2) rostopic info 토픽이름

- ex) rostopic info /turtle1/cmd_vel

* [명령어] rostopic info 토픽이름 : 해당 토픽 정보 확인

3개의 topic 정보를 살펴보면 '/turtle1/cmd_vel' 이름의 topic만 Subscribers에 "/turtlesim" 노드(프로그램)이 연결 되어있고, 나머지 '/turtle1/color_sensor', '/turtle1/pose' 는 Publishers에 "/turtlesim" 노드가 연결되어 있다.

즉, "/turtlesim" 이라는 노드(프로그램)는 '/turtle1/cmd_vel' 토픽을 받고(Subscribers), '/turtle1/color_sensor'과 '/turtle1/pose' 토픽을 준다(Publishers).

*더 자세한 사항은 #1의 링크 참고

 

우리는 '/turtle1/pose' 토픽을 받아서 '/turtle1/cmd_vel' 토픽을 "/turtlesim" 노드(프로그램)에 준다.

Subscriber : /turtle1/pose

Publisher : /turtle1/cmd_vel

 

- 전체코드 미리보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#! /usr/bin/env python
import rospy
from turtlesim.msg import Pose
from geometry_msgs.msg import Twist
 
class turtle_study:
    def __init__(self):
        self.turtle_sub = rospy.Subscriber('/turtle1/pose', Pose, self.callback)
        self.turtle_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
        
    def callback(self, data):
        velocity = Twist()
        global count, x0
 
        #print(count)
 
        if count == 0:
            x0 = data.x
    
        if abs(data.x - x0) >= 2:      velocity.linear.x = 0
        else:                          velocity.linear.x = 2
        
        self.turtle_pub.publish(velocity)
        
        count += 1
 
 
 
def run():
    rospy.init_node('turtle_study1', anonymous=True)
    turtle1 = turtle_study()
    rospy.spin()
 
if __name__ == "__main__":
    count = 0
    switch = 0
    run()
    
    
cs

=> 실행해 보면 거북이가 2의 거리만큼 이동하면 멈춘다. 

 

#3 topic의 정보 확인

2번에서 원하는 데이터를 찾았다면 rostopic info 에서 Type을 기억한다.

- '/turtle1/pose' 토픽의 msg(메시지) 이름 : geometry_msgs/Twist

- '/turtle1/cmd_vel' 토픽의 msg 이름 : turtlesim/Pose

 

=>이것이 나중에 코딩할 때 사용됨. (아래 예시)

1
2
3
4
#! /usr/bin/env python
import rospy
from turtlesim.msg import Pose
from geometry_msgs.msg import Twist
cs

 

#4 code 노드와 "/turtlesim" 노드(프로그램)을 연결하기

* rqt_graph : 노드, 토픽의 관계를 시각화 해준다.

위 그림처럼 연결해주기 위해서 rospy의 Subscriber, Publisher 코드를 사용한다.

rospy.Subscriber('토픽이름', 메시지이름, 객체(변수))

rospy.Publisher('토픽이름', 메시지이름, queue_size)

 

- 객체 : 포인터 개념은 생략하고, 일단은 Subscriber로 받은 데이터를 어디로 줄 것인가? 정도로 이해

- queue_size : 발행할 때 얼만큼의 사이즈로 보낼 것인지. 적정한 queue 사이즈를 정하는게 문제

 

- 코드 예시

6
7
8
9
class turtle_study:
    def __init__(self):
        self.turtle_sub = rospy.Subscriber('/turtle1/pose', Pose, self.callback)
        self.turtle_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
cs

python 문법 설명은 생략,

8 : "/turtlesim" 노드가 주는, "Pose" 메시지의 '/turtle1/pose' 토픽을 self.callback 객체로 주겠다. ( 거북 -> 나 )

9 : 우리가 "Twist" 메시지의 '/turtle1/cmd_vel' 토픽을 10의 큐 사이즈로 "/turtlesim" 노드에게 주겠다. ( 나 -> 거북 )

 

#5 노드 설정 및 코드 구성 마무리

29
30
31
32
33
34
35
36
37
def run():
    rospy.init_node('turtle_study1', anonymous=True)
    turtle1 = turtle_study()
    rospy.spin()
 
if __name__ == "__main__":
    count = 0
    switch = 0
    run()
cs

- 실행 순서대로 코드 설명

34 : 이 이름공간의 이름이 메인이 된다면 .... -> 이 코드가 실행된다면 35, 36, 37번째 코드 실행

     실질적으로 import 말고는 가장 먼저 실행되는 코드

35 : count 변수(객체)에 0 저장(할당)

36 : switch 변수에 0 저장

37 : 29번에 있는 run 함수 실행(호출)

29 : 함수 이름 run 이다. (양식)

30 : 노드의 이름 선언

31 : turtle_study 클래스 실행(호출)

32 : 터미널에 ctrl+c 입력 전 까지 callback 반복

 

#6 코딩 (상세한 설명은 생략) 

- 이 포스팅에는 callback 함수안에서 이루어 지지만 다양한 방법이 있다.

 

- Subscriber해서 오는 데이터는 data변수로 온다.  ex) data.x -> '/turtle1/pose' 토픽의 x값 = 거북이 x좌표

토픽에 어떤 데이터가 오는지 알기 위해선, 위 #3 에서의 msg를 통해 알 수 있는데,

'/turtle1/pose'의 정보는 아래와 같다.

* [명령어] rosmsg show 메시지타입 : 해당 메시지 정보 확인

* 여기서 주의할 점은 pose(위치) 데이터는 어디에 소속되어 있지 않지만, '/turtle1/cmd_vel' 토픽을 보면,

위 그림처럼 linear의 x, y, z angular의 x, y, z 이런 식으로 되어있으니 확인해 볼 것.

 

- 코드의 개략적인 흐름은

1. 변수에 메시지 호출 : 지금은 Publisher를 하기위해서 변수와 메시지를 연결한다 정도만 이해.(그래서 수정이 가능)

2. 제어(멈추거나, 직진하거나)

3. 제어로 결정된 최종적인 값 전달(여기서는 속력)

* 여기서 가장 햇갈렸던 부분이 13~22번에서 아무리 지지고 볶아봤자 가장 마지막에 결정된 값이 23번을 통해 한번 전달되는 점이었다.

 

- 1, 3번은 양식으로 무조건 있어야 하고, 2번을 수정하여 거북이를 제어하는 것.

 

#마무리

간단하게 설명하면, 로봇(위 거북이)의 현재 상태(데이터)를 받아서 제어(속도, 방향 등 조종)한 값(데이터)를 다시 로봇으로 전달해주는 과정을 해본 것이다. 

 

기존에 있는 것 : rosrun turtlesim turtle_teleop_key 명령어를 입력하면, 거북이를 방향키로 조종할 수 있다.

우리가 만든 것 : rosrun 패키지 우리가만든파이썬파일 명령어를 입력하면, 거북이를 한방향으로 2만큼 움직일 수 있다.

 

=> 기존에 있는 걸 구글링이나 다른 매체를 통해 검색해보면서 우리가 직접 만들어 보면 금방 익숙해 진다고 믿는다. 

 

감사합니다.

'ROS' 카테고리의 다른 글

ROS, hector_slam  (0) 2022.02.21
ROS, launch 파일(.xml)  (0) 2022.02.20
ROS, 패키지 만들기, catkin 빌드하기  (0) 2022.02.05
ROS, turtlesim을 활용한 데이터 이동 확인  (0) 2022.02.04
ROS 설치 확인법  (0) 2022.02.04