머신러닝

본문 바로가기
사이트 내 전체검색


머신러닝
머신러닝

7. 액션 메시지

페이지 정보

작성자 관리자 댓글 0건 조회 1,635회 작성일 21-01-15 12:24

본문

7. 액션 메시지

1. 액션 메시지


액션 메시지는 앞서 두가지 방식인 토픽과 서비스와는 다르게 응답까지 시간이 필요하고 동작 중간의 중간 상황에 대한 데이터가 필요한 경우 사용되는 통신 방식입니다.


기본적인 동작 구조는 서비스와 유사합니다. 

요청에 따라 응답에 해당하는 목표 goal 와 결과 result 가 있습니다. 

다른점은 응답까지 오랜 시간이 필요하고 중간의 상태 또는 중간 결과가 필요한 경우 피드백 feedback 을 통해 진행 상황을 파악할 수 있습니다. 

동작구조가 서비스와 유사하다면 통신방식은 토픽과 동일하게 비동기식 통신방식을 활용합니다.




1.PNG



클라이언트는 목표를 서버에 전달하고 서버는 수신된 목표에 따라 액션을 수행하는데 정해진 액션을 수행하고 액션에 대한 피드백을 클라이언트에 전달합니다. 

이에 따라 클라이언트는 정해진 목표까지 계속 목표를 수행하도록 하거나 중간에 목표를 변경 또는 취소하도록 명령을 전달할 수 있습니다. 

이러한 액션 메시지는 복잡한 로봇의 업무를 지시하는 역활로 많이 사용됩니다.



2. 액션 서버

'catkin_create_pkg' 명령을 이용하여 패키지를 생성합니다. 
생성되는 패키지에 rospy와 std_msgs, actionlib_msgs 패키지를 포함하도록 명령어 작성시 다음과 같이 입력합니다.

jklee@holdings:~/catkin_ws/src$ catkin_create_pkg actions_tutorial rospy std_msgs actionlib_msgs
Created file actions_tutorial/package.xml
Created file actions_tutorial/CMakeLists.txt
Created folder actions_tutorial/src
Successfully created files in /home/jklee/catkin_ws/src/actions_tutorial. Please adjust the values in package.xml.
jklee@holdings:~/catkin_ws/src$ cd actions_tutorial/
jklee@holdings:~/catkin_ws/src/actions_tutorial$


액션 메시지 등록을 위한 각종 소스코드와 내용들은 이 폴더에 작성합니다. 
폴더로 이동하고 첫번째로 어떠한 구조의 액션 메시지를 등록할 것인지 작성합니다. 
action 폴더를 생성하고 폴더 내부에 WashTheDishes.action 파일을 생성하고 내용을 편집합니다.

jklee@holdings:~/catkin_ws/src/actions_tutorial$ mkdir action
jklee@holdings:~/catkin_ws/src/actions_tutorial$ vi action/WashTheDishes.action

# Goal
int32 number_of_minutes
---
# Result
string[] dishes_washed
---
# Feedback
string last_dish_washed

WashTheDishes.action 파일에 작성한 내용은 총 3 개의 변수의 내용을 담고 있습니다. 
액션의 목표에 해당하는 number_of_minutes 와 결과에 해당하는 dishes_washed, 피드백에 해당하는 last_dish_washed 입니다. 
number_of_minutes 를 이용하여 액션을 동작시키고, 동작이 완료되면 dishes_washed 를 통해 결과를 확인합니다. 
동작을 수행하는중 세척을 완료할 때 마다 last_dish_washed 를 통해 중간 상황을 받아 볼 수 있도록 합니다.
이제 실제로 액션 메시지 등록과 호출시 실행할 소스코드를 작성합니다. src 폴더에 server.py 를 작성합니다.

jklee@holdings:~/catkin_ws/src/actions_tutorial$ vi src/server.py
#! /usr/bin/env python3 
import rospy
import actionlib
from actions_tutorial.msg import WashTheDishesAction, WashTheDishesFeedback, WashTheDishesResult

