ROS_5) 노드 간 N:N 통신 주고받기 & 나만의 메시지 만들기

한우진·2023년 4월 25일
0

ROS

목록 보기
5/6
post-thumbnail

1:1 통신 예제

통신 구조


Directory 구조


$ cd ~/xycar_ws/src
$ catkin_create_pkg msg_send std_msgs rospy
//패키지 만든다, 패키지 이름, 패키지가 의존하고 있는 다른 패키지 나열
$ mkdir launch
//msg_send 아래 launch 파일을 만듬(xml로 이루어짐)
$ cm
//새로 만든 패키지를 빌드

teacher.py

#!/usr/bin/env python

```
파이썬에서는 #!으로 시작하는 라인을 Shebang 라인이라고 한다. Sharp(#) + Bang(!)의 합성어로 스크립트 파일의 첫줄에 사용되고 스크립트를 실행하는 데 사용되는 인터프리터를 지정한다. shebang이 들어가면 터미널에서 python을 붙이지 않고 바로 ./teacher.py 형태로 실행도 가능하다
```
import rospy
from std_msgs.msg import String

```
rospy 라이브러리를 import한다. rospy는 ROS에서 파이썬을 사용하기 위한 라이브러리이다.
std_msgs.msg 라는 ROS의 표준 패키지에서 String 부분을 가져와 사용하겠다는 의미이다. 더 여러개의 모듈을 가져올 수 있다

```

rospy.init_node('teacher')

#정수나 문자열을 선언하고 초기화하는 것 처럼 teacher라는 이름의 ROS노드를 선언하고 초기화

pub = rospy.Publisher('my_topic', String)

#my_topic 이라는 토픽에 string 메시지를 받아 발행하기 위해 Publisher 객체를 선언했다
#2번째 매개변수 String은 위에서 선언한 std_msgs.msg import String의 String이다

rate = rospy.Rate(2)

#발행 빈도를 2Hz로 설정하는 부분이다. 1초에 2번 반복할 수 있도록 rate 객체를 선언했다

while not rospy.is_shutdown(): #rospy가 종료되기 전까지 무한히 반복하면서
    pub.publish('call me please')
    rate.sleep()

#위에서 발행한 pub을 이용해 my_topic에 call me please 라는 문자열 메시지를 계속 발행한다
#위에서 호출한 rate 객체에 sleep()함수를 걸어줬다. 이는 while문이 종료되기 전까지 무한 반복되는 동안
#while 반복문 안에 rate.sleep()이 있기 때문에 0.5초에 한번씩 동작할 수 있도록 제어해주는 역할을 한다. 

student.py

#!/usr/bin/env python

import rospy
from std_msgs.msg import String

```
teacher.py에서 설명한 바와 같이 첫번째 줄은 스크립트가 파이썬 인터프리터를 사용해 실행할 수 있도록 하는
shebang라인이다. python을 붙이지 않고 ./student.py 와 같은 명령만으로도 실행시킬 수 있다
ROS 노드를 파이썬 코드로 생성하고 통신할 수 있도록 하는 라이브러리를 import하고
ROS 표준 메시지 패키지 std_mgms에서 문자열 타입인 String 메시지 타입을 가져오도록 하는 라인이다
```

def callback(msg):
    print msg.data

# def는 함수를 선언하고 정의할때 쓰는 용어다. callback이라는 함수를(msg)라는 매개변수를 가지고 있는 채로 선언했다
#이 함수는 callback(msg)형태로 사용하는데 msg에 들어온 값을 print(출력) 한다

rospy.init_node('student')

#teacher.py와 같이 student라는 이름의 ROS 노드를 선언하고 초기화 해준다. 다른 노드와 통신하기 위함이다

sub = rospy.Subscriber('my_topic', String, callback)

#my_topic에 대해서 구독자를 생성하고 String 타입의 메시지를 받아 callback 함수를 호출한다
#그리고 구독자의 인스턴스는 sub에 저장이 되며 토픽(메시지)를 받을 때 마다 callback함수가 호출된다

rospy.spin()

#rospy.spin()함수는 노드가 종료될 때까지 메시지를 계속 받고 callback 함수를 호출하는 무한 루프를 생성한다
#rospy.sleep()과 유사할 수 있는데 이 함수는 spin()과 다르게 특정한 시간동안만 동작한다는 부분이다

Launch 파일 작성 및 실행

