ROS Melodic · MoveIt · Gazebo

UR3 Robotic Arm — Pick and Place

A fixed-pose baseline and a camera-guided approach that segments a live depth point cloud, classifies what it sees, and sorts it into a box — both running identically against Gazebo or the real UR3.

Demo

The UR3 arm running at the socialab lab.

Four ways to run it

Two independent choices — approach (how the target pose is decided) and environment (what's actually moving the arm) — combine into four launch commands. Environment only changes the bringup; the pick-place logic is identical either way.

SimulationReal robot
Static roslaunch ur3_pick_place static/sim.launch roslaunch ur3_pick_place static/real.launch
Dynamic roslaunch ur3_pick_place dynamic/sim.launch roslaunch ur3_pick_place dynamic/real.launch

† run dynamic/calibrate.launch once per camera mount first.

Approach 1

Static

scripts/static/static_pick_place.py

No perception — the object's location is fixed and known ahead of time. Home → approach → grasp → lift → move to drop pose → release → retreat, driven entirely through MoveIt. The baseline that validates the driver, controller, and planning pipeline before perception is layered on.

Approach 2

Dynamic

scripts/dynamic/*.py
  1. Calibrate — an ArUco board (marker id 582) held by the gripper is moved through known poses to solve the camera → robot transform.
  2. Detect — the workspace cloud is cropped, the table plane removed via RANSAC, the rest clustered per object, and each cluster classified as pen or cutlery by shape.
  3. Sort — each detected object is picked up and dropped into a sorting box.

Architecture

Environment picks the bringup; approach picks the pipeline. Both land on the same MoveIt call.

Environment — pick one:

Simulationbringup_sim.launch
Gazebo + sim camera
Real robotbringup_real.launch
UR driver + RealSense

Dynamic approach:

Once per mountcamera_calibration.py
Per framepointcloud_object_detector.py
/detected_objectsdynamic_pick_place.py
MoveItmove_group → UR3

Static approach is the same tail end, minus the perception stages — static_pick_place.py talks straight to move_group with poses read from config/static/poses.yaml. Neither approach talks to the bringup directly, only to MoveIt and fixed topic names — that's what makes the environment swap invisible to the pick-place logic.

Environments

What each bringup actually starts.

AspectSimulationReal robot
Bringupbringup_sim.launchbringup_real.launch
ArmGazebo + ur_gazeboUniversal_Robots_ROS_Driver
CameraGazebo depth pluginRealSense, relayed to matching topics
Env varsenv/sim.env.shenv/real.env.sh

Repository structure

catkin_ws/src/ur3_pick_place/
├── msg/DetectedObject.msg          # class, pose, size, confidence
├── urdf/depth_camera.urdf.xacro    # overhead depth camera for Gazebo
├── src/ur3_pick_place/
│   └── gripper_interface.py        # shared GripperCommand wrapper
├── env/
│   ├── sim.env.sh
│   └── real.env.sh
├── config/
│   ├── static/poses.yaml
│   └── dynamic/
│       ├── sorting_box.yaml
│       ├── object_classes.yaml
│       ├── aruco_markers.yaml
│       └── camera_extrinsics.yaml
├── launch/
│   ├── common/          # bringup_sim, bringup_real, moveit_planning
│   ├── static/{sim,real}.launch
│   └── dynamic/{calibrate,sim,real}.launch
└── scripts/
    ├── static/static_pick_place.py
    └── dynamic/{camera_calibration,pointcloud_object_detector,dynamic_pick_place}.py

Running it

Ubuntu 18.04 + ROS Melodic. Full setup steps are in the repo README.

Simulation + Static

source env/sim.env.sh
roslaunch ur3_pick_place static/sim.launch

Simulation + Dynamic

source env/sim.env.sh
roslaunch ur3_pick_place dynamic/calibrate.launch   # once per camera mount
roslaunch ur3_pick_place dynamic/sim.launch

Real robot + Static

roslaunch ur_calibration calibration_correction.launch \
  robot_ip:=$UR3_ROBOT_IP target_filename:="$UR3_KINEMATICS_CONFIG"   # once per unit

source env/real.env.sh
roslaunch ur3_pick_place static/real.launch

Real robot + Dynamic

roslaunch ur_calibration calibration_correction.launch \
  robot_ip:=$UR3_ROBOT_IP target_filename:="$UR3_KINEMATICS_CONFIG"   # once per unit

source env/real.env.sh
roslaunch ur3_pick_place dynamic/calibrate.launch   # once per camera mount
roslaunch ur3_pick_place dynamic/real.launch

History

UR3 work at the socialab lab, 2020.

Feb 17
ROS Melodic + Universal_Robots_ROS_Driver installed
Feb 27
UR3 Academy training modules, first driver bring-up
Mar 5
First live joint control via rqt_joint_trajectory_controller
Mar 10–12
MoveIt + RViz planning integration, controller topic testing
Aug 18
ArUco marker targets prepared for camera calibration
Dec 9
Arm recorded running — the demo video above