#9까지 해서 gazebo에서 quadruped를 제어하기 위한 환경 세팅을 마쳤다.
환경을 만들었으니 이제는 '제어 테스트'를 해볼 차례이다.
제어라고 하지 않고 '제어 테스트'라고 한 것은 gazebo에 구현한 로봇은 내가 실제로 만들 로봇과 100% 같지 않을 것이기 때문이다. 질량이 균등하게 10배가 되어서 질량 중심은 이전과 같겠지만 그렇다고 각 link별 질량, 질량 중심, 상대 위치가 실제와는 조금씩 다를 것이기 때문이다.
또 시뮬레이션에서는 이상이 없다고 판단했지만 실물로 제작하니 부품 사이의 유격, 발견하지 못한 부품 간의 간섭, 모터의 백래시(backlash) 등이 있을 수도 있다.
즉 내가 gazebo 시뮬레이션으로 gait을 잘 구현해도 같은 제어 코드가 실물 로봇에는 잘 맞지 않을 가능성이 높다.
그래서 이번에 구현하는 gait은 간단하게 구현해보는 것이며, 어디까지나 현재 로봇 설계가 바뀔 정도로 큰 문제가 있는지 확인하는 것에 그 목적이 있다.
물론 제어가 그럴 뿐 기구학은 거의 들어맞을 것이라고 생각한다.
가장 먼저 제어에 꼭 필요한 역기구학(IK) 해석을 진행했다.
●다리 1개의 IK를 계산했으며, 다리 1개에 joint 3개가 있어 3dof이지만 구조상 joint0은 따로 분리하고 joint1 + 2 = 2dof만 해석해도 큰 문제가 없다고 판단해서 joint 1+2에 대해서만 진행했다.
●link를 하나의 직선으로 두고 계산해서 tibia의 경우 계산에선 z=0이 ground에 있는 것으로 표현되었지만 실제로는 tibia 끝 구의 반지름만큼 +z하는 것이 실제 위치이다. 끝 부분이 구형이기에 x에 관계없이 z=0이면 ground에 닿는 것이기에 문제가 없다고 판단했다.
tibia의 끝의 (x,z)좌표에 따른 J1, J2 각도를 계산해 냈다.
위와 같이 식을 구성한 것은 당연히 제어에 필요한 IK를 얻기 위함도 있지만, standby각도 θs에 따라 다리를 들 수 있는 높이(z>0)에 대한 탐구가 필요했기 때문도 있었다.
따라서 위 IK를 가지고 tibia끝이 그릴 수 있는 workspace를 그리는 Matlab code를 구성했다.
(보라색 점 : tibia끝이 도달할 수 있는 위치, 빨간색 별 : joint1,2의 위치(=body의 높이), 갈색 선 : ground (z=0))
아래는 각 ws에서 x=0일 때 z+로 가능한 높이를 정리한 것이다.
이후 gait을 제대로 공부한 후 trajectory를 수학적으로 치밀하게 만든다면 '다리를 들 수 있는 높이'가 다를수도 있지만 일단은 가장 간단하게 (0,z)를 '다리를 들수 있는 높이'로 잡았기에 이 수치를 비교해 보는 것이다.
θs | 35º | 40º | 45º |
다리를 들수 있는 높이 | 16mm | 28mm | 38mm |
일단 최소 16mm는 너무 짧고, 38mm는 다리를 높이 들 수 있어 좋긴 하지만 로봇의 standby시 높이가 너무 높아 안정성에 문제가 있을 것으로 판단되어 θs=40º으로 정했다.
사실상 θs까지 결정한 시점에서 설계와 urdf가 확정되었다. 그래서 이를 기반으로 urdf를 만들었고 간단한 동작을 구현하기 위해 기초적인 gait에 대한 내용을 공부했다.
여러 영상을 봤지만 아래 영상이 가장 이해하기 쉬웠다.
https://www.youtube.com/watch?v=O_2swSMecB4
현 설계에서 구현이 가능할 것으로 보이는 gait은 crawling, trotting이었고 gazebo에서는 빠르게 구현할 수 있는 crawling을 구현했다.
기본적인 제어 코드는 다음과 같이 구성했다.
IKnematics_2dof.py
●IK를 계산하는 함수를 포함하며 1개 다리에 대해 (x,z)를 input으로 주면 (J1,J2,fl)을 출력한다. 이때 fl은 J1, J2에 NaN이나 불가능한 각도의 값이 출력될 때를 방지하기 위해 넣은 인수로 -1이 나오면 유효하지 않은 J1, J2임을 의미한다.
trajectory.py
●여러 trajectory를 planning해주는 코드로 현재는 linear trajectory 함수만 구현한 상태이다. numpy의 array를 이용하며 1개 다리에 대해 두 point(x,z)와 step_num을 넣으면 직선 trajectory에 대한 (J1, J2)를 2*step_num의 array로 출력한다.
●추후 linear 외에 곡률 c(curvature)를 주어 구현하는 curvature_trajectory, 사다리꼴로 이동하는 trapezoid_trajectory 를 구현할 예정이다.
push_up.py
●로봇 body를 z축으로만 움직이는, 위아래로 움직이는 코드로 IK와 linear trajectory 코드가 잘 구현되었는지 테스트하기 위해 가장 먼저 구현한 동작이었다.
●push_up을 포함한 다른 동작들 전부 trajectory planning -> execute의 과정으로 코드가 구성되었다.
CLT_controller.py
●IK가 잘 구현되었는지를 더 자세히 보기 위해 만든 코드로 터미널에서 다리와 특정 point(x,z)를 입력하면 그 다리를 그 point에 맞게 이동시키는 코드였다.
Crawling.py
●crawling 동작을 간단하게 구현해 본 코드로 4개 다리가 1개씩 앞으로 움직이는 방식의 gait이다. LF-RF-LB-RB 순으로 다리를 앞으로 내딛으며 각 다리마다 Tilting-Forward-Down의 과정을 거친다.
+)gait에 대한 공부는 추후 다른 gait을 포함해서 더 자세하게 다룰 예정입니다.
●tilting은 다리를 드는 동작이면서 무게 중심을 지면과 닿은 3개 tibia가 그리는 삼각형 내로 이동시키기 위한 동작이다.
●Forward는 다리를 앞으로 내딛는 동작이며 Down은 내디딘 다리를 내려 다시 4개 다리로 땅에 서있게 하는 동작이다.
위의 코드는 이번 시도의 결과로 나온 코드를 간략하게 정리한 것이고 아래는 그 과정에서 내가 고민하거나 새로 배웠던 내용을 정리한 것이다.
Python, ROS
●deep copy와 shallow copy에 대한 내용을 이전에 배웠지만 쓸 기회가 마땅히 없었는데 이번에 확실하게 그 차이를 체감했다. 단순하게 B=A를 이용하니 B를 바꿔도 A가 바뀌는 문제가 발생했기에 copy() 메서드를 사용해 deep copy를 사용했다.
●crawling을 구현할 때 initial pose로써 standby로 만들어줄 필요가 있었기에 [0.0, 0.0, 0.0, ..... 0.0, 0.0]의 joint명령을 1번만 pulish해줬지만 topic이 publish 되었음에도 controller 노드가 이를 subscribe하지 못하는 문제가 발생했었다.
이는 처음에 노드를 initialize하면 약간의 connection을 위한 delay가 생기는데 이때 보내지는 메시지는 씹힐 수 있기에 발생하는 문제였다.
따라서 처음에 pub.get.connections() 함수를 이용해 connection을 확인하는 루프를 추가하는 것으로 이를 해결했다. 자세한 내용은 아래의 영상에 잘 설명되어 있다.
https://www.youtube.com/watch?v=QZLM2u-qjC4
●numpy의 array를 처음 사용했고 vstack, shape 등의 함수를 사용해 trajectory를 만들었다.
내 Quadruped
●설계 때 좌우의 무게 중심에 대한 것은 최대한 조정했지만 앞 뒤 중심에 대해서는 충분히 하지 않았었다. 4족 보행의 경우 무게 중심을 다리 3개가 그리는 삼각형 안에 위치시키는 것이 핵심이기에 내 로봇의 CoM(Center Of Mass)가 어떻게 잡혔는지에 대한 확인이 필요했다.
●이를 위해 standbt상태에서 tilting 없이 한쪽 다리만 들었을 때 어느 쪽으로 넘어지는 지를 확인했다. 하지만 어느 다리를 들어도 그쪽으로 넘어졌고 이는 매우 이상한 상황이었다.
CoM이 위와 같이 잡혀 있는 상황을 가정하면 (a)는 LF를 들었을 때 삼각형 밖에 있으므로 LF로 넘어지지만 그렇기에 (b)에서 RB를 들었을 때 자명하게 RB로 넘어질 수 없었다. 이는 CoM이 어느 4분면(?)에 있어도 적어도 한쪽으로는 넘어지지 않아야 했음을 확인할 수 있는 그림이다.
●나는 다리의 mass를 매우 작게 잡았고 애초에 테스트에서 다리를 z방향으로만 이동시켰기에 CoM이 다리를 든다고 바뀔 수도 없었다.
●나는 이 상황에 대해 일단은 '시뮬레이션에서 구현한 모터의 진동 및 다리를 들 때 발생하는 약간의 각운동량에 의해 발생한 문제'로 결론지었다. 이를 깊게 파고들지 않은 이유는 현재 urdf의 inertial이 현실과 차이가 크다는 점과 모터도 현실적으로 gain을 잡지 못했기 때문이었다.
(12.1추가)##############################################
위에서 발생한 문제의 답이 되지는 않지만 그간 잘못 생각하고 있던 부분을 갑자기 깨달았다.
시중의 rc서보모터는(적어도 MG996R)은 그 CoM이 중심에 잘 오도록 설계되어 있다.
하지만 지금 나의 설계로 stand 자세를 하게 되면 너무나도 자명하게 모터의 CoM이 tibia와 바닥의 접점과 같은 선상에 있지 않게 된다.
즉 로봇 전체로 보면 CoM이 앞쪽으로 e만큼 가도록 되어 있다는 것이다.
이는 간단하게 로봇의 기본 자세를 수정하는 것으로 해결 했다.
mg996 datasheet에 의하면 축과 모터 중심사이의 거리 e는 10mm이므로 그만큼 다리를 앞으로 이동시킨 자세로 바꿔주면 된다.
마침 다리 동작 코드도 IK기반으로 작성했기에 더욱 쉽게 수정할 수 있었다.
######################################################
●따라서 일단은 crawling에서 과도하게 tilting을 하는 것으로 이 문제를 우회했고 해당 문제는 실물을 제작한 후 실물에 대해서도 다시 한번 확인을 해볼 예정이다.
●추가로 이 이상한 문제를 통해 quadruped에서 CoM control이 얼마나 중요한지 간접적으로 느꼈고 또 Quadruped에 적용해 볼 만한 새로운(나름대로 novel하다고 생각하는) 아이디어도 얻었다. 이는 이번 프로젝트에서 적용할 것이다.
어쨌든 여기까지 해서 quadruped prototype의 설계와 간단한 검증을 마쳤다.
다소 찜찜하고 치밀하게 검증하지 못한 부분이 있지만 prototype의 시뮬레이션이기에 70% 정도의 가능성만 확인해도 실물 제작으로 넘어가도 된다고 생각한다. 어디까지나 prototype이기 때문이다.
추가로 예상외로 너무 시간을 많이 썼기에 하루빨리 실물 제작으로 넘어가야 하는 점도 있었다...
이제 실물용 모델링 제작과 동시에 실물 제작에 들어간다.
========================================================================
정확한 정보 전달보단 공부 겸 기록에 초점을 둔 글입니다.
틀린 내용이 있을 수 있습니다.
틀린 내용이나 다른 문제가 있으면 댓글에 남겨주시면 감사하겠습니다. : )
========================================================================