Clion에서 ROS 2.0 Foxy 사용하기

|

Ubuntu 20.04와 ROS2 Foxy를 같이 사용할 경우 Clion에서 빌드를 돌리면 다음과 같은 오류가 발생할 수 있습니다.

Could NOT find FastRTPS (missing: FastRTPS_INCLUDE_DIR FastRTPS_LIBRARIES)

이 경우 CMakeLists.txt 파일에 아래 내용을 넣어주면 됩니다.

set(FastRTPS_INCLUDE_DIR /opt/ros/foxy/include)
set(FastRTPS_LIBRARY_RELEASE /opt/ros/foxy/lib/libfastrtps.so)

ROS 2.0 Foxy 설치 방법(apt 이용)

|

ROS2 Foxy Fitzroy 부터는 Ubuntu 20.04가 권장사항입니다. apt install 명령어를 이용해서 설치하려면 Ubuntu 20.04 버전을 이용해야 합니다. (소스 빌드를 하는 경우에는 Ubuntu 18.04에서도 설치 가능합니다.)


Locale 설정

sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8


ROS2 Repository 추가

sudo apt update && sudo apt install curl gnupg2 lsb-release
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -

sudo sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list'


ROS2 패키지 설치

sudo apt update
sudo apt install ros-foxy-desktop


그리고 ROS2 실행 환경을 실행하려면

source /opt/ros/foxy/setup.bash

와 같은 명령어를 실행하면 되며, .bashrc 등에 위 명령어를 추가할 수도 있습니다. 저는 ZShell을 사용 중이고 ROS_DOMAIN_ID 등을 별도로 지정하기 때문에 ~/.zshrc 파일에 아래 내용을 설정해놓고 사용합니다.

function ros2env() {
  export ROS_DOMAIN_ID=$1
  source /opt/ros/foxy/local_setup.zsh
  echo "ROS Domain ID =" $ROS_DOMAIN_ID
}

이러면 어디서나 ros2env 110과 같은 명령어로 ROS 2.0 환경을 불러올 수 있습니다. 띄어쓰기 뒤의 파라메터는 ROS_DOMAIN_ID 값입니다.


부가적 설치

부가적으로 아래 항목들도 설치해놓으면 개발할 때 편리합니다. 특히 가장 아래 부분의 colcon 컴파일러는 꼭 설치하는 편이 좋습니다.

sudo apt install -y python3-pip
pip3 install -U argcomplete

sudo apt install python3-colcon-common-extensions
# pip3 install -U colcon-common-extensions 으로 설치해도 됨


테스트 명령어

각각 다른 터미널에서 아래 명령어를 실행합니다.

ros2 run demo_nodes_cpp talker

ros2 run demo_nodes_py listener

우분투(Ubuntu) 20.04 한글 키보드 설치

|

iBus 기반 한글 키보드 설치

Ubuntu 20.04 LTS 버전 기준으로 한글 키보드를 설치하는 방법입니다. Ubuntu 18.04 이후부터 기본 한글어 입력기가 다시 ibus로 돌아왔습니다. 그래서 저는 그냥 기본 입력기를 사용하고 있습니다.

ibus를 이용한 한글 입력기 활성화 방법은 다음과 같습니다.

  • 메뉴에서 Language Support 실행 → 필요한 파일들 자동으로 설치
  • 메뉴에서 Region & Language 실행
  • Input Sources 항목에서 기본으로 잡혀있던 English는 삭제하고, Korean(Hangul) 선택
  • 만약, Korean(Hangul)이 뜨지 않고 Korean만 표시되는 경우 재부팅을 하면 됩니다.
  • Korean(Hangul) 항목 오른쪽의 설정 버튼 클릭
  • Hangul Toggle KeyAdd 버튼을 누르고 한글 키 입력(ALT_R 또는 Hangul로 표시됩니다.)

SSH 터널링

|

SSH 터널링

SSH 터널링에는 크게 로컬 터널링(Local Tunneling), 리모트 터널링(Remote Tunneling), 다이나믹 터널링(Dynamic Tunneling)이 있습니다. 암호화를 이용한 데이터 패킷 전송 등에 사용되는데, 여기서는 로컬 터널링과 리모트 터널링에 대해 설명해봅니다.


경유 서버 설정

터널링을 위해서는 경유 서버가 필요합니다. 경유 서버에서 다음 설정을 해줍니다. /etc/ssh/sshd_config 파일에 다음 내용을 추가해줍니다.

GatewayPorts yes
AllowTcpForwarding yes

그 이후

sudo service ssh restart

명령어로 ssh 데몬 서비스를 다시 실행합니다.


Local Tunneling

로컬에 있는 특정 포트를 다른 서버 주소로 연결하는 방식입니다.

다음과 같은 커맨드로 사용할 수 있습니다.

ssh -L sourcePort:forwardToHost:destPort connectToHost
ssh -L [로컬 PC 포트]:[타켓 서버 주소]:[타켓 서버 포트] [경유 서버 주소]

ex)
ssh -L 80:intra.example.com:80 gw.example.com

위 명령어는 ‘gw.example.com’ 서버를 경유 서버로 설정하고, 로컬 PC의 80 포트를 ‘ntra.example.com’ 서버의 80 포트로 연결하는 예제입니다.

조금 응용하면 다음과 같은 예제가 가능합니다.

아마존 서버(AWS)의 ssh 서버 포트가 기본적으로 22로 되어 있는데, 이를 8080 포트로 바꾸는 명령어는 다음과 같습니다. 이 경우는 AWS 서버가 타켓 서버가 됨과 동시에 로컬 PC 역할도 담당합니다.

먼저 아마존 서버에 접속한 다음

ssh -i snowdeer-key.pem -L 8080:localhost:22 localhost

명령어를 수행하면 됩니다.

이제 다른 PC에서 AWS 서버에 SSH 접속을 할 때 기존 22번 포트가 아닌 8080 포트를 사용해서 접속할 수 있습니다.

ssh -i snowdeer-key.pem -p 8080 ubuntu@xxx.xxx.xxx.xxx


Remote Tunneling

ssh -R sourcePort:forwardToHost:destPort connectToHost
ssh -R [오픈할 PC 포트]:[타켓 서버 주소]:[타켓 서버 포트] [경유 서버 주소]

ex)
ssh -R 9000:localhost:3000 user@example.com

위 예제는 로컬 PC의 3000 포트를 경유 서버의 9000 번 포트에 바인딩하는 예제입니다.

이 명령어 실행한 다음 example.com:9000 주소로 패킷을 주고 받을 수 있습니다.

Flutter Network Image 예제

|

Flutter Network Image

네트워크로 이미지 받으려면 먼저 Permission을 부여해줘야 합니다.

MacOS 기준으로 macos/Runner/DebugProfile.entitlements 파일에 권한을 줄 수 있습니다.

    <key>com.apple.security.network.client</key>
    <true/>

안드로이드 같은 경우는 AndroidManifest.xml 파일에 인터넷 권한을 부여하면 됩니다.


예제 코드

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Network Image Example',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Network Image Example'),
        ),
        body: NetworkImageWidget(),
      ),
    );
  }
}

class NetworkImageWidget extends StatelessWidget {
  final url = 'https://snowdeer.github.io/public/img/hello_page.jpg';

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Image.network(url),
    );
  }
}