$ gedit m_send.launch
$ cm
//빌드
$ chmod +x teacher.py student.py
$ roslaunch msg_send m_send.launch
<launch>
	<node pkg="msg_send" type="teacher.py" name="Teacher"/>
    <node pks="msg_send" type="student.py" name="student" output="screen"/>
</launch>

N:N 통신 예제

통신 구조

코드는 위의 코드와 똑같이 해주면 되는데 하나의 코드로 여러 개의 노드를 연결하기 위해선 각 노드의 이름이 달라야 한다 따라서

  • 노드의 init 함수에서 anonymous=True ㄱ밧을 넣어주면 노드 이름을 자동 설정할 수 있다
  • ex) rospy.init_node('student', anonymous=True)

터미널을 띄워 놓고

$ rosrun msg_send teacher_int-1.py
$ rosrun msg_send teacher_int-2.py
$ rosrun msg_send teacher_int-3.py

처럼 3개의 파일을 적어놓고 3번 실행하는 것이 아니라

launch 파일을 사용해서 roslaunch 명령으로 여러 노드를 띄울 수 있다

<launch>
	<node pkg="msg_send" type="teacher_int.py" name="teacher1"/>
    <node pkg="msg_send" type="teacher_int.py" name="teacher"2/>
    <node pkg="msg_send" type="teacher_int.py" name="teacher3"/>
    <node pks="msg_send" type="student_int.py" name="student1" output="screen"/>
    <node pks="msg_send" type="student_int.py" name="student2" output="screen"/>
    <node pks="msg_send" type="student_int.py" name="student3" output="screen"/>
</launch>

1:N 통신, N:1 통신

<launch>
	<node pkg="msg_send" type="teacher_int.py" name="teacher"/>
    <node pks="msg_send" type="student_int.py" name="student1" output="screen"/>
    <node pks="msg_send" type="student_int.py" name="student2" output="screen"/>
    <node pks="msg_send" type="student_int.py" name="student3" output="screen"/>
</launch>

<launch>
	<node pkg="msg_send" type="teacher_int.py" name="teacher1"/>
    <node pkg="msg_send" type="teacher_int.py" name="teacher"2/>
    <node pkg="msg_send" type="teacher_int.py" name="teacher3"/>
    <node pks="msg_send" type="student_int.py" name="student" output="screen"/>
</launch>

응용해서 1:N 이나 N:1이나 코드에는 anonymous=True 값을 설정해줘서 여러개의 노드를 띄워도 알아서 이름을 바꿔 생성할 수 있도록 처리해준뒤 Launch 파일의 xml 코드를 수정해서 한번에 여러개의 노드를 실행시킬 수 있다


나만의 메시지 만들기

폴더 구조

코드

$ cd ~/xycar_ws/src
$ roscd msg_send
$ mkdir msg
$ cd msg
$ gedit my_msg.msg

my_msg.msg

string first_name
string last_name
int32 age
int32 score
string phone_number
int32 id_number

msg_sender.py

#!/usr/bin/env python

import rospy
from msg_send.msg import my_msg

rospy.init_node('msg_sender', anonymous=True)
pub = rospy.Publisher('msg_to_xycar', my_msg)

msg = my_msg()
msg.first_name = "woojin"
msg.last_name = "Han"
msg.id_number = 12345678
msg.phone_number = "010-1234-5678"

rate = rospy.Rate(1)
while not rospy.is_shutdown():
	pub.publish(msg)
	print("sending message")
	rate.sleep()

msg_receiver.py

#!/usr/bin/env python3

import rospy
from msg_send.msg import my_msg

def callback(msg):
    print ("1. Name: ", msg.last_name + msg.first_name)
    print ("2. ID: ", msg.id_number)
    print ("3. Phone Number: " , msg.phone_number)
    
rospy.init_node('msg_receiver', anonymous=True)

sub = rospy.Subscriber('msg_to_xycar', my_msg, callback)

rospy.spin()

package.xml, CmakeLists.txt 수정

  • ~/xycar_ws/src/msg_send/에 위치해있음
$ gedit package.xml

파일 아래 쪽에

  • <build_depend>message_generation</build_depend>
  • <exec_depend>message_runtime</exec_depend>

$ cm
$ rosmsg show my_msg
//결과 확인
$ ~/xycar_ws/devel/lib/python2.7/dist_packages/msg_send/msg
//여기 디렉토리에서 생성된 msg 확인 가능
$ cm
$ roscore
$ rosrun msg_send msg_receiver.py
$ rosrun msg_send msg.sender.py

0개의 댓글