MATLAB / Simscape Multibody tooling for Phil, the AI drummer robot.
Replay logged motion on a physical model, plot motor tracking, and check arm–stick collisions.
The C++ controller (phil-control) writes two kinds of CSV logs while Phil plays: a per-motor tracking log and a 13-joint trajectory log. These MATLAB scripts turn those logs into something you can look at.
plot_motors: per-motor figures with desired vs. actual position, tracking error and torque/current for all 13 motors.simulation_motors: cuts a time window out of a motor log, converts motor angles into joint angles, and replays both arms on a Simscape Multibody stick model above the drum kit. Desired motion is drawn in black, the measured motion in red, so tracking lag is visible in 3D rather than on a plot.simulation_trajectory: replays a 13-joint, 5 ms trajectory on the URDF mesh model of the robot, plots every joint against its limits, and runs an OBB + Separating Axis Theorem collision check between the two arms and the two drum sticks (sat/check_collision.m).- Portable: the Simulink models reference their datasets and STL meshes by paths relative to the repository root, so the whole thing runs from a fresh clone.
| Simscape replay of a motor log (desired = black, actual = red) | Trajectory replay: joint limits, feet, head and collision flag |
|---|---|
![]() |
![]() |
| Motor tracking plots, IDs 0–3 | IDs 7–10 (wrists and pedals) |
|---|---|
![]() |
![]() |
% MATLAB current folder must be the repository root
plot_motors % log/log_0904_1554_motors.csv -> one figure per motor
simulation_trajectory % log/log_0909_1433_trajectory.csv -> sim_trajectory replay + plots + collision check
simulation_motors % WS.mat cache -> sim_motors replay of t = 170..205 sRequirements: MATLAB R2021b or newer with Simulink and Simscape Multibody. No other toolboxes.
| Repo | Role |
|---|---|
| phil-control | C++17 real-time body controller that produces the logs analysed here |
| phil-interaction | Python brain: Whisper STT → LLM planner → validated commands → MeloTTS |
| phil-simulation | Frame-level PyBullet SIL fed by the controller's raw CAN frames and Dynamixel packets |
| phil-midi-converter | MIDI ↔ score converter |
| phil-matlab-analysis (this repo) | MATLAB log analysis and Simscape replay |
Developed at KIST. The detailed documentation below is in Korean. / 아래부터는 상세 한국어 문서입니다.
phil-matlab-analysis/
├── plot_motors.m # 모터 로그 → 모터별 3단 그래프 (desired/actual, error, torque/current)
├── load_log_data.m # 모터 로그 CSV 파서. 13개 모터 cell로 분리, saved_log_data.mat 캐시 저장
├── simulation_motors.m # 모터 로그 구간 → 관절각 변환 → simulink/sim_motors 재생
├── simulation_trajectory.m # 궤적 로그 → simulink/sim_trajectory 재생 + 관절 한계 플롯 + 충돌 검사
├── delete_end_line.m # CSV 앞부분 행 삭제 유틸 (파일을 제자리에서 덮어씀)
├── sat/check_collision.m # FK + OBB 생성 + 분리축 정리(SAT) 충돌 검사 (자체 완결)
├── simulink/
│ ├── sim_motors.slx # 스틱 모델: Cylindrical/Spherical Solid + Revolute Joint, 드럼 9개, desired/actual 팔 2쌍
│ ├── sim_trajectory.slx # URDF 메시 모델 (File Solid 12개) + 13관절 데이터셋 입력
│ └── data_*.mat # 스크립트가 생성하는 Simulink.SimulationData.Dataset (From File 블록 입력)
├── urdf/
│ ├── drumrobot_RL_urdf/ # SolidWorks에서 내보낸 ROS 패키지 (urdf, meshes/*.STL, config, launch)
│ └── drumrobot_RL_urdf.slx # smimport 결과 원본 모델
├── log/ # 샘플 로그 2개 (나머지는 .gitignore)
├── WS.mat # simulation_motors 기본 설정이 참조하는 모터 로그 캐시
└── docs/ # Mechanics Explorer / 결과 그래프 스크린샷
한 줄이 모터 하나의 샘플입니다. load_log_data가 ID별로 나눠 log_data{id+1}에 7열 행렬로 담습니다.
| CSV 열 | 의미 | log_data 열 |
|---|---|---|
| 1 | t (s) | 1 |
| 2 | motor id (0~12) | – |
| 3 | mode (1 = position/CSP, 그 외 velocity/CST) | 2 |
| 4 | desired position (rad) | 3 |
| 5 | actual position (rad) | 4 |
| 6 | position error | 5 |
| 7 | torque/current (DXL 11, 12는 0) | 6 |
| 8 | control input (velocity/CST 모드일 때만) | 7 |
load_csv_file = true면 CSV를 읽고 saved_log_data.mat에 저장, false면 data_name.mat을 바로 읽습니다. 원본 로그는 수백 MB라 저장소에는 5 MB짜리 log_0904_1554_motors.csv(ID 0~8, 약 40초)만 두었습니다.
t, joint 0 … joint 12 14열, 5 ms 간격, 단위 rad. simulation_trajectory가 13열 행렬 q로 읽습니다.
모터별로 figure 하나씩 띄웁니다. 위에서부터 actual(파랑)·desired(빨강) 위치, 오차, 토크/전류입니다. file_name만 바꾸면 됩니다.
- 상체 모터 9개(ID 0~8)의
t, mode, desired, actual을 뽑습니다. 손목(7, 8)은 샘플링이 5배 빠르므로 5배 간격으로 다운샘플합니다. [t1 t2]구간(기본 170~205 s)을 잘라 모터각을 관절각으로 바꿉니다.q = motor .* sign + init,sign = [1 -1 -1 1 -1 -1 1 -1 -1],init = [10 90 90 0 90 0 90 90 90]°.- desired / actual 각각
simulink/data_desired{0..8}.mat,simulink/data_actual{0..8}.mat으로 저장하고sim_motors를 실행합니다.
모델 안에서 쓰는 로봇 치수(DH)와 드럼 위치도 이 스크립트에 있습니다. 스틱 0.373 m, 어깨 폭 0.520 m, 어깨 높이 0.9595 m, 상완 0.230 m, 하완 0.200 m. 드럼 9개(스네어, 플로어탐, 미드탐, 하이탐, 하이햇, 라이드, 오른/왼 크래시, 오픈 하이햇)는 좌우 실측 좌표의 평균입니다.
- 궤적 CSV를 읽어
simulink/data_{0..12}.mat으로 저장하고sim_trajectory를 실행합니다. - 팔 9관절을 한계선과 함께, 발(q9, q10)과 머리(q11 yaw, q12 pitch)를 따로 그립니다.
sat/check_collision으로 프레임마다 충돌 여부를 계산해 시간축에 표시합니다.
관절 한계(도):
| q0 | q1 | q2 | q3 | q4 | q5 | q6 | q7 | q8 | |
|---|---|---|---|---|---|---|---|---|---|
| min | -90 | 0 | 30 | -60 | 0 | -60 | 0 | -30 | -30 |
| max | 90 | 150 | 180 | 90 | 140 | 90 | 140 | 90 | 90 |
FK: 허리 회전과 양팔 관절각에서 팔꿈치, 손목, 스틱 끝 위치를 계산합니다.get_OBB_data: 오른팔, 왼팔, 오른 스틱, 왼 스틱을 각각 OBB(방향 있는 직육면체)로 만듭니다.- 네 쌍(오른팔-왼팔, 오른팔-왼스틱, 오른스틱-왼팔, 오른스틱-왼스틱)에 대해 분리축 정리를 적용합니다. 축 후보는 두 박스의 면 법선 6개와 모서리 외적 9개, 총 15개입니다. 스틱 끝의 x 좌표가 뒤바뀐(팔이 교차한) 프레임은
is_cross플래그로 따로 처리합니다. - 결과는
n × 4논리 행렬이고, 어느 한 쌍이라도 겹치면 그 프레임을 충돌로 표시합니다.
sim_motors.slx: Simscape Multibody 기본 블록만 사용합니다. 두 팔을 desired/actual 두 벌 만들고, 색과 굵기는 스크립트 변수(desired_line_color,actual_point_size등)로 넘깁니다. 관절 입력은 From File 블록 18개입니다.sim_trajectory.slx:urdf/drumrobot_RL_urdf.slx(smimport결과)를 바탕으로 13개 Revolute Joint에 From File 입력을 붙인 모델입니다. 링크 형상은urdf/drumrobot_RL_urdf/meshes/*.STL을 File Solid로 읽습니다.simulation_time변수를 모델 정지 시간으로 씁니다.
원본 모델은 데이터셋과 STL을 Windows 절대 경로로 참조하고 있었습니다. 이 저장소의 모델은 From File의 FileName과 File Solid의 ExtGeomFileName을 저장소 루트 기준 상대 경로(simulink/…, urdf/drumrobot_RL_urdf/meshes/…)로 바꿔 두었습니다. 따라서 MATLAB 현재 폴더가 저장소 루트여야 합니다.
From File 블록이 내부에 캐시한 파일 정보(모델 파일 안의 bdmxdata)에는 예전 절대 경로 문자열이 남아 있습니다. 시뮬레이션은 FileName 파라미터를 기준으로 파일을 찾으므로 문제가 없어야 하지만, 혹시 "file not found" 경고가 나오면 해당 From File 블록을 열어 파일을 한 번 다시 선택하고 저장하면 됩니다.
- 컨트롤러 로그 원본 약 3.2 GB (150여 개). 샘플 2개만 포함했습니다.
TY.mat,saved_log_data.mat같은 재생성 가능한 캐시.- 스크립트 초안과 백업 폴더,
slprj/,*.slxc,*.asv.



