키보드를 이용해서 Service Request를 날리고 이벤트를 Subscription하는 예제(Python)

|

키보드를 이용해서 Service Request를 날리고 이벤트를 Subscription하는 예제

import threading
import rclpy, os
import datetime

from tts_service.srv._tts_request import TtsRequest
from tts_service.msg import TtsEvent

NODE_NAME = "tts_service_controller"

client = None;


def callback_on_tts_event_arrived(msg):
    curTime = datetime.datetime.now()
    if msg.event == TtsEvent.EVENT_ON_TTS_STARTED:
        print("[{0}] EVENT_TTS_STARTED".format(curTime))
    elif msg.event == TtsEvent.EVENT_ON_TTS_FINISHED:
        print("[{0}] EVENT_TTS_FINISHED".format(curTime))


def handle_keyboard():
    global client

    while True:
        print("\n")
        print("   1. Request to Speech Text ('Hello')")
        print("   99. Exit")

        menu = input('Input the menu: ')

        if menu == '1':
            req = TtsRequest.Request()
            req.text = "Hello"
            client.call_async(req)

        elif menu == '99':
            rclpy.shutdown()
            os._exit(1)


def main(args=None):
    global client

    rclpy.init(args=args)

    node = rclpy.create_node(NODE_NAME)
    client = node.create_client(TtsRequest, TtsRequest.Request.NAME)
    subscription = node.create_subscription(TtsEvent, TtsEvent.NAME, callback_on_tts_event_arrived)

    th = threading.Thread(target=handle_keyboard)
    th.start()

    try:
        rclpy.spin(node)
    finally:
        node.destroy_node()
        rclpy.shutdown()


if __name__ == '__main__':
    main()
</pre>

ROS 2.0 Bouncy Android 설치 방법

|

ROS 2.0 Android 설치 방법입니다. 기존의 Ardent 버전에 비해서 크게 변경된 점은 없습니다. 공식 홈페이지는 여기입니다.

여기서는 Ubuntu 18.04 기준으로 설명을 적지만, Ubuntu 16.04에서도 동일하게 동작합니다.

ROS 2.0 Java는 설치하지 않아도 됩니다.


JDK 설치

sudo apt-add-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer


gradle 3.2 이상 버전으로 업그레이드

sudo add-apt-repository ppa:cwchien/gradle
sudo apt install -y gradle


Ament Workspace 다운로드

ROOT_DIR=${HOME}
AMENT_WORKSPACE=${ROOT_DIR}/ament_ws
ROS2_ANDROID_WORKSPACE=${ROOT_DIR}/ros2_android_ws

mkdir -p ${AMENT_WORKSPACE}/src
cd ${AMENT_WORKSPACE}
wget https://raw.githubusercontent.com/esteve/ament_java/master/ament_java.repos
vcs import ${AMENT_WORKSPACE}/src < ament_java.repos
src/ament/ament_tools/scripts/ament.py build --symlink-install --isolated


ROS2 for Java 설치

mkdir -p ~/ros2_java_ws/src
cd ~/ros2_java_ws
curl -skL https://raw.githubusercontent.com/esteve/ros2_java/master/ros2_java_desktop.repos -o ros2_java_desktop.repos
vcs import src < ros2_java_desktop.repos
. ../ament_ws/install_isolated/local_setup.sh
ament build --symlink-install --isolated


Android NDK 설치

공식 홈페이지에서 NDK를 다운로드 합니다. ROS2 for Android 설치 가이드에서는 ~/android_ndk에 압축 해제를 권장하지만, 여기서는 폴더 구조를 조금 더 깔끔하게 가져가기 위해서 ~/Android/Ndk에 압축 해제를 합니다.(Android Studio를 설치했을 때 SDK를 ~/Android/SDK에 설치하기 때문에 통일성을 맞추기 위해서입니다.)

즉, NDK 설치 경로는 ~/Android/Ndk/android-ndk-r17b입니다.

그리고 환경 변수를 다음과 같이 등록해줍니다.

export ANDROID_NDK=~/Android/Ndk/android-ndk-r17b


ROS2 for Android 다운로드

export PYTHON3_EXEC="$( which python3 )"
export ANDROID_ABI=armeabi-v7a
export ANDROID_NATIVE_API_LEVEL=android-21
export ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-clang


mkdir -p ${ROS2_ANDROID_WORKSPACE}/src
cd ${ROS2_ANDROID_WORKSPACE}
wget https://raw.githubusercontent.com/esteve/ros2_java/master/ros2_java_android.repos
vcs import ${ROS2_ANDROID_WORKSPACE}/src < ros2_java_android.repos
source ${AMENT_WORKSPACE}/install_isolated/local_setup.sh

ROS2 for Android 빌드

ament build --isolated --skip-packages test_msgs \
  --cmake-args \
  -DPYTHON_EXECUTABLE=${PYTHON3_EXEC} \
  -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
  -DANDROID_FUNCTION_LEVEL_LINKING=OFF \
  -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \
  -DANDROID_TOOLCHAIN_NAME=${ANDROID_TOOLCHAIN_NAME} \
  -DANDROID_STL=gnustl_shared \
  -DANDROID_ABI=${ANDROID_ABI} \
  -DANDROID_NDK=${ANDROID_NDK} \
  -DTHIRDPARTY=ON \
  -DCOMPILE_EXAMPLES=OFF \
  -DCMAKE_FIND_ROOT_PATH="$AMENT_WORKSPACE/install_isolated;$ROS2_ANDROID_WORKSPACE/install_isolated" \
  -- \
  --parallel \
  --ament-gradle-args \
  -Pament.android_stl=gnustl_shared -Pament.android_abi=$ANDROID_ABI -Pament.android_ndk=$ANDROID_NDK --

.bashrc에 환경 변수 추가

.bashrc에 아래 항목을 추가해줍니다.

# for Java
export JAVA_HOME=/usr/lib/jvm/java-8-oracle

# for Android
export ANDROID_SDK=~/Android/Sdk
export ANDROID_NDK=~/Android/Ndk/android-ndk-r17b
export ANDROID_HOME=$ANDROID_SDK

export PATH=$PATH:$ANDROID_SDK:$ANDROID_TOOLS:$ANDROID_NDK:$ANDROID_HOME/tools:$ANDROID_SDK/platform-tools


android_bouncy.sh 생성

이 파일은 꼭 만들 필요는 없지만, 만들어두면 편리하게 사용할 수 있습니다.

ROOT_DIR=${HOME}
AMENT_WORKSPACE=${ROOT_DIR}/ament_ws
ROS2_ANDROID_WORKSPACE=${ROOT_DIR}/ros2_android_ws

export PYTHON3_EXEC="$( which python3 )"
export ANDROID_ABI=armeabi-v7a
export ANDROID_NATIVE_API_LEVEL=android-21
export ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-clang

source ~/ament_ws/install_isolated/local_setup.sh
source ~/ros2_android_ws/install_isolated/local_setup.bash

그 이후 안드로이드 ROS2 환경이 필요하면 터미널 실행했을 때마다 source android_bouncy.sh를 실행해주면 됩니다.

Message Handler 구현 예제 (Looper 활용)

|

Message Handler 구현 예제

Thread를 상속받아 구현했으며, Thread 내부에서 Handler를 생성하기 위해서 Looper를 이용한 예제입니다.


MessageHandler.java

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public abstract class MessageHandler extends Thread {

  Handler mHandler;

  @Override
  public void init() {
    this.start();
  }

  @Override
  public void fin() {
    this.interrupt();
  }

  @Override
  public void run() {
    Looper.prepare();

    mHandler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
        handle(msg);
      }
    };

    Looper.loop();
  }

  public abstract void handle(Message msg);

  public synchronized void sendMessage(Message msg) {
    mHandler.sendMessage(msg);
  }
}


사용 방법

추상 클래스이기 때문에 상속받아서 구체화된 클래스를 만들어 사용하면 됩니다. 사용 예제는 다음과 같습니다.

public class SampleComponent {

  public o() {
    messageHandler = new MessageHandler() {
      @Override
      public void handle(Message msg) {
        handleMessage(msg);
      }
    };
  }

  public void handleMessage(Message msg) {
    switch (msg.what) {
      case MESSAGE.DEBUG_ON:
        // TODO 
        break;
      case MESSAGE.DEBUG_OFF:
        // TODO
        break;
    }
  }
}

ROS 2.0 Bouncy Java 설치 방법

|

ROS 2.0 Java 설치 방법입니다. 기존의 Ardent 버전에 비해서 크게 변경된 점은 없습니다. 공식 홈페이지는 여기입니다.

여기서는 Ubuntu 18.04 기준으로 설명을 적지만, Ubuntu 16.04에서도 동일하게 동작합니다.


JDK 설치

sudo apt-add-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer


gradle 3.2 이상 버전으로 업그레이드

sudo add-apt-repository ppa:cwchien/gradle
sudo apt install -y gradle


ROS2 for Java 설치

mkdir -p ~/ros2_java_ws/src
cd ~/ros2_java_ws
curl -skL https://raw.githubusercontent.com/esteve/ros2_java/master/ros2_java_desktop.repos -o ros2_java_desktop.repos
vcs import src < ros2_java_desktop.repos
. ../ament_ws/install_isolated/local_setup.sh
ament build --symlink-install --isolated

Tkinter를 이용해서 Image Loader 구현해보기

|

Tinker를 이용해서 Image Loader 구현해보기

import tkinter as tk

images = ["01.png", "02.png"]


class ImageViewer():

    def __init__(self, window):
        self.canvas = tk.Canvas(window, width=1280, height=800)
        self.canvas.grid(row=0, column=0)

        self.button = tk.Button(window, text="Load Image", command=self.on_button_clicked)
        self.button.grid(row=1, column=0)

        self.img = None
        self.image_on_canvas = self.canvas.create_image(0, 0, anchor=tk.NW)
        self.image_idx = 1

    def on_button_clicked(self):
        self.img = tk.PhotoImage(file=images[self.image_idx])
        self.canvas.itemconfig(self.image_on_canvas, image=self.img)
        self.image_idx = 1 - self.image_idx
        pass


window = tk.Tk()
window.title("Image Viewer Sample")
ImageViewer(window)
window.mainloop()