나온 지 좀 오래되었지만, 전자책으로 대여하여 읽었다. 지금도 중국 경제 발전이 영원할 것 처럼 보인다. 코로나 19를 겪으면서 성장률 6%가 꺾였지만, 그 후 8%를 기록하면서 중국이 계속 경제를 성장 시킬 수 있어 보인다. 이런 성장세로 향후 수십년간 미국을 제치고 탑으로 올라설 것 이라고 많은 사람들이 예측한다.
중국 경제 발전이 빠르면 여러 나라들이 좋고, 특히 중국 옆에 있는 우리도 좋겠지만, 저자가 지적한 다른 의견도 있다. 이 책 저자가 중국이 이미 중진국 함정에 빠져있어, 수십년이 지나도 같은 상황일 것 이다 라고 주장한다. 저자 뇌피셜이 아닌게 책 마지막 1/5를 참조 문서로 채웠다.
책은 REAP란 농촌 실태를 조사하는 단체? 비영리 기관?이 연구한 결과를 토대로 서술 되었다. 단체 성격에 맞도록 그 관심이 농촌에 있다. 이런 배경으로 농촌에 거주하는 70% 인적자원 향상이 없이 중국이 중진국에서 벗어날 수 없다고 주장한다. 중국 고유의 후커우 제도, 지방 관리가 시행하는 단기적인 정책, 중국 특유의 인간 경시 생각 등 모두가 인적 자원 향상을 방해하는 요인들이다.
단순 기술만 필요하는 많은 직업들이 기업이 더 싼 노동력을 제공하는 국가로 공장을 옮겨 없어질 것, 자동화로 사람이 필요 없어질 것 이라는 의견에 동의한다. 게다가 최근 미국의 압박으로 첨단 산업도 중국을 떠나고 있다. 중국이 제한된 시간안에 저자가 지적한 어려운 인적자원 향상을 달성하여 중진국을 탈출 할 수 있을지 기대된다.
저자가 중진국 탈출 예시로 사용한 한국, 대만, 아일랜드는 중진국 탈출 과정에 불필요한 혁명, 급격한 정치적인 변화가 없어 탈출이 가능했다고 생각한다. 이런 면에서 트정 시대의 급격한 이벤트인 문화혁명이 여러 세대에 거쳐 트라우마가 되었다.
gazebo 모델 에디터에서 원하는 모양을 그리기 너무 어렵다. 좌표를 수정하기 어렵고, 버그로 인해 객체가 가끔 보이지 않는다. 이번 기회에 오픈소스 프로그램 blender를 배워 3d로 직접 그리기로 했다.
쉬운 게 없다고, blender는 다른 세상이다. 기본인 mesh에서 solidify로 두께를 만든다 던가, cursor를 selection으로 이동하는 등 몇 가지 필수로 알아야 한다. 기본이 없는 상태에서 시작하면 시간을 너무 오래 쓴다. 2D 그림보다 3D 그림이 삼십배 시간이 많이 든다. 3D로 그릴 때 dimension 넣는 방법도 몰라 한참을 헤맸다.
디멘전까지 정확하게 넣었고, 잘 이동한 다음, 줄과 열을 맞춰 4~5개 객체를 통째로 stl로 출력했다. 자 이제 이 단순화된 그림을 gazebo 모델 에디터로 부르기만 하면 된다. 기존에 10개 넘었던 링크가 2개로 단순화 된다!
웬걸..망했다. gazebo는 대략적으로 형상과 재질을 설정하고, 무게와 관성 모멘트를 대충 넣어 주는데, stl을 불러오면 그런 거 하나도 없다. 눈에 어떻게 보이는지만 다르다. 결론은 복잡해도 gazebo에서 대략적으로 그려줘야 한다. 하루종일 그려준게 아까우니 urdf로 만든 파일에 geomery에서 mesh를 찾아 넣어 주기로 했다.
아. gazebo에서 그릴 때 좌표계를 확인하고 넣어 줬어야 했는데, 쓰기 어렵다 보니 일일히 신경쓰지 않았다. 웬걸. 스킨이 방향이 하나도 안 맞는gazebo 모델 에디터에서 원하는 모양을 그리기 너무 어렵다. 좌표를 수정하기 어렵고, 버그로 인해 객체가 가끔 보이지 않는다. 이번 기회에 오픈소스 프로그램 blender를 배워 3d로 직접 그리기로 했다.다. 이거 하는데 하루 종일 걸렸다. 알면 너무나 쉬운데, 모르면 너무 오래 걸린다.
urdf로 모델을 그리려면 각 좌표값를 모두 알아야 한다. 수치를 넣어야 되는데 시간 많이 걸린다. 다행히도 gazebo가 제공하는 model 에디터로 사각형, 바퀴 등 을 쉽게 그릴 수 있다. 원하는 그림이 없다면 무료 프로그램인 blender로 스케치한 다음 stl, dae 파일로 export 후 gazebo에서 import하면 만족도가 높아진다.
그런데 ros가 urdf를 정식으로 지원하고, sdf는 지원하지 않는 듯 하다. sdf만으로는 joint_state_publisher, robot_state_publisher를 제대로 이용할 수 없다. sdf와 urdf는 사용 분야가 다르고, 한 형식이 확장하는 개념은 아니다. ros에서 모델을 불러 제어하기 위해서는 어떻게든 sdf를 urdf로 바꿔야 한다고 결론을 냈다. 다행히 관련 스크립트를 찾을 수 있었다.
여기를 보면 centering 하다가 죽었음을 알았다. 왜 그런지 알 수 없으니, stdout에 표시된 코드를 보면 joint_state_publiser_gui의 182번 줄에서 죽었음을 확인했다.
QStandardPaths: wrong ownership on runtime directory /run/user/1000, 1000 instead of 0
QStandardPaths: wrong ownership on runtime directory /run/user/1000, 1000 instead of 0
Traceback (most recent call last):
File "/opt/ros/noetic/lib/joint_state_publisher_gui/joint_state_publisher_gui", line 52, in <module>
jsp_gui = joint_state_publisher_gui.JointStatePublisherGui("Node: " + rospy.get_name(),
File "/opt/ros/noetic/lib/python3/dist-packages/joint_state_publisher_gui/__init__.py", line 125, in __init__
self.center()
File "/opt/ros/noetic/lib/python3/dist-packages/joint_state_publisher_gui/__init__.py", line 182, in center
joint_info['slider'].setValue(self.valueToSlider(joint['zero'], joint))
TypeError: setValue(self, int): argument 1 has unexpected type 'float'
[joint_state_publisher_gui-1] process has died [pid 11275, exit code 1, cmd /opt/ros/noetic/lib/joint_state_publisher_gui/joint_state_publisher_gui __name:=joint_state_publisher_gui __log:=/root/.ros/log/b95997f0-47a6-11ed-a96e-2cf05d88e0ec/joint_state_publisher_gui-1.log].
log file: /root/.ros/log/b95997f0-47a6-11ed-a96e-2cf05d88e0ec/joint_state_publisher_gui-1*.log
여기 있는 gmapping, slam 튜토리얼을 했다. 튜토리얼은 상당히 쉽게 구성되어 있으나, 내가 실재로 해보면 잘 안된다. 왜 그런지 확인하기 위해 삽질을 했다. 해당 사이트에서 다운로드 받을 수 있는 rosbag 파일에 어떤 토픽이 저장되어 있는지 궁금했다. rqt가 제공하는 rosbag 플러그인으로 어떤 데이터가 있는지 확인했다.
rosbag play로 실행하면 뭐가 잘못 되었는지 다음 메세지를 보았다. debug 레벨을 켜라는 소리인 듯 한데…
[ WARN] [1664664315.511464153]: MessageFilter [target=odom ]: Dropped 100.00% of messages so far. Please turn the [ros.gmapping.message_filter] rosconsole logger to DEBUG for more information.
rosconsole로 message filter 현재 상태를 확인하고 변경할 수 있다.
root:workspace$rosconsole get /slam_gmapping ros.gmapping.message_filter
info
root:workspace$rosconsole set slam_gmapping ros.gmapping.message_filter debug
rosbag에 -a 옵션을 주고 모든 데이터를 저장하면 지도를 만들 수 있다. 아래와 같이 tf와 scan 데이터만 저장한 다음 rosbag play를 실행하면 tf tree가 끊어져 있다. 정확하게는 basefoot_print와 base_link가 끊겨져 있고, scanner_link가 없다.
ros@workspace$rosbag record /tf /laser/scan
[ INFO] [1664767902.638118674]: Subscribing to /laser/scan
[ INFO] [1664767902.642276643]: Subscribing to /tf
[ INFO] [1664767902.645339564]: Recording to '2022-10-03-03-31-42.bag'.
ros@workspace$ros@bag$rosbag play --clock 2022-10-03-03-31-42.bag
하나씩 해 보다가 /tf_static까지 record 해 보았다. 아, 힘들었다^^!
ros@bag$rosbag record -o mydata /tf /tf_static /laser/scan
[ INFO] [1664769638.007469286]: Subscribing to /laser/scan
[ INFO] [1664769638.011680347]: Subscribing to /tf
[ INFO] [1664769638.014193685]: Subscribing to /tf_static
[ INFO] [1664769638.298793651, 1626.350000000]: Recording to 'mydata_2022-10-03-04-00-38.bag'.
record한 결과를 보면 지도가 잘 생성됨을 확인했다. tf_tree를 보면
위 빠진 tf_tree와 다르게 base_footprint와 base_link가, base_link와 scanner_link가 연결되었다. 왜 이렇게 결정되었는지 확인해 보면, urdf에 fixed라고 joint를 정의해서 그렇다. 아래 urdf를 정의한 부분을 확인해 보면 fixed로 joint를 정의했기 때문에 tf_static을 필요로 한다.
42
43 <joint name = "base_footprint_fixed" type = "fixed">
44 <origin xyz = "0 0 0.03" rpy = "0 0 0"/>
45 <parent link = "base_footprint"/>
46 <child link = "base_link"/>
47 </joint>
48
146 <joint name = "left_wheel_joint" type = "continuous">
147 <origin xyz = "0.1 0.15 0" rpy = "0 0 0"/>
148 <parent link = "base_link"/>
149 <child link = "left_wheel"/>
150 <axis xyz = "0 1 0"/>
151
152 </joint>
153
154 <joint name = "left_wheel_joint_back" type = "continuous">
155 <origin xyz = "-0.1 0.15 0" rpy = "0 0 0"/>
156 <parent link = "base_link"/>
157 <child link = "left_wheel_back"/>
158 <axis xyz = "0 1 0"/>
159
160 </joint>
161
162
205 <joint name = "head_scanner" type = "fixed">
206 <!-- rpy를 수정하면 카메라 각도가 바뀜-->
207 <origin xyz = "0.15 0 0" rpy = "0 0 0"/>
208 <parent link = "base_link"/>
209 <child link = "scanner_link"/>
210 </joint>
211
기록한 rosbag 파이을 보면, scan, tf, tf_static 3개가 들어가 있다.
launch가 robot description을 실행하는데, command로 robot.xacro로 세부 설정을 한다. command가 아닌 다른 방식으로는 모델이 움직이지 않는다. robot description 내부에는 robot_description, joint_state_publisher, robot_state_publisher 3개를 설정한다.
now0930@amd2004:~/ros_test/workspace/src/wander_bot$ cat launch/robot_description.launch
<?xml version="1.0"?>
<launch>
<!-- send urdf to param server -->
<!-- xacro -->
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find wander_bot)/urdf/robot.xacro'" />
<!-- urdf or raw xml file -->
<!-- <param name="robot_description" command="cat $(find museumGuide)/urdf_model/peoplebot.xml" /> -->
<!-- Send fake joint values-->
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
<param name="use_gui" value="False"/>
</node>
<!-- Send robot states to tf -->
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" respawn="false" output="screen"/>
</launch>