class ActionServer():
    def __init__(self):
        self.a_server = actionlib.SimpleActionServer(
            "wash_dishes_as", WashTheDishesAction,
            execute_cb=self.execute_cb, auto_start=False)

        self.a_server.start()

    def execute_cb(self, goal):
        success = True
        rate = rospy.Rate(1)

        dish_washed = ''
        result = WashTheDishesResult()

        last_dish_washed = []
        feedback = WashTheDishesFeedback()

        for i in range(0, goal.number_of_minutes):
            if self.a_server.is_preempt_requested():
                success = False
                break

            last_dish_washed = 'bowl ' + str(i)
            feedback.last_dish_washed = last_dish_washed
            self.a_server.publish_feedback(feedback)

            result.dishes_washed.append(last_dish_washed)

            rate.sleep()
 
        if success:
            self.a_server.set_succeeded(result)

if __name__ == "__main__":
    rospy.init_node("Action_Server")
    s = ActionServer()

    rospy.spin()

서버의 노드명칭은 Action_Server 로 작성되어 있습니다. 
액션 처리는 ActionServer클래스에서 처리됩니다. 
ActionServer 클래스를 생성하고 초기화 과정에서 액션 서버를 생성합니다. 
액션의 명칭은 wash_dishes_as 이고 액션의 목표, 결과, 피드백이 담겨있는 파일을 지정합니다. 
파일을 지정할때는 확장자까지 모두 작성할 필요는 없고 파일의 명칭에 Action을 붙여서 지정하면됩니다. 
그리고 액션이 호출되었을 때 작업을 수행할 콜백 메소드를 등록합니다. 
콜백메소드는 execute_cb() 로 작성되어 있습니다. 
액션 호출시 전달된 목표까지 작업을 수행하며 1 회 작업 수행시 마다 피드백을 통해 진행 상황을 알 수 있도록 합니다. 
그리고 작업이 완료되면 작업이 정상적으로 완료되어있다는 것을 확인할 수 있도록 전달합니다.

jklee@holdings:~/catkin_ws/src/actions_tutorial$ chmod +x src/server.py

이제 컴파일을 위한 CMakeLists.txt 파일과 package.xml 파일을 수정합니다.

CMakeLists.txt 에는 컴파일 옵션들을 지정합니다. 
기본적인 내용은 패키지 생성시 미리 작성되어 있습니다. 
서비스 등록을 위한 내용을 추가합니다.


jklee@holdings:~/catkin_ws/src/actions_tutorial$ vi CMakeLists.txt

### 생략
find_package(catkin REQUIRED COMPONENTS
  actionlib_msgs
  rospy
  std_msgs
  message_generation
)
### 생략
add_action_files(
   FILES
   WashTheDishes.action
)
### 생략
generate_messages(
   DEPENDENCIES
   actionlib_msgs
   std_msgs 
)
### 생략


package.xml 파일에는 컴파일 할 때 참조하는 패키지나 실행할 때 참조하는 내용을 입력합니다. 
package.xml 도 CMakeLists.txt 파일과 마찬가지로 패키지 생성시 기본적인 내용은 작성되어 있는상태로 필요한 내용만 추가하거나 주석을 제거하면 됩니다.

jklee@holdings:~/catkin_ws/src/actions_tutorial$ vi package.xml

<!-- 생략 -->
<build_depend>message_generation</build_depend>
<!-- 생략 -->
<exec_depend>message_runtime</exec_depend>
<!-- 생략 -->

컴파일 및 실행을 위한 파일 수정은 완료되었습니다. 
catkin_make 명령을 통해 컴파일을 실행합니다. 
컴파일이 완료되고 나면 완료된 내용을 현재 사용중인 쉘에 적용해야 합니다. 
쉘에 변경사항을 적용하지 않는다면 새로 작성한 패키지의 내용을 찾지 못하거나 등록한 서비스의 내용을 정상적으로 확인하지 못할 수 있습니다. 
변경사항은 ~/catkin_ws/devel 폴더에 파일로 존재합니다. 
현재 사용중인 쉘의 종류에 따라 적용이 될 수 있도록 파일이 구분되어 있습니다. 현재 bash 를 사용중입니다. 
따라서 setup.bash 파일을 source 명령을 통해 적용합니다.

