이전과 마찬가지로 전체 코드는 https://github.com/hwjeon0123/robot-arm-study/ 를 참고한다.
기존 ur_ws 환경과 새 코드를 분리하기 위해 robot-arm-study 워크스페이스를 생성하고 오버레이 환경을 구성한다.
-v "${UR_WS}:/home/${CTR_USERNAME}/ur_ws:rw,z"
-v "${ARM_WS}:/home/${CTR_USERNAME}/robot-arm-study:rw,z"
.bashrc)RUN echo '[ -f ~/ur_ws/install/setup.bash ] && source ~/ur_ws/install/setup.bash' >> /home/$USERNAME/.bashrc && \
echo '[ -f ~/robot-arm-study/install/setup.bash ] && source ~/robot-arm-study/install/setup.bash' >> /home/$USERNAME/.bashrc
jazzy → ur_ws(underlay) → robot-arm-study(overlay) 순서로 덮어씌운다. -f 옵션으로 빌드 결과물이 존재할 때만 소싱되도록 처리했다.
ROS 2 매니퓰레이터 패키지 관례에 따라 형상(Description)과 실행(Bringup)을 분리하여 생성한다.
arm_description: 로봇 모델 형상 정의 (xacro/URDF). 시뮬레이션 및 실물 환경에서 재사용.arm_bringup: 실행 구성 (launch, config yaml). 시나리오별로 분리.mkdir -p ~/robot-arm-study/src
cd ~/robot-arm-study/src
ros2 pkg create arm_description --build-type ament_cmake --dependencies xacro ur_description
ros2 pkg create arm_bringup --build-type ament_cmake --dependencies arm_description robot_state_publisher ros_gz_sim xacro
두 패키지 모두 실행 노드가 아닌 리소스 파일 설치가 목적이므로 --build-type ament_cmake를 사용한다.
패키지 생성 때 의존성 패키지를 지정하면 src/package.xml파일에 추가된다. 각 패키지의 패키지 의존성에 대한 내용은 아래와 같다.
ur_description의 매크로를 가져와 최상위 ur5e.urdf.xacro를 작성한다.
~/robot-arm-study/src/arm_description/urdf/ur5e.urdf.xacro
<?xml version="1.0"?>
<robot xmlns:xacro="http://wiki.ros.org/xacro" name="ur5e">
<xacro:arg name="name" default="ur5e"/>
<xacro:arg name="ur_type" default="ur5e"/>
<xacro:arg name="tf_prefix" default=""/>
<xacro:include filename="$(find ur_description)/urdf/ur_macro.xacro"/>
<xacro:arg name="joint_limit_params" default="$(find ur_description)/config/$(arg ur_type)/joint_limits.yaml"/>
<xacro:arg name="kinematics_params" default="$(find ur_description)/config/$(arg ur_type)/default_kinematics.yaml"/>
<xacro:arg name="physical_params" default="$(find ur_description)/config/$(arg ur_type)/physical_parameters.yaml"/>
<xacro:arg name="visual_params" default="$(find ur_description)/config/$(arg ur_type)/visual_parameters.yaml"/>
<!-- Gazebo 고정 기준 링크 -->
<link name="world"/>
<xacro:ur_robot
name="$(arg name)"
tf_prefix="$(arg tf_prefix)"
parent="world"
joint_limits_parameters_file="$(arg joint_limit_params)"
kinematics_parameters_file="$(arg kinematics_params)"
physical_parameters_file="$(arg physical_params)"
visual_parameters_file="$(arg visual_params)"
force_abs_paths="true">
<origin xyz="0 0 0" rpy="0 0 0"/>
</xacro:ur_robot>
</robot>
parent="world": Gazebo 환경에서 로봇 베이스를 바닥에 고정(fixed joint)하기 위해 추가.force_abs_paths="true": Gazebo가 메시 파일을 정상적으로 로드하도록 절대 경로(file:///) 출력을 강제함.작성 후 CMakeLists.txt에 install(DIRECTORY urdf DESTINATION share/${PROJECT_NAME}) 규칙을 추가하고, check_urdf 명령으로 파싱 결과를 검증한다.
컨트롤러 태그를 분리하여 arm_study.ros2_control.xacro를 생성하고, 최상위 URDF 파일에서 include 한다.
<?xml version="1.0"?>
<robot xmlns:xacro="http://wiki.ros.org/xacro">
<xacro:arg name="controllers_yaml" default=""/>
<xacro:include filename="$(find ur_description)/urdf/inc/ur_joint_control.xacro"/>
<ros2_control name="$(arg name)" type="system">
<hardware>
<plugin>gz_ros2_control/GazeboSimSystem</plugin>
</hardware>
<xacro:ur_joint_control_description tf_prefix="$(arg tf_prefix)"/>
</ros2_control>
<gazebo>
<plugin filename="gz_ros2_control-system" name="gz_ros2_control::GazeboSimROS2ControlPlugin">
<parameters>$(arg controllers_yaml)</parameters>
</plugin>
</gazebo>
</robot>
arm_bringup/config 디렉토리에 arm_controllers.yaml을 생성하여 joint_state_broadcaster와 joint_trajectory_controller를 정의한다. 궤적 컨트롤러의 joints 목록은 ur_joint_control.xacro에 정의된 관절 이름과 동일해야 한다.
arm_bringup/launch 디렉토리에 arm_study_bringup.launch.py를 만들고 다음 구성 요소를 포함한다:
1. xacro 실행 결과 파싱: robot_description_content를 xacro를 이용해서 생성하고 파싱할 때 yaml 파일로 가정하지 않고 단순 문자열로 취급하도록(ParameterValue(..., value_type=str))하여 'Unable to parse the value of parameter robot_description as yaml. 문제를 회피
2. robot_state_publisher 노드 실행: use_sim_time 매개 변수를 true로 설정
3. ros_gz_sim 패키지에서 제공하는 기본 런치 파일(gz_sim.launch.py)을 이용하여 Gazebo 실행
4. ros_gz_sim 패키지의 create 실행 파일을 이용하여 앞서 생성한 robot_description_content를 읽어서 로봇팔이 생성되도록 노드를 실행한다.
5. controller_manager 패키지의 spawner를 실행하여 joint_state_broadcaster(로봇 관절 각도를 보고)와 joint_trajectory_controller(궤적 명령을 받아서 관절 제어) 제어기를 로드한다.
런치 실행 후 ros2 control list_controllers를 통해 2개의 컨트롤러가 active 상태인지 확인한다.
경로를 계획하고 생성하는 MoveIt이 제어기(Gazebo/ros2_control)로 제어 명령을 전달할 수 있도록 Action 통신 채널을 설정하는 과정이다.
참고할 소스:
~/ur_ws/src/ur_driver/ur_moveit_config/config/moveit_controllers.yaml
MoveIt 연동을 위한 런치 파일 작성 및 노드 실행을 위해, arm_bringup 패키지의 package.xml에 다음 의존성을 추가해야 한다.
<depend>moveit_configs_utils</depend>
<depend>ament_index_python</depend>
<depend>moveit_ros_move_group</depend>
• moveit_configs_utils: 복잡한 MoveIt 파라미터를 조립해 주는 MoveItConfigsBuilder 모듈 사용
• ament_index_python: 런치 파일 내에서 타 패키지의 절대 경로를 찾기 위한 get_package_share_directory 함수 사용
• moveit_ros_move_group: 최종적으로 구동할 move_group 노드 패키지
arm_study.srdf.xacro: ur_moveit_config의 기본 ur_macro.srdf.xacro를 가져와서 기존 로봇의 SRDF 설정을 그대로 사용한다.moveit_controllers.yaml: MoveIt 내부에서 궤적 데이터를 던질 Action Client의 정보를 명세한다. Gazebo의 joint_trajectory_controller로 정의한다.MoveItConfigsBuilder를 활용하여 move_group.launch.py를 구성한다. 의존성 파일들의 위치가 각기 다르므로 패키지 기준점을 명확히 지정한다.
arm_description_share = Path(get_package_share_directory("arm_description"))
ur_moveit_config_share = Path(get_package_share_directory("ur_moveit_config"))
moveit_config = (
MoveItConfigsBuilder(robot_name="ur5e", package_name="arm_bringup")
.robot_description_semantic(
arm_description_share / "srdf" / "arm_study.srdf.xacro", {"name": "ur5e"},
)
.robot_description_kinematics(ur_moveit_config_share / "config" / "kinematics.yaml")
.joint_limits(ur_moveit_config_share / "config" / "joint_limits.yaml")
.planning_pipelines(pipelines=["ompl"])
.trajectory_execution()
.to_moveit_configs()
)
MoveItConfigsBuilder에 URDF 경로를 지정하지 않으면, move_group 노드는 자동으로 /robot_description 토픽을 구독하여 값을 채운다.trajectory_execution(): 파일 경로를 명시하지 않으면 arm_bringup/config 디렉토리 내의 moveit_controllers.yaml을 자동 탐색한다.이전과 마찬가지로 전체 코드는 https://github.com/hwjeon0123/robot-arm-study/ 를 참고한다.
터미널 2개를 열어 구축한 하위 계층(Gazebo)과 상위 계층(MoveIt 2)을 차례로 기동하여 연동을 확인한다. (하위 제어기가 켜지기 전에 MoveIt을 먼저 실행하면 통신 대상을 찾지 못해 에러가 발생한다.)
vglrun ros2 launch arm_bringup arm_study_bringup.launch.py
vglrun ros2 launch arm_bringup move_group.launch.py
(vglrun은 앞의 글에서 언급했듯이 컨테이너에서 3차원 가속을 사용하기 위해 설치해 둔 VirtualGL을 사용하기 위해 추가하였다)
터미널 로그에 [move_group-1] You can start planning now! 메시지가 출력된다.