주최: PINKLAB (https://pinklab.art/academy/26-workshop-2/)
- LeRobot 실행 환경 구성
- Teleoperation 기반 데이터셋 수집 (50 episode)
- Hugging Face 업로드:
haewon22/pick_and_place- Colab A100 환경에서 ACT 학습
환경

OMX-AI
리더암: 사람이 직접 조종하는 조종용 장치
팔로워암: 리더암의 움직임을 따라 하면서 실제 작업을 수행하는 로봇팔.
OMX-L은 원격 조작용리더 유닛OMX-F는 그리퍼가 달린 5-DOF 로봇암 팔로워 유닛LeRobot
Hugging Face에서 제공하는 오픈소스 로봇 학습 프레임워크
데이터셋 수집 → 데이터셋 저장 → 모델 학습 → 모델 추론까지 지원함
또한 Hugging Face Hub와 바로 연동되기 때문에, 수집한 데이터셋을 바로 업로드하고, 그 데이터를 다시 학습에 사용하기 유용하다.
포트 확인 및 udev 규칙으로 포트 고정
포트 고정?
Linux에서는 USB 장치가 연결 순서에 따라 /dev/ttyACM0, /dev/ttyACM1 같은 이름으로 잡힘
문제는 Leader와 Follower를 다시 꽂거나, 연결 순서가 바뀌면 이 번호가 뒤바뀔 수가 있음 그러면 코드에서 Follower에 보내야 할 명령이 Leader로 가거나, 반대로 Leader 입력을 못 읽는 문제가 생길 수 있음
따라서 이름을 고정해 이후 명령어에서 안정적으로 사용할 수 있게 만들어야 함
먼저 어떤 장치가 어느 포트인지 확인하기 위해 lerobot-find-port를 사용
source ~/venv/il/bin/activate
lerobot-find-port
이 명령은 현재 연결된 포트를 저장한 다음, 특정 장치를 뽑았을 때 사라진 포트를 비교해서 해당 장치가 어떤 /dev/ttyACM* 인지 알려준다. 덕분에 Leader와 Follower를 각각 식별할 수 있었다.
그다음에는 포트 접근 권한 문제를 해결하기 위해 아래 과정을 진행하는 흐름을 이해했다.
sudo chmod 666 /dev/ttyACM0
sudo chmod 666 /dev/ttyACM1
sudo usermod -a -G dialout $USER
sudo reboot now
groups
여기서 chmod 666은 임시 해결이고, dialout 그룹 추가는 재부팅 이후에도 유지되는 영구적 방식이다. 즉 처음에는 일단 접근 가능하게 만들고, 장기적으로는 dialout 그룹으로 정리하는 흐름이라고 이해했다.
그다음에는 장치의 고유값을 읽어 udev 규칙에 사용할 정보를 확보했다.
udevadm info -q all -n /dev/ttyACM0 | egrep 'DEVNAME=|ID_VENDOR_ID=|ID_MODEL_ID=|ID_SERIAL=|ID_SERIAL_SHORT=|ID_MODEL=|ID_VENDOR=|ID_USB_INTERFACE_NUM='
udevadm info -q all -n /dev/ttyACM1 | egrep 'DEVNAME=|ID_VENDOR_ID=|ID_MODEL_ID=|ID_SERIAL=|ID_SERIAL_SHORT=|ID_MODEL=|ID_VENDOR=|ID_USB_INTERFACE_NUM='
이 단계에서 ID_VENDOR_ID, ID_SERIAL_SHORT 같은 값을 확인하고, 이를 기준으로 Leader와 Follower를 고정 이름에 매핑하는 udev 규칙을 만든다.
규칙 파일 구조는 아래처럼 정리할 수 있다.
sudo gedit /etc/udev/rules.d/99-omx.rules
예시 구조는 다음과 같다.
SUBSYSTEM=="tty", ATTRS{idVendor}=="<ID_VENDOR_ID>", ATTRS{serial}=="<FOLLOWER_SERIAL>", SYMLINK+="omx_follower"
SUBSYSTEM=="tty", ATTRS{idVendor}=="<ID_VENDOR_ID>", ATTRS{serial}=="<LEADER_SERIAL>", SYMLINK+="omx_leader"
규칙을 만든 뒤에는 아래 명령으로 다시 로드하고 결과를 확인한다.
sudo udevadm control --reload-rules
sudo udevadm trigger
ls -l /dev/omx_follower /dev/omx_leader
이렇게 해두면 이후에는 /dev/ttyACM0 대신, 의미가 분명한 장치 이름으로 로봇을 계속 제어할 수 있게 된다는 점이 가장 큰 장점이 있다.
하드웨어 연결이 끝난 뒤에는 LeRobot을 실행할 수 있는 Python 환경을 세팅했다. 실습에서는 Linux + Python 3.10 조합이 권장되었고, LeRobot 버전은 v0.4.4를 기준으로 사용했다.
Python 가상환경 설정
sudo add-apt-repository ppa:deadsnakes/ppa -y
sudo apt update
sudo apt install python3.10 python3.10-venv python3.10-dev -y
mkdir ~/venv
python3.10 -m venv ~/venv/il
source ~/venv/il/bin/activate
pip3 install --upgrade pip
LeRobot 설치
mkdir -p ~/il_ws/src && cd ~/il_ws/src
git clone --branch v0.4.4 <https://github.com/huggingface/lerobot.git>
cd ~/il_ws/src/lerobot
pip install -e ".[dynamixel]"
sudo apt install ffmpeg git
여기서 pip install -e ".[dynamixel]"는 현재 소스 폴더를 editable 모드로 설치하면서, DYNAMIXEL 관련 종속성까지 함께 설치하는 방식
ffmpeg는 수집되는 영상 데이터를 처리하기 위해 필요하다.
데이터를 모으기 전, 로봇이 정상적으로 움직이는지 먼저 확인하는 과정 크게 두 방식으로 접근할 수 있다.
먼저 키보드 입력으로 Follower를 직접 움직여보는 방식이다.
mv ~/Downloads/omx_f_keyboard_teleop.py ~/il_ws/src/
source ~/venv/il/bin/activate
cd ~/il_ws/src
ls -l /dev/omx_follower
python3 omx_f_keyboard_teleop.py
이 단계에서는 각 관절이 어떤 키에 연결되어 있는지, 그리퍼가 잘 열리고 닫히는지, 포트가 제대로 잡혀 있는지를 확인했다.
1 / q: Joint 12 / w: Joint 23 / e: Joint 34 / r: Joint 45 / t: Joint 5o / p: 그리퍼 열기 / 닫기ESC: 종료source ~/venv/il/bin/activate
cd ~/il_ws/src/lerobot
lerobot-teleoperate \\
--robot.type=omx_follower \\
--robot.port=/dev/omx_follower \\
--robot.id=omx_follower_arm \\
--teleop.type=omx_leader \\
--teleop.port=/dev/omx_leader \\
--teleop.id=omx_leader_arm
사람이 Leader를 움직이면 Follower가 실시간으로 따라오고, 이 과정이 곧 action 데이터의 기반이 된다. → 모델이 배울 demonstration을 만드는 작업
pick-and-place 50 episodes를 수집하였다.
source ~/venv/il/bin/activate
HF_USER=$(hf auth whoami | head -n 1 | sed 's/\\[[0-9;]*m//g' | awk -F': ' '{print $2}' | xargs)
cd ~/il_ws/src/lerobot && lerobot-record \\
--robot.type=omx_follower \\
--robot.port=/dev/omx_follower \\
--robot.id=omx_follower_arm \\
--robot.cameras="{
front: {type: opencv, index_or_path: 4, width: 640, height: 480, fps: 30},
wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}
}" \\
--teleop.type=omx_leader \\
--teleop.port=/dev/omx_leader \\
--teleop.id=omx_leader_arm \\
--display_data=true \\
--dataset.repo_id=haewon22/pick_and_place \\
--dataset.single_task="Pick up Doll and put in cup" \\
--dataset.episode_time_s=30 \\
--dataset.num_episodes=50 \\
--dataset.reset_time_s=10
-robot.*: Follower 로봇 설정-teleop.*: Leader 장치 설정-robot.cameras: 카메라 구성과 해상도, FPS 설정-display_data=true: 수집 중 실시간 시각화-dataset.repo_id=haewon22/pick_and_place: 오늘 실제 업로드한 저장소-dataset.num_episodes=50: 오늘 실제 수집한 episode 수-dataset.episode_time_s: 한 episode의 녹화 길이-dataset.reset_time_s: 다음 episode 전 정리 시간Recording → Reset → Recording → Reset ...
한 episode를 녹화하고, reset time 동안 물체를 다시 초기 위치로 옮긴 다음, 다음 episode를 계속 이어가는 방식이다.
또 녹화 도중에는 단축키로 세션을 제어할 수 있었다.
→ : 현재 episode 종료 후 다음 episode로 이동← : 현재 episode 취소 후 다시 녹화Esc : 세션 종료 및 업로드데이터셋은 LeRobotDataset 형식을 따른다.
action: 사람이 Leader로 시연한 관절값observation.state: Follower의 실제 관절 상태observation.images.front: 정면 시야 이미지observation.images.wrist: 손목 시야 이미지timestamp: 해당 step의 시각 정보frame_index: episode 안에서의 순서