jklee@holdings:~/catkin_ws/src/actions_tutorial$ cd ~/catkin_ws
jklee@holdings:~/catkin_ws$ catkin_make
Base path: /home/jklee/catkin_ws
Source space: /home/jklee/catkin_ws/src
Build space: /home/jklee/catkin_ws/build
Devel space: /home/jklee/catkin_ws/devel
Install space: /home/jklee/catkin_ws/install
####
#### Running command: "cmake /home/jklee/catkin_ws/src -DCATKIN_DEVEL_PREFIX=/home/jklee/catkin_ws/devel -DCMAKE_INSTALL_PREFIX=/home/jklee/catkin_ws/install -G Unix Makefiles" in "/home/jklee/catkin_ws/build"
####
-- Using CATKIN_DEVEL_PREFIX: /home/jklee/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /home/jklee/catkin_ws/devel;/opt/ros/melodic
-- This workspace overlays: /home/jklee/catkin_ws/devel;/opt/ros/melodic
-- Found PythonInterp: /usr/bin/python2 (found suitable version "2.7.17", minimum required is "2")
-- Using PYTHON_EXECUTABLE: /usr/bin/python2
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/jklee/catkin_ws/build/test_results
-- Found gtest sources under '/usr/src/googletest': gtests will be built
-- Found gmock sources under '/usr/src/googletest': gmock will be built
-- Found PythonInterp: /usr/bin/python2 (found version "2.7.17")
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.7.28
-- BUILD_SHARED_LIBS is on
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 3 packages in topological order:
-- ~~  - actions_tutorial
-- ~~  - motor_service
-- ~~  - service_tutorial
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'actions_tutorial'
-- ==> add_subdirectory(actions_tutorial)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- +++ processing catkin package: 'motor_service'
-- ==> add_subdirectory(motor_service)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- motor_service: 0 messages, 1 services
-- +++ processing catkin package: 'service_tutorial'
-- ==> add_subdirectory(service_tutorial)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- service_tutorial: 0 messages, 1 services
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jklee/catkin_ws/build
####
#### Running command: "make -j4 -l4" in "/home/jklee/catkin_ws/build"
####
Scanning dependencies of target std_msgs_generate_messages_eus
Scanning dependencies of target std_msgs_generate_messages_py
Scanning dependencies of target std_msgs_generate_messages_lisp
[  0%] Built target std_msgs_generate_messages_eus
[  0%] Built target std_msgs_generate_messages_lisp
[  0%] Built target std_msgs_generate_messages_py
Scanning dependencies of target std_msgs_generate_messages_nodejs
Scanning dependencies of target std_msgs_generate_messages_cpp
[  0%] Built target std_msgs_generate_messages_nodejs
[  0%] Built target std_msgs_generate_messages_cpp
[  0%] Built target _motor_service_generate_messages_check_deps_motor
[ 21%] Built target motor_service_generate_messages_lisp
[ 21%] Built target motor_service_generate_messages_py
[ 35%] Built target motor_service_generate_messages_eus
[ 35%] Built target _service_tutorial_generate_messages_check_deps_AddInts
[ 50%] Built target motor_service_generate_messages_nodejs
[ 50%] Built target motor_service_generate_messages_cpp
[ 57%] Built target service_tutorial_generate_messages_lisp
[ 71%] Built target service_tutorial_generate_messages_eus
[ 78%] Built target service_tutorial_generate_messages_cpp
[ 85%] Built target service_tutorial_generate_messages_nodejs
[100%] Built target service_tutorial_generate_messages_py
[100%] Built target motor_service_generate_messages
[100%] Built target service_tutorial_generate_messages
jklee@holdings:~/catkin_ws$

jklee@holdings:~/catkin_ws$ source devel/setup.bash


이제 프로그램 실행을 위해 첫번째 터미널에서 마스터노드를 실행합니다. 
마스터 노드 실행 명령은 roscore 입니다.

jklee@holdings:~$ roscore

새로 작성한 노드는 마스터 노드가 실행되어 있지 않았다면 정상적으로 실행되지 않습니다. 
마스터 노드 실행된 이후에 마스터노드가 실행되지 않은 두번째 터미널에서 rosrun 명령을 통해 컴파일한 패키지를 실행합니다.

jklee@holdings:~/catkin_ws$ rosrun actions_tutorial server.py

액션 서버를 실행하면 아무런 메시지도 화면에 출력되지않습니다. 
정상적으로 서버가 동작되고 액션 메시지가 등록되었는지 확인하려면 rosmsg 명령을 활용합니다. 
rosmsg list 는 현재 동작중인 ROS 에서 사용가능한 메시지의 목록을 출력합니다. 
ROS 실행시 기본적으로 여러가지 메시지들이 등록되어 있어 내가 등록한 메시지를 찾을 때는 grep 명령을 함께 활용하는 것이 효율적입니다.
 

jklee@holdings:~/catkin_ws$ rosmsg list | grep actions_tutorial
actions_tutorial/WashTheDishesAction
actions_tutorial/WashTheDishesActionFeedback
actions_tutorial/WashTheDishesActionGoal
actions_tutorial/WashTheDishesActionResult
actions_tutorial/WashTheDishesFeedback
actions_tutorial/WashTheDishesGoal
actions_tutorial/WashTheDishesResult
jklee@holdings:~/catkin_ws$



3. 액션 클라이언트

작성한 액션을 통해 명령을 내리고 결과를 수신하는 클라이언트를 작성합니다. 
서버와 마찬가지로 src 폴더에 프로그램을 작성합니다.

jklee@holdings:~/catkin_ws/src/actions_tutorial$ vi src/client.py

#! /usr/bin/env python3

import rospy
import actionlib
from actions_tutorial.msg import WashTheDishesAction, WashTheDishesGoal

def feedback_cb(msg):
    print("Feedback: ", msg)

def call_server():
    client = actionlib.SimpleActionClient('wash_dishes_as', WashTheDishesAction)

    client.wait_for_server()

    goal = WashTheDishesGoal()
    goal.number_of_minutes = 7

    client.send_goal(goal, feedback_cb=feedback_cb)
    client.wait_for_result()
    result = client.get_result()

    del(client)
    return result

if __name__ == "__main__":
    rospy.init_node("Action_Client")

    print("Result is ''", call_server())


액션을 호출하는 클라이언트입니다. 
Action_Client 라는 명칭의 노드를 등록하고 액션을 호출합니다. 
현재 실행중인 ROS 에 액션이 등록되어 있는지 확인하고 액션이 등록되어 있다면 해당 액션에 목표를 지정하여 작업을 수행하도록 호출합니다. 
이 때 피드백을 받을 콜백 메소드를 등록하여 피드백이 수신될 떄 마다 화면에 수신된 메시지를 출력합니다. 
주기적으로 피드백을 수신하며 결과가 수신될 때까지 대기하고 결과가 수신되면 결과를 화면에 출력합니다.

프로그램 작성이 완료되면 rosrun 명령을 통해 클라이언트를 실행합니다. 
액션을 수행하는 횟수에 따라 피드백이 수신되고 결과가 수신되는 것을 확인할 수 있습니다.

jklee@holdings:~/catkin_ws/src/actions_tutorial$ chmod +x src/client.py

jklee@holdings:~/catkin_ws/src/actions_tutorial$ rosrun actions_tutorial client.py
Feedback:  last_dish_washed: "bowl 0"
Feedback:  last_dish_washed: "bowl 1"
Feedback:  last_dish_washed: "bowl 2"
Feedback:  last_dish_washed: "bowl 3"
Feedback:  last_dish_washed: "bowl 4"
Feedback:  last_dish_washed: "bowl 5"
Feedback:  last_dish_washed: "bowl 6"
Result is '' dishes_washed:
  - bowl 0
  - bowl 1
  - bowl 2
  - bowl 3
  - bowl 4
  - bowl 5
  - bowl 6
jklee@holdings:~/catkin_ws/src/actions_tutorial$

 

댓글목록

등록된 댓글이 없습니다.


개인정보취급방침 서비스이용약관 모바일 버전으로 보기 상단으로

TEL. 063-469-4551 FAX. 063-469-4560 전북 군산시 대학로 558
군산대학교 컴퓨터정보공학과

Copyright © www.leelab.co.kr. All rights reserved.