diff --git a/iai_stacy_description/CMakeLists.txt b/iai_stacy_description/CMakeLists.txt new file mode 100644 index 0000000..1a596b7 --- /dev/null +++ b/iai_stacy_description/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.5) +project(iai_stacy_description) + +find_package(ament_cmake REQUIRED) +find_package(xacro REQUIRED) + +install(DIRECTORY launch + DESTINATION share/${PROJECT_NAME}) + +install(DIRECTORY meshes + DESTINATION share/${PROJECT_NAME}) + +install(DIRECTORY urdf + DESTINATION share/${PROJECT_NAME}) + +ament_package() diff --git a/iai_stacy_description/README.md b/iai_stacy_description/README.md new file mode 100644 index 0000000..132cb3d --- /dev/null +++ b/iai_stacy_description/README.md @@ -0,0 +1,36 @@ +# iai_stacy_description + +URDF description and bringup launch files for the Stacy robot at AICOR Institute for Artificial Intelligence, University of Bremen. + +## Network Setup + +To connect to the robot, plug an ethernet cable directly from the robot controller into your PC. +Then configure a static IPv4 interface on that network adapter: + +| Field | Value | +|---------|-----------------| +| IP | 192.168.1.10 | +| Netmask | 255.255.255.0 | +| Gateway | 192.168.1.1 | + +The robot controller is reachable at `192.168.1.2`. + +## Package structure + +The hardware bringup uses a two-URDF pattern required by `ur_robot_driver`: + +- **`urdf/stacy.urdf.xacro`** — plain description used by `display.launch.py` (no ros2_control tag). +- **`urdf/stacy_controlled.urdf.xacro`** — hardware description: same geometry plus the `` hardware interface tag that `ur_control.launch.py` needs. +- **`launch/rsp.launch.py`** — custom robot state publisher launch that processes `stacy_controlled.urdf.xacro`. Passed to `ur_control.launch.py` via the `description_launchfile` argument, overriding the driver's default `ur_rsp.launch.py` so the full robot (column, camera, tool) is published on `/robot_description` instead of just the bare UR5. + +## Launch + +**RViz visualization (no hardware required):** +```bash +ros2 launch iai_stacy_description display.launch.py +``` + +**Real hardware bringup:** +```bash +ros2 launch iai_stacy_description hardware.launch.py +``` diff --git a/iai_stacy_description/launch/display.launch.py b/iai_stacy_description/launch/display.launch.py new file mode 100644 index 0000000..fe65990 --- /dev/null +++ b/iai_stacy_description/launch/display.launch.py @@ -0,0 +1,49 @@ +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.conditions import IfCondition, UnlessCondition +from launch.substitutions import Command, LaunchConfiguration +from launch_ros.actions import Node + + +def generate_launch_description(): + pkg_share = get_package_share_directory('iai_stacy_description') + + urdf_file = os.path.join(pkg_share, 'urdf', 'stacy.urdf.xacro') + + robot_description = Command(['xacro ', urdf_file]) + + return LaunchDescription([ + DeclareLaunchArgument( + 'gui', + default_value='true', + description='Launch joint_state_publisher_gui if true'), + + Node( + package='robot_state_publisher', + executable='robot_state_publisher', + name='robot_state_publisher', + output='screen', + parameters=[{'robot_description': robot_description}]), + + Node( + package='joint_state_publisher_gui', + executable='joint_state_publisher_gui', + name='joint_state_publisher_gui', + output='screen', + condition=IfCondition(LaunchConfiguration('gui'))), + + Node( + package='joint_state_publisher', + executable='joint_state_publisher', + name='joint_state_publisher', + output='screen', + condition=UnlessCondition(LaunchConfiguration('gui'))), + + Node( + package='rviz2', + executable='rviz2', + name='rviz2', + output='screen'), + ]) diff --git a/iai_stacy_description/launch/hardware.launch.py b/iai_stacy_description/launch/hardware.launch.py new file mode 100644 index 0000000..1a1c912 --- /dev/null +++ b/iai_stacy_description/launch/hardware.launch.py @@ -0,0 +1,52 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription +from launch.substitutions import Command, LaunchConfiguration +from launch_ros.actions import Node +from launch.launch_description_sources import PythonLaunchDescriptionSource +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # Launch args for IPs + ip = LaunchConfiguration('robot_ip') + + orbbec_share_dir = get_package_share_directory('orbbec_camera') + launch_dir = os.path.join(orbbec_share_dir, 'launch') + + return LaunchDescription([ + DeclareLaunchArgument('robot_ip', default_value='192.168.1.2'), + IncludeLaunchDescription( + PythonLaunchDescriptionSource([ + os.path.join( + get_package_share_directory('ur_robot_driver'), + 'launch', + 'ur_control.launch.py' + ) + ]), + launch_arguments={ + 'robot_ip': ip, + 'use_fake_hardware': 'false', + 'ur_type': 'ur5', + 'initial_joint_controller': 'forward_velocity_controller', + 'launch_rviz': 'false', + 'description_launchfile': os.path.join( + get_package_share_directory('iai_stacy_description'), + 'launch', + 'rsp.launch.py' + ), + }.items() + ), + IncludeLaunchDescription( + PythonLaunchDescriptionSource( + os.path.join(launch_dir, 'femto_bolt.launch.py') + ), + launch_arguments={ + 'color_width': '1920', + 'color_height': '1080', + 'depth_registration': 'True', + 'enable_colored_point_cloud': 'True', + 'enable_noise_removal_filter': 'True', + 'noise_removal_filter_min_diff': '3' + }.items() + ), + ]) \ No newline at end of file diff --git a/iai_stacy_description/launch/rsp.launch.py b/iai_stacy_description/launch/rsp.launch.py new file mode 100644 index 0000000..0508d60 --- /dev/null +++ b/iai_stacy_description/launch/rsp.launch.py @@ -0,0 +1,49 @@ +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 + + +def generate_launch_description(): + ur_type = LaunchConfiguration('ur_type') + robot_ip = LaunchConfiguration('robot_ip') + kinematics_parameters_file = LaunchConfiguration('kinematics_parameters_file') + use_mock_hardware = LaunchConfiguration('use_mock_hardware') + mock_sensor_commands = LaunchConfiguration('mock_sensor_commands') + headless_mode = LaunchConfiguration('headless_mode') + + robot_description_content = Command([ + PathJoinSubstitution([FindExecutable(name='xacro')]), + ' ', + PathJoinSubstitution([FindPackageShare('iai_stacy_description'), 'urdf', 'stacy_controlled.urdf.xacro']), + ' robot_ip:=', robot_ip, + ' ur_type:=', ur_type, + ' kinematics_parameters_file:=', kinematics_parameters_file, + ' use_mock_hardware:=', use_mock_hardware, + ' mock_sensor_commands:=', mock_sensor_commands, + ' headless_mode:=', headless_mode, + ]) + + return LaunchDescription([ + DeclareLaunchArgument('ur_type', default_value='ur5', + description='UR robot type'), + DeclareLaunchArgument('robot_ip', + description='IP address of the UR robot'), + DeclareLaunchArgument( + 'kinematics_parameters_file', + default_value=PathJoinSubstitution([ + FindPackageShare('ur_description'), 'config', ur_type, 'default_kinematics.yaml' + ]), + description='Kinematics calibration file (use robot-specific file for real hardware)'), + DeclareLaunchArgument('use_mock_hardware', default_value='false', + description='Use mock hardware instead of real robot'), + DeclareLaunchArgument('mock_sensor_commands', default_value='false'), + DeclareLaunchArgument('headless_mode', default_value='false'), + + Node( + package='robot_state_publisher', + executable='robot_state_publisher', + output='both', + parameters=[{'robot_description': robot_description_content}]), + ]) diff --git a/iai_stacy_description/meshes/camera_adapter.stl b/iai_stacy_description/meshes/camera_adapter.stl new file mode 100644 index 0000000..d168e49 Binary files /dev/null and b/iai_stacy_description/meshes/camera_adapter.stl differ diff --git a/iai_stacy_description/meshes/item_robot_column.stl b/iai_stacy_description/meshes/item_robot_column.stl new file mode 100644 index 0000000..6ba06ed Binary files /dev/null and b/iai_stacy_description/meshes/item_robot_column.stl differ diff --git a/iai_stacy_description/package.xml b/iai_stacy_description/package.xml new file mode 100644 index 0000000..f18697c --- /dev/null +++ b/iai_stacy_description/package.xml @@ -0,0 +1,27 @@ + + + iai_stacy_description + 1.0.0 + URDF description and bringup launch files for the Stacy robot at IAI, University of Bremen. + + Malte Huerkamp + + LGPL + + ament_cmake + + xacro + xacro + robot_state_publisher + joint_state_publisher + joint_state_publisher_gui + rviz2 + ur_description + ur_robot_driver + orbbec_description + orbbec_camera + + + ament_cmake + + diff --git a/iai_stacy_description/urdf/stacy.urdf.xacro b/iai_stacy_description/urdf/stacy.urdf.xacro new file mode 100644 index 0000000..f93e750 --- /dev/null +++ b/iai_stacy_description/urdf/stacy.urdf.xacro @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/iai_stacy_description/urdf/stacy_controlled.urdf.xacro b/iai_stacy_description/urdf/stacy_controlled.urdf.xacro new file mode 100644 index 0000000..a1eb8be --- /dev/null +++ b/iai_stacy_description/urdf/stacy_controlled.urdf.xacro @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iai_stacy_description/urdf/stacy_macro.xacro b/iai_stacy_description/urdf/stacy_macro.xacro new file mode 100644 index 0000000..f399896 --- /dev/null +++ b/iai_stacy_description/urdf/stacy_macro.xacro @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +