🤝
이 가이드는 인류와 AI가 함께 만드는 지식입니다.
이 콘텐츠는 Human + AI Partnership 철학 아래 모든 사람이 로봇·AI를 배울 수 있도록 무료로 제공됩니다. 당신의 질문과 기여가 다음 학생의 미래를 바꿉니다.
ROS 2 수중로봇(ROV/AUV) 가이드 2026
ROS 2로 ROV(원격조종)·AUV(자율) 수중 로봇 개발. 수중 통신, 센서 융합, 자율 내비게이션, 해양 탐사 시스템 구축.
1. 수중 로봇 아키텍처
수중 로봇 시스템 설계:
- ROV (원격조종): 케이블 연결, 실시간 제어, 고해상도 센서
- AUV (자율주행): 배터리 독립, 사전 프로그램 경로, 자율 네비게이션
- 하이브리드: 케이블+배터리, 강화 학습 활용
- 군집 운영: 다중 AUV 협력, 분산 제어
2. 수중 통신 (모뎀 제어)
수중 음파 모뎀 통신:
// 수중 음파 모뎀 ROS 2 인터페이스
class UnderwaterModemDriver : public rclcpp::Node {
public:
UnderwaterModemDriver() : Node("modem_driver") {
// 모뎀 시리얼 연결
modem_sub_ = create_subscription<std_msgs::msg::String>(
"modem_rx", 10,
[this](const std_msgs::msg::String::SharedPtr msg) {
parse_acoustic_message(*msg);
});
modem_pub_ = create_publisher<std_msgs::msg::String>(
"modem_tx", 10);
}
private:
void parse_acoustic_message(const std_msgs::msg::String& msg) {
// 수중 통신 지연: 1500m/s (음속)
// 패킷: [DEST_ID] [TIMESTAMP] [PAYLOAD] [CHECKSUM]
double sound_speed = 1500.0; // m/s 해수
double range = 5000.0; // 5km 통신 범위
double latency = range / sound_speed; // ~3.3초
RCLCPP_INFO(get_logger(), "Acoustic RX from vehicle: %s (latency: %.1fs)",
msg.data.c_str(), latency);
}
void send_acoustic_command(const std::string& cmd) {
// 모뎀으로 음파 전송
std_msgs::msg::String msg;
msg.data = cmd;
modem_pub_->publish(msg);
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr modem_sub_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr modem_pub_;
};3. 수중 센서 융합 (USBL/DVL)
위치 결정 센서:
class UnderwaterNavigationFusion : public rclcpp::Node {
private:
// USBL: Ultra Short Baseline 음파 위치결정
// DVL: Doppler Velocity Log 속도 측정
Eigen::VectorXd state_; // [x, y, z, vx, vy, vz, heading]
Eigen::MatrixXd covariance_;
public:
void update_with_usbl(const geometry_msgs::msg::PointStamped& position) {
// USBL 위치 업데이트 (정확도 ±수미터)
Eigen::Vector3d measurement(
position.point.x,
position.point.y,
position.point.z);
double usbl_noise = 2.0; // 2m 표준편차
update_kalman(measurement, usbl_noise);
}
void update_with_dvl(const geometry_msgs::msg::TwistStamped& velocity) {
// DVL 속도 업데이트 (정확도 0.2%)
Eigen::Vector3d velocity_meas(
velocity.twist.linear.x,
velocity.twist.linear.y,
velocity.twist.linear.z);
update_velocity(velocity_meas);
}
void update_with_imu_compass(
const sensor_msgs::msg::Imu& imu,
const sensor_msgs::msg::MagneticField& compass) {
// IMU + 나침반으로 방향 보정
double heading = compute_heading(compass);
state_(6) = heading; // 헤딩 업데이트
}
// 확장 칼만 필터
void update_kalman(const Eigen::Vector3d& meas, double noise) {
// USBL 센서 모델
// H = [1 0 0 0 0 0 0; 0 1 0 0 0 0 0; 0 0 1 0 0 0 0]
// 측정 = position (z 무시가능)
}
};4. 자율 내비게이션 (SLAM 수중)
수중 SLAM 알고리즘:
# 수중 SLAM 패키지 설치 및 실행
ros2 install ros-humble-fssf-slam # Forward-Scanning Sonar SLAM
ros2 install ros-humble-slam-toolbox
# SLAM 설정 파일 (underwater_slam.yaml)
slam_toolbox:
plugins:
slam_toolbox_mappingsf:
plugin: slam_toolbox/SerialAsyncSlamToolbox
# 수중 특화 파라미터:
correlation_search_space_dimension: 0.5 # 50cm 해상도
correlation_search_space_resolution: 0.05 # 5cm 격자
loop_search_space_dimension: 20.0 # 20m 루프 클로저 감지
# 음향 이미징 소나 SLAM 실행
ros2 launch slam_toolbox online_async_launch.py slam_params_file:=underwater_slam.yaml5. 원격 조종 (ROV 제어)
케이블 ROV 실시간 제어:
class RemoteOperatedVehicle : public rclcpp::Node {
public:
RemoteOperatedVehicle() : Node("rov_controller") {
// 조이스틱 입력
joy_sub_ = create_subscription<sensor_msgs::msg::Joy>(
"joy", 10,
[this](const sensor_msgs::msg::Joy::SharedPtr msg) {
handle_joystick_input(*msg);
});
// 6DOF 추력기 명령어
thruster_pub_ = create_publisher<std_msgs::msg::Float64MultiArray>(
"rov_thrusters", 10);
// 카메라/조명 제어
light_pub_ = create_publisher<std_msgs::msg::Float32>(
"rov_light_intensity", 10);
}
private:
void handle_joystick_input(const sensor_msgs::msg::Joy& joy) {
// 조이스틱 맵핑:
// axes[0] = 전진/후진
// axes[1] = 좌/우 (yaw)
// axes[2] = 상승/하강
// buttons[0] = 그리퍼 열기
// buttons[1] = 그리퍼 닫기
std_msgs::msg::Float64MultiArray thruster_cmd;
thruster_cmd.data.resize(8); // 8개 추력기
// 수압 보정: 깊이에 따라 중성부력 조정
double depth = current_depth_; // 미터
double pressure_compensation = depth * 1025 * 9.81 / 1000; // kg·m/s²
// 추력기 분배 알고리즘 (8-DOF vector allocation)
allocate_thrusts(joy, pressure_compensation, thruster_cmd.data);
thruster_pub_->publish(thruster_cmd);
}
rclcpp::Subscription<sensor_msgs::msg::Joy>::SharedPtr joy_sub_;
rclcpp::Publisher<std_msgs::msg::Float64MultiArray>::SharedPtr thruster_pub_;
rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr light_pub_;
double current_depth_ = 0.0;
};6. AUV 자율 경로 계획
사전 프로그램 탐사 경로:
class AUVMissionPlanner : public rclcpp::Node {
public:
struct MissionWaypoint {
double latitude, longitude;
double depth;
double heading;
int action; // 0=항해, 1=샘플링, 2=촬영
};
void execute_mission(const std::vector<MissionWaypoint>& waypoints) {
for (const auto& wp : waypoints) {
// 위치 도착
navigate_to_waypoint(wp);
// 임무 수행
if (wp.action == 1) {
collect_sample(); // 샘플 수집
} else if (wp.action == 2) {
capture_image(); // 사진 촬영
}
// 배터리 상태 확인
if (get_battery_percent() < 20.0) {
abort_mission_return_to_surface();
}
}
}
private:
void navigate_to_waypoint(const MissionWaypoint& target) {
// 1. GPS → UTM 변환 (선상)
// 2. GPS-거부 해역: DVL + 나침반 무향법
// 3. 도착 기준: 수평거리 ±2m, 깊이 ±0.5m
}
void abort_mission_return_to_surface() {
// 비상 상승 (긍정 부력으로 해수면 복귀)
RCLCPP_WARN(get_logger(), "Battery critical - returning to surface");
set_positive_buoyancy();
}
};7. 수중 장애물 회피 (Sonar)
소나 기반 장애물 감지:
class SonarObstacleAvoidance : public rclcpp::Node {
public:
SonarObstacleAvoidance() : Node("sonar_avoidance") {
sonar_sub_ = create_subscription<sensor_msgs::msg::LaserScan>(
"sonar_scan", 10,
[this](const sensor_msgs::msg::LaserScan::SharedPtr msg) {
detect_obstacles(*msg);
});
trajectory_pub_ = create_publisher<nav_msgs::msg::Path>(
"obstacle_free_path", 10);
}
private:
void detect_obstacles(const sensor_msgs::msg::LaserScan& scan) {
// 소나 스캔 분석
// 범위: 0.5-100m, 해상도: 1-2도
double danger_distance = 5.0; // 5m 이상 접근 금지
std::vector<double> obstacle_angles;
for (size_t i = 0; i < scan.ranges.size(); ++i) {
if (scan.ranges[i] < danger_distance && scan.ranges[i] > scan.range_min) {
double angle = scan.angle_min + i * scan.angle_increment;
obstacle_angles.push_back(angle);
}
}
// 회피 경로 계산: VFM (Vector Field Method)
nav_msgs::msg::Path safe_path = compute_vector_field(obstacle_angles);
trajectory_pub_->publish(safe_path);
}
nav_msgs::msg::Path compute_vector_field(
const std::vector<double>& obstacle_angles) {
// 인력장: 목표 방향
// 척력장: 장애물 반대 방향
// 합성장: 안전 경로
nav_msgs::msg::Path path;
return path;
}
rclcpp::Subscription<sensor_msgs::msg::LaserScan>::SharedPtr sonar_sub_;
rclcpp::Publisher<nav_msgs::msg::Path>::SharedPtr trajectory_pub_;
};8. 해양 환경 시뮬레이션
Gazebo 수중 물리 엔진:
# UUV Simulator 플러그인 설치 (Gazebo 수중 전문)
ros2 install ros-humble-uuv-simulator
ros2 install ros-humble-freefloating-gazebo
# 수중 환경 설정 (underwater_world.world)
<sdf version="1.9">
<world name="underwater_world">
<!-- 유체 역학 -->
<plugin name="ocean_current" filename="libOceanCurrentPlugin.so">
<current_velocity>0.2 0.0 0.0</current_velocity> <!-- 0.2 m/s 동쪽 흐름 -->
</plugin>
<!-- 조명 (수심 감소)-->
<light name="sun" type="directional">
<intensity>0.5</intensity> <!-- 수중 어두움 -->
</light>
<!-- 해저 지형 -->
<model name="seafloor">
<static>true</static>
<mesh>seafloor.dae</mesh> <!-- 3D 해저 지형
</model>
</world>
</sdf>
# 시뮬레이션 실행
ros2 launch uuv_simulator one_auv_two_thrusters.launch.py9. 실제 배포 체크리스트
- ✅ 모뎀 통신 테스트 (5km 범위, 3초 지연)
- ✅ 센서 캘리브레이션 (USBL, DVL, 나침반)
- ✅ 압력 센서 영점 조정
- ✅ 배터리 용량/소비율 측정
- ✅ 해양 환경 시험 (담수/해수, 수온)
- ✅ 안전 프로토콜 (케이블 강도, 수심 제한)
- ✅ 규제 승인 (IMO, 각국 해양청)
10. 국제 표준 & 규제
수중 로봇 준수 사항:
- IMO SOLAS (국제 해상 안전 규약)
- IEC 61162 (해상 데이터 네트워크)
- DNV GL 인증 (해양 장비 검사)
- 국가별 해양청 인허가 (EEZ, 어업권)
핵심 정리
ROS 2 기반 수중 로봇 시스템은 음파 통신, 센서 융합, 자율 내비게이션을 통해 심해 탐사·해양 연구·해양자원 개발을 실현합니다. ROV 원격 제어와 AUV 자율 운영의 조화가 해양 로보틱스의 미래입니다.