- 기간: 2024.03 – 2025.12 (22개월)
- 플랫폼: Twinny Nargo60 · Velodyne VLP-16 · Jetson AGX Orin
- 환경: Ubuntu 20.04 · ROS Noetic · C++
- 주요 기술: TEB Local Planner
00. Summary
이 프로젝트는 시각장애인이 로봇 핸들을 잡고 전시관을 독립 이동하면서, 태블릿 · 음성 · 햅틱 피드백을 통해 전시 안내를 받는 실증 과제이다.

전시관 경유지 정보를 기반으로, 로봇이 전시관 내부를 안전하게 이동할 수 있도록 ROS 기반 Waypoint 주행 구조와 TEB Local Planner 통합을 수행했다.
01. 전체 과제 구조
이 과제는 하나의 로봇 안내 서비스를 위해 3개의 팀이 결합된 형태로 진행되었다.
| 구분 | 역할 |
|---|---|
| 안내 콘텐츠 / 태블릿 파트 | 사용자에게 전시 정보를 제공하고 목적지 또는 안내 상태를 전달 |
| 햅틱 피드백 파트 | 버튼 입력 및 사용자 피드백 제공 |
| 로봇 주행 파트 | 경유지 기반 이동, local planning, 시각장애인 맞춤 주행 특성 적용 |
- 내가 속한 팀은 로봇 주행 파트이다.
- 태블릿 또는 햅틱 시스템에서 전달되는 경유지·트리거 정보를 받아 로봇의 목표 지점을 갱신하고, TEB Local Planner를 통해 속도 명령을 생성하는 구조를 구성했다.
02. My Contribution
이 프로젝트에서 내가 직접 담당한 내용은 다음과 같다.
- 경유지 이동 로직 구현 (06. 경유지 이동 로직 구현)
- 시각장애인 안내 주행을 위한 TEB 파라미터 튜닝 (04. Planner Selection & Tuning)
- 로봇 플랫폼의 odometry topic과 TEB 내부 odometry 불일치 문제 해결 (05. 문제 해결)
- TEB planner 객체 재초기화로 인한 파라미터 초기화 문제 해결 (05. 문제 해결)
- 멀티 PC 환경의 TF timestamp drift 문제를 NTP 기반으로 동기화 (05. 문제 해결)
03. System Architecture
03-1. Hardware / Network 구성
실증 시스템은 로봇 PC, 태블릿 PC, 햅틱장갑 PC가 연결된 멀티 PC 구조였다.
Tablet PC
└─ 전시 안내 상태 / 경유지 정보 전달
Haptic Glove PC
└─ 버튼 입력 / 사용자 피드백 신호 전달
Robot PC
└─ ROS Navigation / TEB Local Planner / velocity command 생성
전체 흐름은 다음과 같다.
Tablet / Haptic
↓ waypoint, button trigger
Waypoint Manager
↓ goal update
TEB Local Planner
↓ velocity command
Robot Base04. 플래너 선택 & 튜닝
04-1. 왜 TEB Local Planner인가
- 시각장애인 안내 로봇은 일반적인 모바일 로봇과 조건이 다르다.
- 사용자가 로봇 뒤에서 핸들을 잡고 따라간다는 점 때문에, planner 선택 기준이 단순한 경로 최적화가 아니라 사용자 안전성 중심으로 바뀐다.
| 항목 | DWA | TEB | 판단 |
|---|---|---|---|
| 도착 시 회전 | 제자리 회전이 발생하기 쉬움 | 파라미터로 회전 억제 가능 | 로봇이 제자리 회전시 사용자에게 불편 및 위험 |
| 후진 | 조건에 따라 발생 가능 | max_vel_x_backwards 등의 파라미터로 강하게 제한 가능 | 뒤로 걷게 될 경우 불편 및 위험 |
| 각속도 제한 | 조정 가능 | 조정 가능 | 급회전 억제가 필요 |
| 파라미터 자유도 | 상대적으로 낮음 | 높음 | 실환경 반복 튜닝에 유리 |
따라서 이 프로젝트에서는 TEB Local Planner를 사용했고, 시각장애인 안내 주행에 맞게 후진, 회전, 속도 관련 파라미터를 조정했다.
04-2. 주요 파라미터 튜닝
- TEB Local Planner의 weight 및 속도 파라미터를 분석하고, TurtleBot 시뮬레이션과 실로봇 테스트를 통해 회전·후진·속도 특성이 안내 주행에 적합하도록 조정했다.
- 아래 표는 전방 주행성 및 회전 주행 관련 웨이트를 조정한 대표 파라미터이다.
| 파라미터 | 조정 방향 | 목적 |
|---|---|---|
max_vel_x_backwards | 매우 낮게 제한 | 안내 중 후진을 사실상 억제 |
max_vel_theta | 낮게 제한 | 급회전으로 인한 사용자 불안정 방지 |
weight_kinematics_forward_drive | 전방 주행 성향 증가 | 전진 주행 성향을 높여 제자리 회전을 방지 |
특히 weight_kinematics_forward_drive는 TEB cost function에서 후진 방향 운동학에 penalty를 부여하는 항목이다.
이 값을 크게 설정하면 전진 방향 경로를 강하게 선호하게 되며, 사용자가 로봇 핸들을 잡고 따라가는 안내 상황에서 예측 가능한 주행을 만들 수 있었다.
터틀봇 시뮬레이션 파라미터 튜닝
후진 정차 모션 (파라미터 튜닝 전)
선회 주행 모션 (파라미터 튜닝 후)
실제 로봇 파라미터 적용
05. 경유지 이동 로직 구현
전시관 안내 시나리오는 여러 전시 지점을 순서대로 방문하는 방식으로 구성되었다.
이를 위해 Waypoint 기반 이동 로직을 구현했다.
05-1. 전체 흐름
initializeWaypoints()
전시관 경유지 좌표 정의
↓
publishGoal()
현재 waypoint를 navigation goal로 발행
↓
TEB Local Planner
경로 및 속도 명령 계산
↓
checkGoalReached()
위치 오차 + 방향 오차 기반 도착 판정
↓
도착 시 안내 대기
↓
next waypoint로 전환05-2. 초기 도착 판단 로직
도착 판단은 위치 오차와 방향 오차를 동시에 고려했다.
void checkGoalReached() {
double dx = goal_pose.position.x - current_pose.position.x;
double dy = goal_pose.position.y - current_pose.position.y;
double position_error = std::sqrt(dx * dx + dy * dy);
double yaw_error = normalizeAngle(
goal_yaw - current_yaw
);
if (position_error < position_tolerance &&
std::fabs(yaw_error) < yaw_tolerance) {
waitForGuidance();
moveToNextWaypoint();
}
}하지만 실제 실증에서는 위와 같은 코드로 주행을 할 때 로봇이 멈추지 않았는데 도착했다 판단하여 음성 안내가 시작되는 문제가 있었다.
- 초기에 제작한 map이 완벽하게 매칭 되지 않아 Localization 문제로 오실레이션이 발생.
- 따라서 TEB 내부 함수 중
isGoalReached()를 사용하여 TEB가 완전히 멈춤을 판단할 때 도착했다고 판단.
05-3. 태블릿 · 햅틱장갑 연동
태블릿과 햅틱장갑은 주행 시스템에 다음과 같은 신호를 전달했다.
| 입력 | 주행 시스템에서의 역할 |
|---|---|
| 태블릿 경유지 메시지 | 이동할 전시 지점 또는 안내 상태 갱신 |
| 햅틱 버튼 입력 | 다음 경유지 이동 트리거 |
| 안내 상태 메시지 | 로봇 도착 여부와 안내 진행 상태 공유 |
06. 문제 해결
오픈소스 TEB Local Planner를 상용 로봇 플랫폼에 올렸을 때, 단순 파라미터 튜닝만으로는 해결되지 않는 통합 문제가 발생했다.
이 섹션은 실제로 발생한 문제와 디버깅 과정을 정리한 것이다.
06-1. 파라미터가 계속 초기화되는 문제
문제
설정한 TEB 파라미터가 주행 중 계속 기본값으로 돌아가는 현상이 발생했다.
원인
처음에 작성한 node 코드에서 TEB planner 객체가 함수 내부의 로컬 변수로 생성되어 있었다.
메인 루프에서 해당 함수가 반복 호출되면서 planner 객체가 매번 새로 생성되고, initialize()가 반복 실행되었다.
// 문제 구조: 함수가 호출될 때마다 planner 객체가 새로 생성됨
void runTebPlanner() {
teb_local_planner::TebLocalPlannerROS teb_planner;
teb_planner.initialize("planner_name", &tf_buffer, &costmap);
while (ros::ok()) {
teb_planner.computeVelocityCommands(cmd_vel);
}
}수정
TEB planner 객체를 클래스 멤버 변수로 이동시키고, initialize()를 생성자 또는 초기화 단계에서 한 번만 실행하도록 구조를 변경했다.
class NavigationModule {
private:
teb_local_planner::TebLocalPlannerROS teb_planner_;
public:
NavigationModule() {
teb_planner_.initialize("planner_name", &tf_buffer_, &costmap_);
}
void run() {
teb_planner_.computeVelocityCommands(cmd_vel_);
}
};결과
planner 객체가 유지되면서 파라미터가 정상적으로 적용되었고, 주행 중 파라미터가 초기화되는 문제가 사라졌다.
06-2. 로봇 속도가 비정상적으로 느린 문제
문제
파라미터 초기화 문제를 해결한 뒤에도 로봇이 약 0.1 m/s 수준으로만 이동하는 현상이 남아 있었다.
원인 추적
처음에는 속도 제한 파라미터 문제로 예상했지만, 관련 파라미터를 조정해도 현상이 동일했다.
그래서 computeVelocityCommands() 내부에 로그를 추가하여 TEB가 인식하는 현재 속도를 확인했다.
ROS_INFO("current vel x: %.3f", robot_vel.linear.x);
ROS_INFO("current vel theta: %.3f", robot_vel.angular.z);
// 출력 예시
// current vel x: 0.000로그 확인 결과, 실제 로봇은 움직이고 있었지만 TEB 내부에서는 현재 속도를 0으로 인식하고 있었다.
TEB 내부 odometry 참조 구조를 따라가 보니, 기본 설정은 /odom 계열 topic을 기준으로 현재 속도를 가져오고 있었다.
하지만 상용 로봇 플랫폼은 자체 odometry topic을 사용하고 있었기 때문에, TEB가 현재 속도를 정상적으로 읽지 못했다.
TEB가 참조하는 odometry topic
→ 기본 odometry topic
실제 로봇 플랫폼이 발행하는 twinny odometry topic
→ 플랫폼 전용 twinny odometry topic그 결과 TEB는 현재 속도를 항상 0으로 인식했고, 내부 가속도 제한 계산이 0 기준으로 적용되어 속도 증가가 매우 느려졌다.
현재 속도 = 0으로 인식
→ 가속도 제한 계산이 0 기준으로 적용
→ 매 루프마다 증가 가능한 속도량이 제한됨
→ 목표 속도에 도달하지 못함수정

