Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CustomRobots/pick_place_harmonic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Pick Place Harmonic - CustomRobots Directory

This directory contains resources for the Pick and Place Harmonic exercise using Gazebo Harmonic.

## Structure

- **launch/**: Launch files for the exercise
- **models/**: Symbolic link to warehouse models from robotiq_description
- **urdf/**: Symbolic link to URDF files from ur5_gripper_description

## Main Launch File

The main launcher is located in `/RoboticsInfrastructure/Launchers/pick_place_harmonic.launch.py`

This launcher wraps the `spawn_robot_warehouse.launch.py` from the `ur5_gripper_description` package,
which is part of the `pick_place_harmonic_exercise` in IndustrialRobots.

## Package Dependencies

The exercise depends on packages from:
`/home/dev_ws/src/IndustrialRobots/pick_place_harmonic_exercise/`

These must be built with colcon before the exercise can run.
43 changes: 43 additions & 0 deletions Launchers/pick_place_harmonic.launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Pick Place Harmonic - Main World Launcher
Wraps the spawn_robot_warehouse.launch.py from ur5_gripper_description package
Academy launches this with launch_rviz=false
"""

import os
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
# Get package directory
try:
ur5_gripper_pkg = get_package_share_directory('ur5_gripper_description')
except Exception as e:
print(f"ERROR: Cannot find ur5_gripper_description package: {e}")
print("Make sure packages are built in /home/ws")
raise

# Path to spawn_robot_warehouse launch file
warehouse_launch_file = os.path.join(
ur5_gripper_pkg,
'launch',
'spawn_robot_warehouse.launch.py'
)

print(f"Including launch file: {warehouse_launch_file}")

# Include the warehouse launch with launch_rviz=false (Academy launches RViz separately)
warehouse_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(warehouse_launch_file),
launch_arguments={
'launch_rviz': 'false', # Academy launches RViz separately
}.items()
)

return LaunchDescription([
warehouse_launch,
])
131 changes: 131 additions & 0 deletions Launchers/pick_place_harmonic_rviz.launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""
Pick Place Harmonic - RViz + MoveIt Launcher
Launches ONLY: MoveIt move_group + RViz with motion planning
Assumes Gazebo and robot are already running
"""

import os
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import TimerAction
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
# Get package directories
pkg_share_dir = get_package_share_directory("ur5_gripper_description")
moveit_config_package = "ur5_gripper_moveit_config"
moveit_pkg_share = get_package_share_directory(moveit_config_package)

# Robot description (must match what's in Gazebo)
import xacro
xacro_file = os.path.join(pkg_share_dir, "urdf", "ur5_robotiq85_gripper.urdf.xacro")
controllers_file = os.path.join(pkg_share_dir, "config", "ur5_controllers.yaml")

robot_description_content = xacro.process_file(
xacro_file,
mappings={
"ur_type": "ur5",
"name": "ur",
"prefix": "",
"use_fake_hardware": "false",
"sim_gazebo": "false",
"sim_gz": "true",
"simulation_controllers": controllers_file,
}
).toxml()

robot_description = {"robot_description": robot_description_content}

# SRDF
srdf_file = os.path.join(moveit_pkg_share, "srdf", "ur5_robotiq.srdf")
with open(srdf_file, 'r') as file:
robot_description_semantic = {"robot_description_semantic": file.read()}

# Kinematics
kinematics_yaml = os.path.join(moveit_pkg_share, "config", "kinematics.yaml")

# OMPL planning
ompl_planning_yaml = os.path.join(moveit_pkg_share, "config", "ompl_planning.yaml")

# MoveIt controllers
moveit_controllers = os.path.join(moveit_pkg_share, "config", "controllers.yaml")

# Planning pipeline
planning_pipelines_config = {
"planning_pipelines": ["ompl"],
"default_planning_pipeline": "ompl",
"ompl": {
"planning_plugin": "ompl_interface/OMPLPlanner",
"request_adapters": "default_planner_request_adapters/AddTimeOptimalParameterization default_planner_request_adapters/ResolveConstraintFrames default_planner_request_adapters/FixWorkspaceBounds default_planner_request_adapters/FixStartStateBounds default_planner_request_adapters/FixStartStateCollision default_planner_request_adapters/FixStartStatePathConstraints",
"start_state_max_bounds_error": 0.1,
}
}

# Trajectory execution
trajectory_execution = {
"moveit_manage_controllers": True,
"trajectory_execution.allowed_execution_duration_scaling": 1.2,
"trajectory_execution.allowed_goal_duration_margin": 0.5,
"trajectory_execution.allowed_start_tolerance": 0.01,
}

planning_scene_monitor_parameters = {
"publish_planning_scene": True,
"publish_geometry_updates": True,
"publish_state_updates": True,
"publish_transforms_updates": True,
}

# MoveIt move_group node
move_group_node = Node(
package="moveit_ros_move_group",
executable="move_group",
output="screen",
parameters=[
robot_description,
robot_description_semantic,
kinematics_yaml,
ompl_planning_yaml,
planning_pipelines_config,
trajectory_execution,
moveit_controllers,
planning_scene_monitor_parameters,
{"use_sim_time": True},
],
)

# RViz with MoveIt configuration
rviz_config_file = os.path.join(moveit_pkg_share, "rviz", "moveit.rviz")

rviz_node = Node(
package="rviz2",
executable="rviz2",
name="rviz2",
output="log",
arguments=["-d", rviz_config_file],
parameters=[
robot_description,
robot_description_semantic,
ompl_planning_yaml,
kinematics_yaml,
{"use_sim_time": True},
],
)

# Delay MoveIt slightly to let controllers stabilize
delay_move_group = TimerAction(
period=2.0,
actions=[move_group_node],
)

# Delay RViz after MoveIt
delay_rviz = TimerAction(
period=3.0,
actions=[rviz_node],
)

return LaunchDescription([
delay_move_group,
delay_rviz,
])
4 changes: 3 additions & 1 deletion database/universes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ COPY public.universes (id, name, world_id, robot_id) FROM stdin;
52 Montreal Circuit Classic 52 0
53 Nurburgring Circuit Classic 53 0
54 Vacuums House Roof Classic 54 0
55 Pick And Place Harmonic World 55 0
\.


Expand Down Expand Up @@ -243,6 +244,7 @@ COPY public.worlds (id, name, launch_file_path, tools_config, ros_version, type,
52 Montreal Circuit Classic /opt/jderobot/Launchers/montreal_circuit_classic.launch.py None ROS2 gazebo {0.0,0.0,0.0,0.0,0.0,0.0}
53 Nurburgring Circuit Classic /opt/jderobot/Launchers/nurburgring_circuit_classic.launch.py None ROS2 gazebo {0.0,0.0,0.0,0.0,0.0,0.0}
54 Vacuums House Roof Classic /opt/jderobot/Launchers/montecarlo_visual_loc_classic.launch.py None ROS2 gazebo {0.0,0.0,0.0,0.0,0.0,0.0}
55 Pick And Place Harmonic /opt/jderobot/Launchers/pick_place_harmonic.launch.py {"rviz":"/opt/jderobot/Launchers/pick_place_harmonic_rviz.launch.py"} ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
\.

--
Expand Down Expand Up @@ -311,4 +313,4 @@ CREATE INDEX exercises_universe_name_459df99a_like ON public.universes USING btr

--
-- PostgreSQL database dump complete
--
---- Updated Wed Jan 28 12:24:20 AM IST 2026
23 changes: 23 additions & 0 deletions scripts/.env
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There must be no changes in this file

Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,26 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu/gazebo-11/plug

# Default rendering display
export DISPLAY=:0

# === Pick Place Harmonic - Gazebo Harmonic Environment === #
export GZ_VERSION=harmonic

# gz_ros2_control plugin paths - CRITICAL for controller loading
export GZ_SIM_SYSTEM_PLUGIN_PATH="/opt/ros/humble/lib:${GZ_SIM_SYSTEM_PLUGIN_PATH}"

# Gazebo Harmonic resource paths for robot models
# CRITICAL: Use BOTH install/share (parent of package name) AND source directories
# Source directories are needed because that's where meshes actually are during development
export GZ_SIM_RESOURCE_PATH="/home/dev_ws/install/ur5_gripper_description/share:/home/dev_ws/install/robotiq_description/share:/home/dev_ws/src/IndustrialRobots/pick_place_harmonic_exercise/ur5_gripper_description:/home/dev_ws/src/IndustrialRobots/pick_place_harmonic_exercise/robotiq_description:${GZ_SIM_RESOURCE_PATH}"

# Library paths for gz_ros2_control
export LD_LIBRARY_PATH="/opt/ros/humble/lib:${LD_LIBRARY_PATH}"

# === Pick Place Harmonic - gz_ros2_control for Gazebo Harmonic === #
GZ_CTRL=/opt/jderobot/IndustrialRobots/pick_place_harmonic_exercise/gz_ros2_control/install
if [ -d $GZ_CTRL ]; then
source $GZ_CTRL/setup.bash 2>/dev/null || true
export GZ_SIM_SYSTEM_PLUGIN_PATH=$GZ_CTRL/gz_ros2_control/lib:/opt/ros/humble/lib:$GZ_SIM_SYSTEM_PLUGIN_PATH
export GZ_SIM_RESOURCE_PATH=/home/ws/install/ur5_gripper_description/share:/home/ws/install/robotiq_description/share:$GZ_SIM_RESOURCE_PATH
export LD_LIBRARY_PATH=$GZ_CTRL/gz_ros2_control/lib:/opt/ros/humble/lib:$LD_LIBRARY_PATH
fi