이번 강의에서는 Qt Designer를 사용해서 turtlebot3_burger_gui.ui 파일을 처음부터 하나씩 만들고, 각 단계마다 Python 코드를 작성해서 추가한 컴포넌트를 바로 사용하는 방식으로 실습합니다.
최종 목표는 TurtleBot3 Burger를 제어할 수 있는 PyQt 기반 GUI를 만드는 것입니다.
GUI에서 다룰 기능은 다음과 같습니다.
- ROS 2 연결
- TurtleBot3 Burger bringup 실행
- SLAM 실행
- Nav2 실행
- RViz2 실행
/cmd_vel수동 주행 명령 발행/odom위치 표시/scan최소 거리 표시- Nav2 목표 좌표 전송
- Initial Pose 발행
- 실행 로그 표시
실습 환경은 다음과 같습니다.
- Ubuntu 22.04
- ROS 2 Humble
- TurtleBot3 Burger
- Python 3
- PyQt5
- Qt Designer
1. Qt Designer 실행하기
터미널에서 Qt Designer를 실행합니다.
designer
Qt Designer가 실행되면 새 폼을 선택하는 창이 나옵니다.
다음 순서대로 선택합니다.
Main Window선택Create클릭

이제 빈 QMainWindow 화면이 열립니다.
오른쪽 Object Inspector에서 최상위 객체 이름을 확인합니다. 기본값은 보통 MainWindow입니다.

이번 강의에서는 최상위 객체 이름을 다음처럼 변경합니다.
TurtleBot3BurgerMainWindow
변경 방법은 다음과 같습니다.
- Object Inspector에서
MainWindow클릭 - 오른쪽 Property Editor에서
objectName찾기 - 값을
TurtleBot3BurgerMainWindow로 변경

그 다음 창 제목을 변경합니다.
Property Editor에서 windowTitle 값을 다음처럼 입력합니다.
TurtleBot3 Burger ROS2 Humble Control GUI

창 크기는 다음과 같이 설정합니다.
width: 1180
height: 760
설정 방법은 다음과 같습니다.
- 최상위 MainWindow 선택
- Property Editor에서
geometry항목 열기 - Width를
1180으로 설정 - Height를
760으로 설정

여기까지 완료한 뒤 파일을 저장합니다.
turtlebot3_burger_gui.ui

2. 첫 번째 Python 코드 작성하기
이제 방금 만든 .ui 파일을 Python에서 열어보겠습니다.
turtlebot3_burger_gui_node.py 파일을 생성합니다.
cd pyqt_ws/src/pyqt_component_gui/pyqt_component_gui
touch turtlebot3_burger_gui_node.py

아래 코드를 작성합니다.
import sys
from pathlib import Path
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
ui_path = Path(__file__).with_name('turtlebot3_burger_gui.ui')
uic.loadUi(str(ui_path), self)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
저장 후 실행합니다.
python3 turtlebot3_burger_gui_node.py
빈 창이 뜨면 성공입니다.


여기서 중요한 점은 .ui 파일을 Python 코드로 변환하지 않았다는 것입니다.
PyQt에서는 다음 코드로 .ui 파일을 직접 불러올 수 있습니다.
uic.loadUi(str(ui_path), self)
이 방식의 장점은 Qt Designer에서 UI를 수정한 뒤 Python 코드를 크게 바꾸지 않아도 된다는 것입니다.
3. ROS 2 System 영역 만들기
이제 첫 번째 기능 영역을 만듭니다.
이 영역은 ROS 2 연결, Domain ID 설정, Namespace 설정을 담당합니다.
Qt Designer에서 왼쪽 Widget Box를 봅니다.
Group Box를 검색하거나 Containers 항목에서 Group Box를 찾습니다.
MainWindow 중앙 영역에 Group Box를 하나 추가합니다.
Property Editor에서 다음과 같이 설정합니다.
objectName: system_groupBox
title: ROS2 System
geometry:
x: 20
y: 30
width: 360
height: 150


이제 system_groupBox 안에 Label, LineEdit, PushButton을 추가합니다.
첫 번째 Label을 추가합니다.
class: QLabel
objectName: domain_label
text: Domain ID
geometry:
x: 20
y: 35
width: 90
height: 25


첫 번째 LineEdit를 추가합니다.
class: QLineEdit
objectName: domain_lineEdit
text: 30
geometry:
x: 120
y: 35
width: 80
height: 25


두 번째 Label을 추가합니다.
class: QLabel
objectName: namespace_label
text: Namespace
geometry:
x: 20
y: 70
width: 90
height: 25


두 번째 LineEdit를 추가합니다.
class: QLineEdit
objectName: namespace_lineEdit
placeholderText: empty or /tb3
geometry:
x: 120
y: 70
width: 210
height: 25


이제 버튼 3개를 추가합니다.
class: QPushButton
objectName: connect_PB
text: Connect
geometry:
x: 20
y: 110
width: 100
height: 30


class: QPushButton
objectName: disconnect_PB
text: Disconnect
geometry:
x: 130
y: 110
width: 100
height: 30


class: QPushButton
objectName: exit_PB
text: Exit
geometry:
x: 240
y: 110
width: 90
height: 30


저장합니다.
turtlebot3_burger_gui.ui
4. ROS 2 System 버튼을 Python 코드에서 사용하기
이제 방금 만든 버튼과 입력창을 Python에서 사용해보겠습니다.
기존 Python 코드를 다음처럼 수정합니다.
import sys
import os
from pathlib import Path
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
ui_path = Path(__file__).with_name('turtlebot3_burger_gui.ui')
uic.loadUi(str(ui_path), self)
self.connect_signals()
def connect_signals(self):
self.connect_PB.clicked.connect(self.connect_ros)
self.disconnect_PB.clicked.connect(self.disconnect_ros)
self.exit_PB.clicked.connect(self.close)
def connect_ros(self):
domain_id = self.domain_lineEdit.text().strip()
namespace = self.namespace_lineEdit.text().strip()
os.environ['ROS_DOMAIN_ID'] = domain_id if domain_id else '30'
print(f'ROS_DOMAIN_ID = {os.environ["ROS_DOMAIN_ID"]}')
print(f'Namespace = {namespace}')
print('Connect button clicked')
def disconnect_ros(self):
print('Disconnect button clicked')
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

실행합니다.
python3 turtlebot3_burger_gui_node.py

GUI에서 Connect 버튼을 누르면 터미널에 다음과 비슷한 내용이 출력됩니다.
ROS_DOMAIN_ID = 30
Namespace =
Connect button clicked
여기서 핵심은 Qt Designer에서 만든 objectName을 Python 코드에서 그대로 변수처럼 사용할 수 있다는 것입니다.

예를 들어 Qt Designer에서 버튼 이름을 connect_PB로 만들었기 때문에 Python 코드에서 다음처럼 접근할 수 있습니다.
self.connect_PB.clicked.connect(self.connect_ros)
LineEdit도 마찬가지입니다.
domain_id = self.domain_lineEdit.text().strip()
그래서 Qt Designer에서 objectName을 대충 만들면 나중에 코드가 지저분해집니다.
GUI를 만들 때는 반드시 기능이 보이는 이름으로 설정하는 습관을 들이는 것이 좋습니다.
5. Launch Control 영역 만들기
이번에는 GUI에서 bringup, SLAM, Nav2, RViz2를 실행하는 버튼을 추가합니다.
Qt Designer에서 Group Box를 추가합니다.
objectName: launch_groupBox
title: Launch Control
geometry:
x: 400
y: 30
width: 360
height: 150


그 안에 버튼 6개를 추가합니다.
Bringup 버튼입니다.
class: QPushButton
objectName: bringup_PB
text: Run Bringup
geometry:
x: 20
y: 35
width: 150
height: 30


SLAM 버튼입니다.
class: QPushButton
objectName: slam_PB
text: Run SLAM
geometry:
x: 190
y: 35
width: 150
height: 30


Nav2 버튼입니다.
class: QPushButton
objectName: nav2_PB
text: Run Nav2
geometry:
x: 20
y: 75
width: 150
height: 30


RViz2 버튼입니다.
class: QPushButton
objectName: rviz_PB
text: Run RViz2
geometry:
x: 190
y: 75
width: 150
height: 30


지도 저장 버튼입니다.
class: QPushButton
objectName: save_map_PB
text: Save Map
geometry:
x: 20
y: 115
width: 150
height: 30


프로세스 종료 버튼입니다.
class: QPushButton
objectName: kill_proc_PB
text: Stop Launches
geometry:
x: 190
y: 115
width: 150
height: 30


저장합니다.
turtlebot3_burger_gui.ui
6. Launch Control 버튼 사용하기
Python에서 외부 명령을 실행하기 위해 상단에 다음 import를 추가합니다.
import subprocess
import signal
__init__()에 실행 중인 프로세스를 보관할 리스트를 추가합니다.
self.processes = []
connect_signals()에 Launch 버튼 연결을 추가합니다.
self.bringup_PB.clicked.connect(
lambda: self.run_command(
'bringup',
['ros2', 'launch', 'turtlebot3_bringup', 'robot.launch.py']
)
)
self.slam_PB.clicked.connect(
lambda: self.run_command(
'slam',
['ros2', 'launch', 'turtlebot3_cartographer', 'cartographer.launch.py', 'use_sim_time:=false']
)
)
self.nav2_PB.clicked.connect(
lambda: self.run_command(
'nav2',
['ros2', 'launch', 'turtlebot3_navigation2', 'navigation2.launch.py', 'use_sim_time:=false']
)
)
self.rviz_PB.clicked.connect(
lambda: self.run_command(
'rviz2',
['rviz2']
)
)
self.save_map_PB.clicked.connect(
lambda: self.run_command(
'save_map',
['ros2', 'run', 'nav2_map_server', 'map_saver_cli', '-f', 'tb3_map']
)
)
self.kill_proc_PB.clicked.connect(self.stop_processes)

이제 명령 실행 함수를 추가합니다.
def run_command(self, name, cmd):
env = os.environ.copy()
env['TURTLEBOT3_MODEL'] = env.get('TURTLEBOT3_MODEL', 'burger')
try:
proc = subprocess.Popen(
cmd,
env=env,
preexec_fn=os.setsid
)
self.processes.append((name, proc))
print(f'{name} launched: {" ".join(cmd)}')
except FileNotFoundError:
print(f'Command not found: {cmd[0]}')
except Exception as exc:
print(f'Launch failed: {exc}')
run_command() 함수는 외부 명령어를 실행하고, 실행된 프로세스를 관리 리스트에 저장하는 역할을 합니다.
쉽게 말하면 다음과 같은 기능을 합니다.
명령어 실행
→ 프로세스 객체 저장
→ 실행 성공 또는 실패 메시지 출력
ROS, TurtleBot3, Gazebo, RViz 같은 프로그램을 Python GUI나 제어 프로그램에서 실행할 때 사용할 수 있는 구조입니다.
def run_command(self, name, cmd):
이 함수는 두 개의 인자를 받습니다.
name은 실행할 명령에 붙이는 이름입니다. 예를 들어 "gazebo", "rviz", "navigation" 같은 식으로 사용할 수 있습니다.
cmd는 실제 실행할 명령어입니다. 리스트 형태로 전달하는 것이 일반적입니다.
예를 들면 다음과 같습니다.
self.run_command(
"turtlebot3_gazebo",
["ros2", "launch", "turtlebot3_gazebo", "turtlebot3_world.launch.py"]
)
env = os.environ.copy()
이 코드는 현재 Python 프로그램이 실행 중인 환경 변수를 복사합니다.
환경 변수는 운영체제나 프로그램 실행 환경에 필요한 설정값입니다. ROS에서는 ROS_DOMAIN_ID, TURTLEBOT3_MODEL, PATH, LD_LIBRARY_PATH 같은 환경 변수가 중요합니다.
외부 명령을 실행할 때 환경 변수를 제대로 넘겨주지 않으면, 터미널에서는 잘 되던 명령이 Python에서는 실패할 수 있습니다.
그래서 현재 환경을 그대로 복사한 뒤, 필요한 값만 추가하거나 수정합니다.
env['TURTLEBOT3_MODEL'] = env.get('TURTLEBOT3_MODEL', 'burger')
이 코드는 TURTLEBOT3_MODEL 환경 변수를 설정합니다.
TurtleBot3에서는 사용하는 로봇 모델을 환경 변수로 지정합니다.
위 코드는 기존 환경 변수에 TURTLEBOT3_MODEL이 이미 설정되어 있다면 그 값을 그대로 사용합니다. 만약 설정되어 있지 않다면 기본값으로 "burger"를 사용합니다.
proc = subprocess.Popen(
cmd,
env=env,
preexec_fn=os.setsid
)
이 부분이 실제로 외부 명령어를 실행하는 핵심 코드입니다.
subprocess.Popen()은 Python에서 외부 프로그램을 실행할 때 사용하는 함수입니다. subprocess.run()과 달리 명령 실행이 끝날 때까지 기다리지 않고, 프로세스를 백그라운드에서 실행한 뒤 바로 다음 코드로 넘어갑니다.
ROS launch 파일처럼 계속 실행되어야 하는 프로세스를 다룰 때는 Popen()이 적합합니다.
env=env
이 옵션은 앞에서 만든 환경 변수를 외부 프로세스에 전달합니다.
즉, 실행되는 명령어는 현재 Python 프로그램의 환경 변수와 함께 TURTLEBOT3_MODEL 값까지 전달받게 됩니다.
preexec_fn=os.setsid
이 코드는 실행되는 프로세스를 새로운 프로세스 그룹으로 분리합니다.
이렇게 해두면 나중에 해당 프로세스와 그 자식 프로세스들을 한 번에 종료하기 쉬워집니다.
os.setsid를 사용하면 프로세스 그룹 단위로 종료할 수 있기 때문에, launch로 실행된 여러 프로세스를 관리하기에 좋습니다.
self.processes.append((name, proc))
명령 실행에 성공하면 프로세스 정보를 self.processes 리스트에 저장합니다.
저장되는 값은 (name, proc) 형태의 튜플입니다.
print(f'{name} launched: {" ".join(cmd)}')
명령 실행에 성공하면 어떤 명령이 실행되었는지 출력합니다.
예를 들어 name이 "gazebo"이고, cmd가 다음과 같다면
["ros2", "launch", "turtlebot3_gazebo", "turtlebot3_world.launch.py"]
출력 결과는 다음과 같습니다.
gazebo launched: ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
프로세스를 종료하는 함수도 추가합니다.
def stop_processes(self):
for name, proc in self.processes:
if proc.poll() is None:
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
print(f'{name} stopped')
self.processes.clear()

for name, proc in self.processes:
self.processes는 실행된 프로세스들을 저장해 둔 리스트입니다.
보통 이전에 subprocess.Popen()으로 프로세스를 실행할 때 다음과 같이 저장합니다.
self.processes.append((name, proc))
그래서 self.processes의 구조는 다음과 같습니다.
[
("gazebo", proc1),
("rviz", proc2),
("navigation", proc3)
]
여기서 name은 프로세스의 이름이고, proc은 subprocess.Popen()이 반환한 프로세스 객체입니다.
if proc.poll() is None:
proc.poll()은 해당 프로세스가 아직 실행 중인지 확인하는 메서드입니다.
동작 방식은 다음과 같습니다.
proc.poll() is None → 아직 실행 중
proc.poll()이 숫자 반환 → 이미 종료됨
즉, 이 코드는 이미 종료된 프로세스는 건드리지 않고, 아직 살아 있는 프로세스만 종료하겠다는 의미입니다.
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
이 코드가 실제로 프로세스를 종료하는 핵심 부분입니다.
단순히 하나의 프로세스만 종료하는 것이 아니라, 프로세스 그룹 전체에 종료 신호를 보냅니다.
os.getpgid(proc.pid)
이 코드는 특정 프로세스의 프로세스 그룹 ID를 가져옵니다.
proc.pid는 subprocess.Popen()으로 실행한 프로세스의 PID입니다.
즉, 아래 코드는
os.getpgid(proc.pid)
해당 프로세스가 속한 프로세스 그룹의 ID를 가져오는 코드입니다.
그리고 이 값을 os.killpg()에 전달하면 그 그룹에 속한 프로세스 전체에 신호를 보낼 수 있습니다.
signal.SIGTERM
SIGTERM은 프로세스에게 종료를 요청하는 신호입니다.
강제로 즉시 죽이는 SIGKILL과 달리, SIGTERM은 프로그램이 정리 작업을 할 수 있는 기회를 줍니다.
예를 들어 ROS 노드는 종료 신호를 받으면 내부 리소스를 정리하고 정상적으로 종료할 수 있습니다.
일반적으로는 먼저 SIGTERM을 사용하는 것이 좋습니다.
SIGTERM → 정상 종료 요청
SIGKILL → 강제 종료
따라서 이 함수는 무작정 프로세스를 죽이는 방식이 아니라, 비교적 안전하게 종료를 요청하는 방식입니다.
self.processes.clear()
모든 프로세스에 종료 신호를 보낸 뒤에는 self.processes 리스트를 비웁니다.
이 작업을 하지 않으면 이미 종료된 프로세스 정보가 리스트에 계속 남아 있게 됩니다.
그 상
이제 GUI에서 Run Bringup, Run SLAM, Run Nav2, Run RViz2 버튼을 누르면 각각의 명령이 실행됩니다.
다만 실제 로봇에서는 bringup을 GUI에서 실행할지, 별도 터미널에서 실행할지 수업 상황에 맞게 선택하면 됩니다. 특히 TurtleBot3는 Remote PC에서 실행하는 환경이기 때문에 모두 GUI에서 실행하는 것은 무리가 있습니다.
7. Robot Status 영역 만들기
이번에는 로봇 상태를 표시하는 영역을 만듭니다.
이 영역에서는 ROS 연결 상태, LaserScan 최소 거리, 마지막 /cmd_vel 값을 보여줄 것입니다.
Qt Designer에서 Group Box를 하나 추가합니다.
objectName: status_groupBox
title: Robot Status
geometry:
x: 780
y: 30
width: 380
height: 150


그 안에 Label과 LineEdit를 추가합니다.
첫 번째 Label입니다.
class: QLabel
objectName: ros_status_label
text: ROS
geometry:
x: 20
y: 35
width: 120
height: 25


첫 번째 LineEdit입니다.
class: QLineEdit
objectName: ros_status_lineEdit
text: Disconnected
readOnly: true
geometry:
x: 150
y: 35
width: 190
height: 25


두 번째 Label입니다.
class: QLabel
objectName: scan_label
text: Min Scan(m)
geometry:
x: 20
y: 70
width: 120
height: 25


두 번째 LineEdit입니다.
class: QLineEdit
objectName: scan_lineEdit
readOnly: true
geometry:
x: 150
y: 70
width: 190
height: 25


세 번째 Label입니다.
class: QLabel
objectName: cmd_label
text: Last cmd_vel
geometry:
x: 20
y: 105
width: 120
height: 25


세 번째 LineEdit입니다.
class: QLineEdit
objectName: cmd_lineEdit
readOnly: true
geometry:
x: 150
y: 105
width: 190
height: 25


저장합니다.
turtlebot3_burger_gui.ui

8. Robot Status 컴포넌트 사용하기
Python 코드에서 연결 상태를 화면에 표시해보겠습니다.
connect_ros()와 disconnect_ros() 함수를 다음처럼 수정합니다.
def connect_ros(self):
domain_id = self.domain_lineEdit.text().strip()
namespace = self.namespace_lineEdit.text().strip()
os.environ['ROS_DOMAIN_ID'] = domain_id if domain_id else '30'
self.ros_status_lineEdit.setText('Connected')
print(f'ROS_DOMAIN_ID = {os.environ["ROS_DOMAIN_ID"]}')
print(f'Namespace = {namespace}')
print('ROS 2 connected')
def disconnect_ros(self):
self.ros_status_lineEdit.setText('Disconnected')
print('ROS 2 disconnected')

테스트합니다.
python3 turtlebot3_burger_gui_node.py
확인할 내용은 다음입니다.
- 처음 실행하면
ROS상태가Disconnected로 표시됩니다. Connect버튼을 누르면Connected로 바뀝니다.Disconnect버튼을 누르면 다시Disconnected로 바뀝니다.
이 단계에서는 아직 실제 ROS 2 노드를 만들지는 않았습니다.

먼저 UI와 Python 이벤트 연결이 정상적으로 되는지 확인하는 것이 중요합니다.
9. Velocity Control 영역 만들기
이번에는 TurtleBot3 Burger를 수동으로 움직이는 버튼을 만듭니다.
TurtleBot3 Burger는 /cmd_vel 토픽으로 geometry_msgs/msg/Twist 메시지를 받습니다.
전진, 후진, 좌회전, 우회전, 정지 버튼을 만들고, Python 코드에서 각 버튼을 누를 때마다 속도 명령을 보내게 만들 것입니다.
Qt Designer에서 Group Box를 하나 추가합니다.
objectName: teleop_groupBox
title: Velocity Control
geometry:
x: 20
y: 190
width: 360
height: 260


먼저 선속도 입력용 Label을 추가합니다.
class: QLabel
objectName: linear_label
text: Linear m/s
geometry:
x: 20
y: 35
width: 100
height: 25


선속도 입력용 QDoubleSpinBox를 추가합니다.
class: QDoubleSpinBox
objectName: linear_spinBox
decimals: 2
minimum: 0.00
maximum: 0.22
singleStep: 0.01
value: 0.10
geometry:
x: 130
y: 35
width: 90
height: 25
TurtleBot3 Burger의 속도는 너무 크게 주면 위험합니다.
실습에서는 최대 선속도를 0.22 m/s 정도로 제한합니다.


이번에는 각속도 입력용 Label을 추가합니다.
class: QLabel
objectName: angular_label
text: Angular rad/s
geometry:
x: 20
y: 70
width: 100
height: 25


각속도 입력용 QDoubleSpinBox를 추가합니다.
class: QDoubleSpinBox
objectName: angular_spinBox
decimals: 2
minimum: 0.00
maximum: 2.84
singleStep: 0.10
value: 0.50
geometry:
x: 130
y: 70
width: 90
height: 25
이제 버튼 5개를 추가합니다.


전진 버튼입니다.
class: QPushButton
objectName: forward_PB
text: Forward
geometry:
x: 130
y: 115
width: 90
height: 35


좌회전 버튼입니다.
class: QPushButton
objectName: left_PB
text: Left
geometry:
x: 35
y: 160
width: 90
height: 35


정지 버튼입니다.
class: QPushButton
objectName: stop_PB
text: STOP
geometry:
x: 130
y: 160
width: 90
height: 35


우회전 버튼입니다.
class: QPushButton
objectName: right_PB
text: Right
geometry:
x: 230
y: 160
width: 90
height: 35


후진 버튼입니다.
class: QPushButton
objectName: backward_PB
text: Backward
geometry:
x: 130
y: 205
width: 90
height: 35


저장합니다.
turtlebot3_burger_gui.ui

10. Velocity Control 버튼 사용하기
먼저 ROS 2를 붙이지 않고 버튼 동작만 확인해보겠습니다.
connect_signals() 함수에 버튼 연결을 추가합니다.
def connect_signals(self):
self.connect_PB.clicked.connect(self.connect_ros)
self.disconnect_PB.clicked.connect(self.disconnect_ros)
self.exit_PB.clicked.connect(self.close)
self.forward_PB.clicked.connect(lambda: self.send_velocity(self.linear_spinBox.value(), 0.0))
self.backward_PB.clicked.connect(lambda: self.send_velocity(-self.linear_spinBox.value(), 0.0))
self.left_PB.clicked.connect(lambda: self.send_velocity(0.0, self.angular_spinBox.value()))
self.right_PB.clicked.connect(lambda: self.send_velocity(0.0, -self.angular_spinBox.value()))
self.stop_PB.clicked.connect(lambda: self.send_velocity(0.0, 0.0))

그리고 send_velocity() 함수를 추가합니다.
def send_velocity(self, linear, angular):
self.cmd_lineEdit.setText(f'lin={linear:.2f}, ang={angular:.2f}')
print(f'cmd_vel: linear={linear:.2f}, angular={angular:.2f}')

실행합니다.
python3 turtlebot3_burger_gui_node.py
버튼을 누르면 Last cmd_vel 칸에 값이 표시됩니다.
예를 들어 Forward를 누르면 다음처럼 표시됩니다.
lin=0.10, ang=0.00

Left를 누르면 다음처럼 표시됩니다.
lin=0.00, ang=0.50