TEB가 참조하는 odometry topic을 실제 로봇 플랫폼의 odometry topic에 맞게 수정했다.
// 수정 전: 기본 odometry topic 사용
odom_helper.setOdomTopic(default_odom_topic);
// 수정 후: 로봇 플랫폼 전용 odometry topic 사용
odom_helper.setOdomTopic(robot_platform_odom_topic);결과
TEB가 현재 로봇 속도를 정상적으로 인식했고, velocity command가 정상 범위로 출력되는 것을 확인했다.
06-3. Multi-PC Time Sync
문제
Twinny 로봇 내부 PC와 TEB Local Planner를 구동하는 외부 PC가 서로 다른 시스템 시각을 사용하면서 TF timestamp drift가 발생했다. 이로 인해 odometry, robot pose, TF frame의 timestamp 기준이 맞지 않았고, 일부 구간에서 transform lookup 실패 또는 TF drop 문제가 발생했다.
진단
다음 명령어를 사용해 frame delay와 timestamp를 확인했다.
rosrun tf tf_monitor
rostopic echo /tf해결
로봇 PC를 기준으로 NTP 서버를 설정하고, navigation PC의 시스템 시각을 동기화했다.
Twinny Robot PC
└─ NTP 기준 서버
Navigation PC
└─ Robot PC 기준으로 시간 동기화결과
NTP 적용 후 두 PC 간 TF timestamp drift가 감소했고, 주행 중 transform lookup 실패 빈도가 줄어들었다.
이를 통해 navigation PC에서 로봇 pose와 odometry 정보를 더 안정적으로 참조할 수 있었고, 실제 로봇 주행 테스트의 안정성이 개선되었다.
07. 결과
07-1. 프로젝트 차원 결과
< 실제 주행 경로 및 실증 환경 >
| 항목 | 결과 |
|---|---|
| 초기 실증 | 광주 세광학교 |
| 본 실증 | 광주과학관 |
| 참여자 | 시각장애인 참여자 20명 |
| 운영 결과 | 전 구간 완주, 충돌 0건 |
이 결과는 전체 팀이 함께 구성한 안내 서비스의 실증 결과이다.
태블릿 안내, 햅틱 피드백, 로봇 주행 시스템이 결합되어 실제 사용자를 대상으로 전시 안내 흐름을 검증했다.
07-2. 나의 역할 결과
내가 담당한 로봇 주행 파트에서는 다음 결과를 얻었다.
- TEB Local Planner를 실제 상용 로봇 플랫폼에 통합
- Waypoint 기반 전시 안내 주행 시나리오 구현
- odometry topic mismatch로 인한 저속 주행 문제 해결
- TEB planner 객체 재초기화로 인한 파라미터 초기화 문제 해결
- 시각장애인 안내 상황에 맞게 후진, 회전, 속도 조건을 제한
- NTP 기반 시간 동기화를 통해 멀티 PC 환경의 TF timestamp drift 문제 완화
08. 회고
이 프로젝트를 통해 단순히 planner를 실행하는 것과, 실제 상용 로봇 플랫폼에서 안정적인 안내 서비스를 수행하는 것은 다르다는 점을 경험했다.
특히 다음 세 가지를 크게 배웠다.
-
오픈소스 planner 통합에서는 topic, frame, odometry 구조 확인이 핵심이다.
같은 ROS 기반 시스템이라도 플랫폼별 topic 이름과 odometry 구조가 다르면 planner가 정상 동작하지 않을 수 있다. -
로봇 주행 성향.
시각장애인 안내 로봇에서는 빠른 이동보다 예측 가능한 전진 주행, 낮은 회전 속도, 후진 억제가 더 중요했다. -
멀티 PC 로봇 시스템에서는 시간 동기화가 주행 안정성에 직접 영향을 준다.
TF timestamp drift는 단순 경고가 아니라 실제 transform lookup 실패와 주행 불안정으로 이어질 수 있었다.
9. Research 2로 이어진 이유
실증을 마친 뒤 한 가지 중요한 문제가 남았다.
로봇이 안전하게 이동하더라도, 뒤에서 핸들을 잡은 사용자의 실제 보행 경로는 로봇 경로와 달랐다.
로봇 경로만 최적화하면 로봇 자체는 안정적으로 움직일 수 있지만, 사용자의 몸은 로봇의 회전과 경로 곡률에 의해 다른 궤적을 따라가게 된다.
즉, 이 프로젝트를 통해 다음 문제의식이 생겼다.
로봇의 경로뿐 아니라, 사용자의 실제 보행 경로까지 함께 고려해야 하지 않을까?
이 관찰이 이후 학위연구인
시각장애인을 위한 핸들 제어형 이동 안내 로봇의 안전 경로 생성 및 추종 연구로 이어졌다.
