Pilz manipulator PRBT 6
This guide provides instructions on how to set up Pilz manipulators PRBT 6 using ros2_canopen. Before following this guide, make sure to refer to the user guide to Configuration Package, How to create a configuration package and How to create a robot system with ros2_control. Additionally, this guide is based on: pilz_robots.
To configure the PRBT 6 using ros2_canopen, please refer to the pre-existing configuration in the pilz_robot package.
Package creation and setup
Create a new configuration package for the robot with the name
prbt_robot_support
.$ ros2 pkg create --dependencies ros2_canopen lely_core_libraries --build-type ament_cmake prbt_robot_support $ cd prbt_robot_support $ rm -rf src $ rm -rf include $ mkdir -p launch $ mkdir -p config $ mkdir -p urdf $ touch config/prbt_ros2_control.yaml
Create a new bus configuration folder with name
prbt
. And createbus.yml
and copyprbt_0_1.dcf
from pilz_support package.Now the package structure should look like this:
prbt_robot_support ├── config │ ├── prbt │ | ├── bus.yml │ | └── prbt_0_1.dcf │ └── prbt_ros2_control.yaml ├── launch ├── urdf ├── CMakeLists.txt └── package.xml
Add the following to the
bus.yml
options: dcf_path: "@BUS_CONFIG_PATH@" master: node_id: 1 driver: "ros2_canopen::MasterDriver" package: "canopen_master_driver" sync_period: 10000 defaults: dcf: "prbt_0_1.dcf" driver: "ros2_canopen::Cia402Driver" package: "canopen_402_driver" period: 10 heartbeat_producer: 1000 switching_state: 2 position_mode: 7 scale_pos_from_dev: 0.00001745329252 scale_pos_to_dev: 57295.7795131 sdo: - {index: 0x6081, sub_index: 0, value: 1000} - {index: 0x60C2, sub_index: 1, value: 10} # Interpolation time period at 10 ms matches the period. tpdo: # TPDO needed statusword, actual velocity, actual position, mode of operation 1: enabled: true cob_id: "auto" transmission: 0x01 mapping: - {index: 0x6041, sub_index: 0} # status word - {index: 0x6061, sub_index: 0} # mode of operation display 2: enabled: true cob_id: "auto" transmission: 0x01 mapping: - {index: 0x6064, sub_index: 0} # position actual value - {index: 0x606c, sub_index: 0} # velocity actual position 3: enabled: false 4: enabled: false rpdo: # RPDO needed controlword, target position, target velocity, mode of operation 1: enabled: true cob_id: "auto" mapping: - {index: 0x6040, sub_index: 0} # controlword - {index: 0x6060, sub_index: 0} # mode of operation - {index: 0x60C1, sub_index: 1} # interpolated position data 2: enabled: true cob_id: "auto" mapping: - {index: 0x607A, sub_index: 0} # target position nodes: prbt_joint_1: node_id: 3 prbt_joint_2: node_id: 4 prbt_joint_3: node_id: 5 prbt_joint_4: node_id: 6 prbt_joint_5: node_id: 7 prbt_joint_6: node_id: 8
Create
prbt.ros2_control.xacro
file inurdf
folder and add the following to the file:<?xml version="1.0"?> <robot xmlns:xacro="http://www.ros.org/wiki/xacro"> <xacro:macro name="prbt_ros2_control" params=" name prefix bus_config master_config can_interface_name master_bin"> <ros2_control name="${name}" type="system"> <hardware> <plugin>canopen_ros2_control/RobotSystem</plugin> <param name="bus_config">${bus_config}</param> <param name="master_config">${master_config}</param> <param name="can_interface_name">${can_interface_name}</param> <param name="master_bin">"${master_bin}"</param> </hardware> <joint name="${prefix}joint_1"> <param name="device_name">prbt_joint_1</param> </joint> <joint name="${prefix}joint_2"> <param name="device_name">prbt_joint_2</param> </joint> <joint name="${prefix}joint_3"> <param name="device_name">prbt_joint_3</param> </joint> <joint name="${prefix}joint_4"> <param name="device_name">prbt_joint_4</param> </joint> <joint name="${prefix}joint_5"> <param name="device_name">prbt_joint_5</param> </joint> <joint name="${prefix}joint_6"> <param name="device_name">prbt_joint_6</param> </joint> </ros2_control> </xacro:macro> </robot>
Add the following to the
prbt_ros2_control.yaml
file:controller_manager: ros__parameters: update_rate: 100 # Hz joint_state_broadcaster: type: joint_state_broadcaster/JointStateBroadcaster arm_controller: type: joint_trajectory_controller/JointTrajectoryController arm_controller: ros__parameters: joints: - prbt_joint_1 - prbt_joint_2 - prbt_joint_3 - prbt_joint_4 - prbt_joint_5 - prbt_joint_6 command_interfaces: - position state_interfaces: - position - velocity stop_trajectory_duration: 0.2 state_publish_rate: 100.0 action_monitor_rate: 25.0 goal_time: 0.0 limits: prbt_joint_1: has_acceleration_limits: true max_acceleration: 6.0 prbt_joint_2: has_acceleration_limits: true max_acceleration: 6.0 prbt_joint_3: has_acceleration_limits: true max_acceleration: 6.0 prbt_joint_4: has_acceleration_limits: true max_acceleration: 6.0 prbt_joint_5: has_acceleration_limits: true max_acceleration: 6.0 prbt_joint_6: has_acceleration_limits: true max_acceleration: 6.0
Create a launch file with name
robot.launch.py
in the launch directory of your package. Follow the instructions How to create a robot system with ros2_control to complete the launch file. The launch file should look like this:import os from ament_index_python import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument from launch.substitutions import Command, FindExecutable, LaunchConfiguration, PathJoinSubstitution from launch_ros.actions import Node from launch_ros.substitutions import FindPackageShare from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource import launch_ros def generate_launch_description(): declared_arguments = [] declared_arguments.append( DeclareLaunchArgument( "description_package", description="Package where urdf file is stored.", default_value="prbt_robot_support" ) ) declared_arguments.append( DeclareLaunchArgument( "can_interface_name", default_value="vcan0", description="Interface name for can", ) ) declared_arguments.append( DeclareLaunchArgument( "use_ros2_control", default_value="true", description="Use ros2_control", ) ) controller_config = PathJoinSubstitution([FindPackageShare("prbt_robot_support"), "config", "prbt_ros2_control.yaml"]) bus_config = PathJoinSubstitution([FindPackageShare("prbt_robot_support"), "config", "prbt", "bus.yml"]) master_config = PathJoinSubstitution([FindPackageShare("prbt_robot_support"), "config", "prbt", "master.dcf"]) can_interface_name = LaunchConfiguration("can_interface_name") master_bin_path = os.path.join( get_package_share_directory("prbt_robot_support"), "config", "prbt", "master.bin", ) if not os.path.exists(master_bin_path): master_bin_path = "" robot_description_content = Command( [ PathJoinSubstitution([FindExecutable(name="xacro")]), " ", PathJoinSubstitution([FindPackageShare(LaunchConfiguration("description_package")), "urdf", "prbt.xacro"]), " ", "bus_config:=", bus_config, " ", "master_config:=", master_config, " ", "master_bin:=", master_bin_path, " ", "can_interface_name:=", can_interface_name, ] ) robot_description = {"robot_description": launch_ros.descriptions.ParameterValue(robot_description_content, value_type=str)} robot_state_publisher_node = Node( package="robot_state_publisher", executable="robot_state_publisher", output="both", parameters=[robot_description], ) # Controller manager controller_manager_node = Node( package="controller_manager", executable="ros2_control_node", output="both", parameters=[robot_description, controller_config], ) joint_state_broadcaster_spawner = Node( package="controller_manager", executable="spawner", arguments=["joint_state_broadcaster", "--controller-manager", "/controller_manager"], ) arm_controller_spawner = Node( package="controller_manager", executable="spawner", arguments=["arm_controller", "--controller-manager", "/controller_manager"], ) nodes_list = [ robot_state_publisher_node, controller_manager_node, joint_state_broadcaster_spawner, arm_controller_spawner, ] return LaunchDescription(declared_arguments + nodes_list)
Edit the CMakeLists.txt file of your package and add the following lines after the find_package section.
cogen_dcf(prbt) install(DIRECTORY launch urdf meshes DESTINATION share/${PROJECT_NAME}) install(FILES config/prbt_ros2_control.yaml DESTINATION share/${PROJECT_NAME}/config)
Build your package and source the setup file.
MoveIt2 setup
Follow the MoveIt Setup Assistance tutorial and create the MoveIt2 package for your robot. The MoveIt2 package should be created in the same workspace as your robot package.
Update
moveit_controller.yaml
file in the config directory of your MoveIt2 package. The file should look like this:# MoveIt uses this configuration for controller management trajectory_execution: allowed_execution_duration_scaling: 1.2 allowed_goal_duration_margin: 0.5 allowed_start_tolerance: 0.01 moveit_controller_manager: moveit_simple_controller_manager/MoveItSimpleControllerManager moveit_simple_controller_manager: controller_names: - arm_controller arm_controller: type: FollowJointTrajectory action_ns: follow_joint_trajectory default: True joints: - prbt_joint_1 - prbt_joint_2 - prbt_joint_3 - prbt_joint_4 - prbt_joint_5 - prbt_joint_6
Create a launch file
moveit_planning_execution.launch.py
to launch moveit and robot components.from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription from launch.substitutions import LaunchConfiguration, PathJoinSubstitution from launch_ros.substitutions import FindPackageShare from launch.actions import IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.actions import TimerAction from moveit_configs_utils import MoveItConfigsBuilder def generate_launch_description(): moveit_config = MoveItConfigsBuilder( "prbt", package_name="prbt_robot_moveit_config" ).to_moveit_configs() declared_arguments = [] declared_arguments.append( DeclareLaunchArgument( "can_interface_name", default_value="can0", description="Interface name for can", ) ) robot_hw_node = IncludeLaunchDescription( PythonLaunchDescriptionSource( [PathJoinSubstitution([FindPackageShare("prbt_robot_support"), "launch", "robot.launch.py"])], ), launch_arguments={ "can_interface_name": LaunchConfiguration("can_interface_name"), }.items(), ) virtual_joints = IncludeLaunchDescription( PythonLaunchDescriptionSource( str( moveit_config.package_path / "launch/static_virtual_joint_tfs.launch.py" ) ), ) move_group = IncludeLaunchDescription( PythonLaunchDescriptionSource( str(moveit_config.package_path / "launch/move_group.launch.py") ), ) rviz = IncludeLaunchDescription( PythonLaunchDescriptionSource( str(moveit_config.package_path / "launch/moveit_rviz.launch.py") ), ) node_list = [ robot_hw_node, virtual_joints, move_group, rviz, ] return LaunchDescription(declared_arguments + node_list)
Running the PRBT robot
There are two ways to run the demo. First you can use canopen_fake_slave
to simulate the robot using CAN interface vcan0
. Second you can use the real robot.
Refer Setup CAN Controller to configure CAN interface.
# Run the demo using fake robot
ros2 launch prbt_robot_moveit_config moveit_planning_execution.launch.py can_interface_name:=vcan0
# Run the demo using real robot
ros2 launch prbt_robot_moveit_config moveit_planning_execution.launch.py can_interface_name:=can0
Rviz2: