[PROJECTS] MobileRobot1
Intro
나만의 모바일 로봇을 만들어보자. 모바일 로봇의 이미지부터 컨트롤 관련 코드를 직접 작성해보도록 하겠다. 더불어 카메라, 센서 등을 통해 얻은 데이터를 처리할 수 있도록 하는 것이 최종 목표이다.
1. Robot_pkg
Workspace에 'my_robot_pkg'
를 생성하자.
$ ros2 pkg create --build-type ament_cmake --node-name my_robot my_robot_pkg
$ mkdir launch rviz udrf
📦my_robot_pkg
┣ 📂include
┃ ┗ 📂my_robot_pkg
┣ 📂launch
┣ 📂rviz
┣ 📂src
┃ ┗ 📜my_robot.cpp
┣ 📂urdf
┃ ┗ 📜my_robot.urdf
┣ 📜CMakeLists.txt
┗ 📜package.xml
이때 생성한 launch
, rviz
, udrf
디렉터리의 용도는 다음과 같다.
-
launch Directory: launch 디렉터리는 ROS에서 사용되는 런치 파일들을 저장하는 곳이다. 런치 파일은 ROS 시스템을 시작하는 데 사용되는 XML 형식의 설정 파일이다. 이 파일들은 ROS 노드, 토픽, 서비스, 액션 서버 등과 같은 ROS 구성 요소들을 정의하고 실행하는 데 사용된다.
-
rviz Directory: 로봇 패키지의 rviz 디렉토리는 ROS 시각화 도구 중 하나인 RViz와 관련된 파일을 포함하는 디렉토리이다. RViz는 로봇의 상태, 센서 데이터, 경로 등을 시각화하는 강력한 도구로, 로봇 개발 및 디버깅에 유용하게 사용된다.
-
urdf Directory: urdf 디렉터리는 ROS에서 사용되는 URDF(Unified Robot Description Format) 파일을 저장하는 곳이다. URDF는 로봇 모델의 기하학적 형태, 관절, 연결 및 센서 등의 정보를 정의하는 XML 기반의 파일 형식이다. 이 디렉터리에는 로봇의 URDF 파일 뿐만 아니라 관련된 자원 파일들도 함께 저장될 수 있다.
이후에 'CMakeLists.txt'
파일에 아래의 코드를 추가해준다.
# Install launch files
install(DIRECTORY
launch
urdf
rviz
DESTINATION share/${PROJECT_NAME}
)
1.1. URDF
우선 'urdf'
디렉터리를 생성하고 'my_robot.urdf'
를 통해 로봇을 만들어보자.
xacro를 통해 inertial와 관련하여 정의를 한 뒤에 링크를 서로 연결하여 간단하게 모델을 생성해보자.
코드는 다음과 같다.
<?xml version="1.0"?>
<robot name="my_robot" xmlns:xacro="http://ros.org/wiki/xacro">
<xacro:property name="base_width" value = "0.31"/>
<xacro:property name="base_length" value = "0.42"/>
<xacro:property name="base_height" value = "0.18"/>
<xacro:property name="wheel_radius" value="0.10"/>
<xacro:property name="wheel_width" value="0.04"/>
<xacro:property name="wheel_ygap" value="0.025"/>
<xacro:property name="wheel_zoff" value="0.01"/>
<xacro:property name="wheel_xoff" value="0.05"/>
<xacro:property name="caster_xoff" value="0.1"/>
<!-- Define intertial property macros -->
<xacro:macro name="box_inertia" params="m w h d">
<inertial>
<origin xyz="0 0 0" rpy="${pi/2} 0 ${pi/2}"/>
<mass value="${m}"/>
<inertia ixx="${(m/12) * (h*h + d*d)}" ixy="0.0" ixz="0.0" iyy="${(m/12) * (w*w + d*d)}" iyz="0.0" izz="${(m/12) * (w*w + h*h)}"/>
</inertial>
</xacro:macro>
<xacro:macro name="cylinder_inertia" params="m r h">
<inertial>
<origin xyz="0 0 0" rpy="${pi/2} 0 0" />
<mass value="${m}"/>
<inertia ixx="${(m/12) * (3*r*r + h*h)}" ixy = "0" ixz = "0" iyy="${(m/12) * (3*r*r + h*h)}" iyz = "0" izz="${(m/2) * (r*r)}"/>
</inertial>
</xacro:macro>
<xacro:macro name="sphere_inertia" params="m r">
<inertial>
<mass value="${m}"/>
<inertia ixx="${(2/5) * m * (r*r)}" ixy="0.0" ixz="0.0" iyy="${(2/5) * m * (r*r)}" iyz="0.0" izz="${(2/5) * m * (r*r)}"/>
</inertial>
</xacro:macro>
<!-- Robot Base -->
<link name="base_link">
<visual>
<origin xyz="0 0 ${base_height/2}" rpy="0 0 0"/>
<geometry>
<box size="${base_length} ${base_width} ${base_height}"/>
</geometry>
<material name="Cyan">
<color rgba="0 1.0 1.0 1.0"/>
</material>
</visual>
<collision>
<origin xyz="0 0 ${base_height/2}" rpy="0 0 0"/>
<geometry>
<box size="${base_length} ${base_width} ${base_height}"/>
</geometry>
</collision>
<xacro:box_inertia m="5" w="${base_width}" d="${base_length}" h="${base_height}"/>
</link>
<gazebo reference="base_link">
<material>Gazebo/Orange</material>
</gazebo>
<!-- Caster Wheel -->
<link name="caster">
<visual>
<geometry>
<sphere radius="${wheel_zoff}"/>
</geometry>
<material name="white">
<color rgba="1 1.0 1.0 1.0"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<sphere radius="${wheel_zoff}"/>
</geometry>
</collision>
<xacro:sphere_inertia m="0.5" r="${(wheel_radius+wheel_zoff-(base_height/2))}"/>
</link>
<gazebo reference="caster">
<material>Gazebo/Blue</material>
</gazebo>
<joint name="caster_joint" type="fixed">
<parent link="base_link"/>
<child link="caster"/>
<origin xyz="${-caster_xoff} 0.0 0" rpy="0 0 0"/>
</joint>
<!-- Wheels -->
<xacro:macro name="wheel" params="prefix x_reflect y_reflect">
<link name="${prefix}_link">
<visual>
<origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
<geometry>
<cylinder radius="${wheel_radius}" length="${wheel_width}"/>
</geometry>
<material name="Gray">
<color rgba="0.5 0.5 0.5 1.0"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
<geometry>
<cylinder radius="${wheel_radius}" length="${wheel_width}"/>
</geometry>
</collision>
<xacro:cylinder_inertia m="0.5" r="${wheel_radius}" h="${wheel_width}"/>
</link>
<joint name="${prefix}_joint" type="continuous">
<parent link="base_link"/>
<child link="${prefix}_link"/>
<origin xyz="${-x_reflect*wheel_xoff} ${y_reflect*(base_width/2+wheel_ygap)} ${wheel_radius-wheel_zoff}" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</xacro:macro>
<xacro:wheel prefix="drivewhl_l" x_reflect="-1" y_reflect="1" />
<xacro:wheel prefix="drivewhl_r" x_reflect="-1" y_reflect="-1" />
</robot>
$ ros2 launch urdf_tutorial display.launch.py model:=my_robot.urdf
이때 rviz 디렉터리에 RViz 설정 파일인 'config.rviz'
파일을 만들자.
상단의 RViz 창에서 File 에 들어가서 Save Config As 를 통해 rviz 디렉터리에 'config.rviz'
로 저장하면 된다.
2. Launch
간단한 launch 파일 두 개를 작성해보자.
2.1. display.launch.py
모델을 RViz를 통해서 확인할 수 있도록 한 런치파일을 작성해보자.
2.2. gazebo.launch.py
Reference
- https://github.com/aarsht7/teleop_cpp_ros2/blob/main/README.md