콘텐츠로 이동

로봇 키트

로보틱스 툴킷: drive, sense, look, listen, speak, emote 도구와 독립형 안전 모니터.

로봇 키트(crates/robot-kit)는 Revka 에이전트를 물리적 로봇의 두뇌로 변환합니다. 이 크레이트는 독립형 Rust 크레이트로, drive, sense, look, listen, speak, emote의 여섯 가지 에이전트 도구와 AI가 요청하는 모든 움직임을 재정의할 수 있는 독립형 SafetyMonitor를 제공합니다. Raspberry Pi 배포 환경에서 오프라인 추론(비전용 Ollama, 청취용 Whisper.cpp, 음성용 Piper)을 사용하도록 설계되었으나, 모든 도구에 mock 모드가 있어 하드웨어 없이도 개발 및 테스트할 수 있습니다.

자연어 에이전트 호출로 제어하는 구현체 로봇(로버, 장난감, 순찰 봇 등)을 만들려면 이 페이지를 참고하세요. 유선 마이크로컨트롤러 GPIO(Pico, Arduino, Nucleo) 및 Aardvark 어댑터에 대해서는 GPIO 도구Aardvark I2C/SPI/GPIO를 참조하세요. Pi에서 Revka 자체를 실행하는 방법은 Raspberry Pi (셀프 호스팅)를 참조하세요.

로봇 키트는 에이전트 루프와 하드웨어 사이에 위치합니다. 에이전트가 도구를 호출하면 모든 드라이브 명령은 독립적인 태스크로 실행되는 SafetyMonitor를 통해 전달되며, SafetyMonitor가 로봇의 이동 여부를 최종적으로 결정합니다.

Revka AI Brain ──tool calls──▶ Robot Kit tools
drive · look · listen · speak · sense · emote
SafetyMonitor (independent task)
pre-move check · speed limiting · bump · watchdog · E-stop
Hardware: motors · camera · mic · speaker · LIDAR · LEDs

크레이트의 핵심 원칙: AI는 이동을 요청할 수 있지만, SafetyMonitor가 이를 허용합니다. 모델이 환각을 일으키더라도 안전이 항상 우선입니다.

이 키트는 독립적으로 사용할 수 있도록 경량 Tool 트레이트를 자체 정의하지만, 도구는 Revka의 에이전트 루프와도 호환됩니다. 이 크레이트는 워크스페이스 멤버이며 코어 런타임에 자동으로 등록되지 않습니다 — Rust에서 직접 연결해야 합니다(에이전트에 연결하기 참조).

크레이트를 워크스페이스 패키지로 빌드합니다:

Terminal window
cargo build -p revka-robot-kit --release
피처기본값활성화 내용
safetyonSafetyMonitor 백그라운드 태스크 및 SafeDrive 래퍼. 강력히 권장하며 활성화 상태를 유지하세요.
gpiooffrppal을 통한 직접 GPIO 제어 (Raspberry Pi / Linux 전용).
ros2offROS2 통합 빌드 플래그.
lidaroffLIDAR 지원 빌드 플래그.
visionoff카메라 + 비전 모델 빌드 플래그.

모든 하드웨어 및 제한 설정은 robot.toml에 있습니다. 크레이트에서 템플릿을 복사한 후 로봇에 맞게 수정하세요:

Terminal window
mkdir -p ~/.revka
cp crates/robot-kit/robot.toml ~/.revka/

최소한의 mock 모드 설정은 다음과 같습니다:

[drive]
backend = "mock" # "ros2" | "serial" | "gpio" | "mock"
ros2_topic = "/cmd_vel"
serial_port = "/dev/ttyACM0"
max_speed = 0.5 # m/s
max_rotation = 1.0 # rad/s
[camera]
device = "/dev/video0" # or "picam" for the Pi Camera Module
width = 640
height = 480
vision_model = "moondream" # "llava" | "moondream" | "none"
ollama_url = "http://localhost:11434"
[audio]
mic_device = "default"
speaker_device = "default"
whisper_model = "base" # "tiny" | "base" | "small"
whisper_path = "/usr/local/bin/whisper-cpp"
piper_path = "/usr/local/bin/piper"
piper_voice = "en_US-lessac-medium"
[sensors]
lidar_port = "/dev/ttyUSB0"
lidar_type = "mock" # "rplidar" | "ydlidar" | "ros2" | "mock"
motion_pins = [17, 27] # BCM, PIR sensors
ultrasonic_pins = [23, 24] # BCM (trigger, echo); omit to disable
[safety]
min_obstacle_distance = 0.3 # meters — robot will not move closer than this
slow_zone_multiplier = 3.0 # start slowing at 0.3 × 3.0 = 0.9 m
approach_speed_limit = 0.3 # fraction of max speed near obstacles
max_drive_duration = 30 # seconds — watchdog auto-stop window
sensor_timeout_secs = 5 # block movement if sensors go stale this long
blind_mode_speed_limit = 0.2 # speed cap when sensors are mock/unavailable
estop_pin = 4 # BCM — physical emergency-stop button
bump_sensor_pins = [5, 6] # BCM — chassis microswitches
bump_reverse_distance = 0.15 # meters to back up after a bump
predict_collisions = true # trajectory prediction (needs LIDAR)
confirm_movement = false # require verbal confirmation before each move

drive는 전방향 이동을 제어합니다. 자연어 동작을 네 가지 모터 백엔드 중 하나에 매핑하고, 요청한 거리와 설정된 속도 제한을 기반으로 이동 시간을 계산합니다.

drive(action="forward", distance=1.0)
drive(action="rotate_left", distance=90)
drive(action="left", distance=0.5, speed=0.3)
drive(action="stop")
필드타입기본값의미
actionstring— (필수)forward, backward, left, right (측면 이동), rotate_left, rotate_right, stop, 또는 custom.
distancenumber0.5 m / 90°직선 이동 시 미터 단위, 회전 시 도(°) 단위.
speednumber0.5속도 배율 0.01.0, drive.max_speed에 의해 스케일됨.
linear_x / linear_y / angular_znumber0.0action="custom" 시 원시 속도값 (-1.0에서 1.0).

stop은 항상 즉시 실행되며 차단되지 않습니다. 드라이브 명령은 초당 하나로 속도가 제한되고, 모든 이동 시간은 safety.max_drive_duration으로 제한되어 단일 명령이 무한 실행되지 않습니다.

드라이브 백엔드 (drive.backend):

백엔드동작
ros2ros2 topic pub을 통해 설정된 ros2_topic(기본값 /cmd_vel)으로 geometry_msgs/msg/Twist를 발행합니다. 프로덕션에서는 rclrs(Rust ROS2 바인딩)로 교체하세요.
serialdrive.serial_port에 연결된 Arduino/모터 컨트롤러로 M <lx> <ly> <az> <ms> 프레임을 전송합니다.
gpiorppal을 통한 직접 PWM 제어 (gpio 피처 필요).
mock명령을 로그로 기록하고 성공을 반환합니다. 기본값 — 개발 시 사용하세요.

sense는 LIDAR, PIR 모션 센서, 초음파 거리 측정기로부터 로봇의 환경을 읽습니다.

sense(action="scan", direction="forward")
sense(action="clear_ahead")
sense(action="all")
필드타입의미
actionstring (필수)scan (LIDAR), motion (PIR), distance (초음파), clear_ahead (전방 경로 확인), 또는 all (통합 보고서).
directionstringscan 시: forward (기본값), left, right, back, 또는 all.

LIDAR 백엔드는 sensors.lidar_type으로 설정합니다(rplidar, ydlidar, ros2, 또는 mock). 실제 하드웨어를 사용할 수 없는 경우 시뮬레이션 룸 스캔으로 폴백하므로, sense는 mock 모드에서도 항상 유효한 결과를 반환합니다.

look은 카메라 프레임을 캡처(ffmpeg, 불가 시 fswebcam으로 폴백)하고 선택적으로 Ollama의 로컬 비전 모델로 내용을 설명합니다.

look(action="describe")
look(action="find", prompt="a red ball")
look(action="capture")
필드타입의미
actionstring (필수)capture (사진만 촬영), describe (사진 + AI 설명), 또는 find (특정 대상 탐색 — prompt 필수).
promptstringdescribe 시 집중할 대상, find 시 탐색할 대상.

설명 기능을 비활성화하고 캡처만 사용하려면 camera.vision_model = "none"으로 설정하세요. 프레임은 ~/.revka/captures/에 저장됩니다.

listen은 마이크로 몇 초간 녹음하고 Whisper.cpp로 음성을 텍스트로 변환합니다.

listen(duration=5)
필드타입기본값의미
durationinteger5녹음 길이(초, 130).
promptstring변환을 위한 선택적 컨텍스트 힌트 (예: "The speaker is a child").

audio.whisper_pathwhisper.cpp 바이너리가 필요합니다. 모델 크기는 audio.whisper_model로 설정합니다(tiny 가장 빠름 → small 가장 정확).

speak는 Piper TTS로 텍스트를 음성으로 변환하여 스피커로 재생합니다. 짧은 효과음 재생도 지원합니다.

speak(text="Hello, I am ready.")
speak(sound="chime")
필드타입의미
textstring말할 텍스트.
emotionstring톤: neutral (기본값), excited, sad, 또는 whisper.
soundstring말하는 대신 효과음 재생 (예: beep, chime, laugh, alert).

audio.piper_pathpiper 바이너리와 audio.piper_voice에 음성 모델이 필요합니다.

emote는 LED 매트릭스에 얼굴을 표시하고 매칭되는 효과음을 재생하여 로봇을 더욱 생동감 있게 만듭니다.

emote(expression="happy")
emote(expression="excited", animation="dance")
필드타입기본값의미
expressionstring (필수)happy, sad, surprised, thinking, sleepy, excited, love, angry, confused, 또는 wink.
animationstring선택적: blink, nod, shake, 또는 dance.
soundbooleantrue매칭되는 효과음 재생.
durationinteger3표정 유지 시간(초, 최대 10초).

LED 백엔드는 FIFO/제어 스크립트가 있을 경우 이를 통해 출력하고, LED 하드웨어가 없을 경우 패턴을 무해하게 로그로 기록합니다.

SafetyMonitor는 LLM이 호출할 수 있는 도구가 아닙니다 — 모든 이동을 제어하는 독립적인 백그라운드 태스크입니다. SafeDrive 래퍼는 DriveTool 앞에 위치하므로, create_safe_tools(...)로 도구를 빌드하면 모든 drive 호출은 모터가 작동하기 전에 모니터의 사전 승인을 받아야 합니다.

다섯 가지 안전 레이어를 강제합니다:

  1. 사전 이동 확인 — 이동 전 경로가 깨끗한지 확인합니다.
  2. 능동 모니터링 — 이동 중 지속적인 센서 폴링; 근접도에 따라 속도가 감소합니다.
  3. 반응형 정지 — 장애물 또는 범퍼 센서 접촉 시 즉시 정지합니다.
  4. 워치독 타이머max_drive_duration 내에 새 명령이 없으면 자동 정지; 센서 데이터가 오래된 경우에도 이동이 차단됩니다.
  5. 하드웨어 E-stopestop_pin의 물리적 버튼이 모든 것을 재정의합니다; 명시적으로 리셋할 때까지 잠긴 상태를 유지합니다.

안전 상태와 이벤트를 관찰할 수 있습니다: 모니터는 can_move 플래그, estop_active 플래그, 현재 최소 장애물 거리, 근접 기반 속도 배율, 차단 이유를 추적합니다. 구독 가능한 tokio::sync::broadcast 채널을 통해 SafetyEventObstacleDetected, EmergencyStop, WatchdogTimeout, BumpDetected, MovementApproved, MovementDenied, Recovered — 를 브로드캐스트합니다.

설정 키타입기본값의미
min_obstacle_distancefloat (m)0.3장애물이 이 거리보다 가까우면 이동하지 않습니다.
slow_zone_multiplierfloat3.0min_obstacle_distance × multiplier 범위 내에서 감속을 시작합니다.
approach_speed_limitfloat0.3감속 구간 내 속도 상한 (최대 속도의 비율).
max_drive_durationint (s)30워치독 창 — 새 명령 없이 이 시간이 지나면 자동 정지.
sensor_timeout_secsint (s)5센서 데이터가 이 시간보다 오래된 경우 모든 이동을 차단합니다.
blind_mode_speed_limitfloat0.2센서가 mock/사용 불가 상태일 때 속도 상한.
estop_pinint (BCM)4물리적 비상 정지 버튼 GPIO (null로 비활성화).
bump_sensor_pinsint[] (BCM)[5, 6]섀시 마이크로스위치; 즉시 정지를 트리거합니다.
bump_reverse_distancefloat (m)0.15범퍼 충돌 후 후진 거리.
predict_collisionsbooltrue궤적 예측 (LIDAR 필요).
confirm_movementboolfalse각 이동 전 음성 확인 요구.

먼저 안전 모니터를 빌드하고, SafeDrive로 래핑된 도구 세트를 생성한 후, 에이전트 루프에 도구를 등록합니다:

use revka_robot_kit::{RobotConfig, SafetyMonitor, create_safe_tools};
use std::sync::Arc;
// Load configuration (or RobotConfig::default() for mock mode)
let config = RobotConfig::load(std::path::Path::new("~/.revka/robot.toml"))?;
// Create the independent safety monitor
let (safety, _events_rx) = SafetyMonitor::new(config.safety.clone());
let safety = Arc::new(safety);
// All six tools, with drive wrapped by SafeDrive
let tools = create_safe_tools(&config, safety.clone());
// Register `tools` with the Revka agent loop, then drive the safety loop:
// tokio::spawn(async move { safety.run(sensor_rx).await; });

안전 래퍼 없이 도구를 사용하려면(mock 개발 전용) create_tools(&config)를 대신 사용하세요. 등록 후 에이전트는 자연어를 통해 로봇에 접근합니다:

Terminal window
revka agent -m "Look around, tell me what you see, then move forward 1 meter if the path is clear"

Pi 5, 모터 컨트롤러, LIDAR, 카메라, 마이크, 스피커, LED 매트릭스, E-stop, 범퍼 센서를 포함한 완전한 로봇 빌드는 crates/robot-kit/PI5_SETUP.md를 따르세요. 이 문서에는 기본 robot.toml에서 사용하는 GPIO 배선 맵이 포함되어 있습니다(E-stop은 GPIO 4, 범퍼 센서는 5/6, 모터 PWM은 12/13, PIR은 17/27, LED 매트릭스는 18, 초음파는 23/24). 소프트웨어 의존성(Ollama, Whisper.cpp, Piper, ALSA, ffmpeg)은 crates/robot-kit/README.md에 나열되어 있습니다.