Skip to content

Commit

Permalink
feat: add Panda joint locker service (#209)
Browse files Browse the repository at this point in the history
This commit adds a Gazebo world plugin that can be used to lock/unlock
specific panda joints. This plugin creates the `lock_unlock_panda_joints`
users can request lock or unlock actions.
  • Loading branch information
rickstaa authored Jan 1, 2024
1 parent 8a78a1a commit b0845a5
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 42 deletions.
24 changes: 14 additions & 10 deletions panda_gazebo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ find_package(catkin REQUIRED COMPONENTS
trajectory_msgs
control_msgs
dynamic_reconfigure
roscpp
gazebo_ros
)

## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
find_package(gazebo REQUIRED)

## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
Expand Down Expand Up @@ -72,6 +74,7 @@ add_service_files(
GetEeRpy.srv
GetRandomEePose.srv
GetRandomJointPositions.srv
LockJoints.srv
SetEePose.srv
SetGripperWidth.srv
SetJointCommands.srv
Expand Down Expand Up @@ -132,25 +135,28 @@ catkin_package(
CATKIN_DEPENDS
message_runtime rospy gazebo_msgs std_msgs controller_manager_msgs
geometry_msgs actionlib_msgs trajectory_msgs sensor_msgs control_msgs rviz actionlib
franka_description franka_gazebo panda_moveit_config
# DEPENDS system_lib
franka_description franka_gazebo panda_moveit_config gazebo_ros
DEPENDS
gazebo
)

###########
## Build ##
###########

# Link to gazebo libraries
link_directories(${GAZEBO_LIBRARY_DIRS})

## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${Boost_INCLUDE_DIR}
${catkin_INCLUDE_DIRS}
${GAZEBO_INCLUDE_DIRS}
)

## Declare a C++ library
# add_library(${PROJECT_NAME}
# src/${PROJECT_NAME}/panda_gazebo.cpp
# )
add_library(${PROJECT_NAME} src/panda_joint_locker_world_plugin.cpp)

## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
Expand All @@ -173,9 +179,7 @@ include_directories(
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
# ${catkin_LIBRARIES}
# )
target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES} ${GAZEBO_LIBRARIES})

#############
## Install ##
Expand Down
88 changes: 57 additions & 31 deletions panda_gazebo/docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,61 @@ Welcome to panda-gazebo documentation
Welcome to the API documentation for the :panda-gazebo:`panda_gazebo <>` package. This package
contains all the ROS packages needed for creating a `Panda Emika Franka`_ Gazebo simulation. It
is used by the :ros-gazebo-gym:`ros_gazebo_gym <>` RL framework to create the Panda task environments.
It wraps the `franka_ros`_ and `panda_moveit_config`_ packages to add the
functionalities needed to train RL agents efficiently.
It wraps the `franka_ros`_ package to add the functionalities needed to train RL agents efficiently.

The :panda-gazebo:`panda_gazebo <>` package contains several launch files and ROS nodes that ease the
:ros-gazebo-gym:`ros_gazebo_gym <>` interaction with the `Panda Gazebo simulation`_. These launch files
can spawn the Panda Robot in several distinct task environments (see `the ros_gazebo_gym documentation`_ for
the available environments). The ROS nodes generate several ROS services that make controlling or getting
information from the robot easier:
Package Overview
----------------

The :panda-gazebo:`panda_gazebo <>` package contains several launch files, ROS nodes and a Gazebo plugin that ease the
:ros-gazebo-gym:`ros_gazebo_gym <>` interaction with the `Panda Gazebo simulation`_. The launch files
can spawn the Panda Robot in several distinct task environments. The ROS nodes generate several ROS services that make
controlling or getting information from the robot easier. The Gazebo plugins can lock specific joints of the Panda robot.
It also contains a Gazebo world plugin that can be used to lock specific joints of the Panda robot.

Launch files
~~~~~~~~~~~~

- **put_robot_in_world.launch:** Spawns the Panda robot in a given task environment.
- **Start_pick_and_place_world.launch:** Loads the pick and place task environment.
- **Start_push_world.launch:** Loads the push task environment.
- **Start_reach_world.launch:** Loads the reach task environment.
- **Start_slide_world.launch:** Loads the slide task environment.
- **start_simulation.launch:** Loads the Panda robot in a given task environment.

For more information about these task environments see `the ros_gazebo_gym documentation`_.

ROS Nodes
~~~~~~~~~

- **panda_control_server**: Creates services related to the panda_control.
- **get_controlled_joints:** Returns the panda joints that are currently controlled when using a given control type.
- **follow_joint_trajectory:** Sets the arm joint trajectory and the gripper width.
- **set_joint_commands:** Sets an arm command (i.e. position or effort) based on the specified control type.
- **panda_arm/follow_joint_trajectory:** Sets the arm joint trajectory.
- **panda_hand/set_gripper_width:** Sets the gripper width.
- **panda_arm/set_joint_positions:** Sets the arm positions.
- **panda_arm/set_joint_efforts:** Sets the arm efforts.
- ``get_controlled_joints:`` Returns the panda joints that are currently controlled when using a given control type.
- ``follow_joint_trajectory:`` Sets the arm joint trajectory and the gripper width.
- ``set_joint_commands:`` Sets an arm command (i.e. position or effort) based on the specified control type.
- ``panda_arm/follow_joint_trajectory:`` Sets the arm joint trajectory.
- ``panda_hand/set_gripper_width:`` Sets the gripper width.
- ``panda_arm/set_joint_positions:`` Sets the arm positions.
- ``panda_arm/set_joint_efforts:`` Sets the arm efforts.
- **panda_moveit_server:** Creates services to control the robot through `MoveIt!`_.
- **panda_arm/set_ee_pose:** Sets the end-effector pose.
- **get_random_joint_positions**: Returns random valid joint positions.
- **get_random_ee_pose**: Returns a valid random end-effector pose.
- **planning_scene/add_box**: Adds a box to the MoveIt planning scene
- **planning_scene/add_plane**: Adds a plane to the MoveIt planning scene
- **panda_arm/get_ee**: Returns the currently used end-effector link name.
- **panda_arm/set_ee**: Sets the end effector link.
- **panda_arm/get_ee_pose**: Returns the current end-effector pose.
- **panda_arm/get_ee_pose_joint_config**: Returns a set of possible joint configurations for a given end-effector pose.
- **panda_arm/get_ee_rpy**: Returns the current end-effector orientation.
- **set_joint_positions**: Sets the arm and Hand joints positions.
- **get_controlled_joints**: Gets the joints that MoveIt currently controls.
- **panda_arm/set_joint_positions**: Sets the arm joints positions.
- **panda_hand/set_joint_positions**: Sets the hand joints position.

For more information about the messages these services require, see the :ref:`ROS API documentation <ros_api>`. More
information about this package's modules and classes can be found in the :ref:`Python API documentation <python_api>`.
- ``panda_arm/set_ee_pose:`` Sets the end-effector pose.
- ``get_random_joint_positions``: Returns random valid joint positions.
- ``get_random_ee_pose``: Returns a valid random end-effector pose.
- ``planning_scene/add_box``: Adds a box to the MoveIt planning scene
- ``planning_scene/add_plane``: Adds a plane to the MoveIt planning scene
- ``panda_arm/get_ee``: Returns the currently used end-effector link name.
- ``panda_arm/set_ee``: Sets the end effector link.
- ``panda_arm/get_ee_pose``: Returns the current end-effector pose.
- ``panda_arm/get_ee_pose_joint_config``: Returns a set of possible joint configurations for a given end-effector pose.
- ``panda_arm/get_ee_rpy``: Returns the current end-effector orientation.
- ``set_joint_positions``: Sets the arm and Hand joints positions.
- ``get_controlled_joints``: Gets the joints that MoveIt currently controls.
- ``panda_arm/set_joint_positions``: Sets the arm joints positions.
- ``panda_hand/set_joint_positions``: Sets the hand joints position.

Gazebo plugins
~~~~~~~~~~~~~~

- **panda_joint_locker**: Creates a service that can be used to lock/unlock specific joints of the Panda robot.
- ``lock_unlock_panda_joints``: Locks/unlocks the specified joints of the Panda robot.

.. _`Panda Emika Franka`: https://frankaemika.github.io/docs
.. _`gazebo`: https://gazebosim.org
Expand All @@ -53,6 +73,12 @@ information about this package's modules and classes can be found in the :ref:`P
.. _`Panda Gazebo simulation`: https://github.com/frankaemika/franka_ros/tree/develop/franka_gazebo
.. _`MoveIt!`: https://moveit.ros.org

API Documentation
-----------------

More information about this package's modules and classes can be found in the :ref:`Python API documentation <python_api>`. For more
information about the message the services require, see the :ref:`ROS API documentation <ros_api>`.

Contents
========

Expand Down
7 changes: 6 additions & 1 deletion panda_gazebo/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
<build_depend>control_msgs</build_depend>
<build_depend>python3-catkin-pkg</build_depend>
<build_depend>python3-catkin-tools</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>gazebo_ros</build_depend>

<!--Extra build dependencies
NOTE: Disabled by default as they are only needed for some test scripts
Expand Down Expand Up @@ -88,6 +90,7 @@
<exec_depend>effort_controllers</exec_depend>
<exec_depend>joint_trajectory_controller</exec_depend>
<exec_depend>panda_moveit_config</exec_depend>
<exec_depend>roscpp</exec_depend>

<!--Extra run dependencies
NOTE: Disabled by default as they are only needed for some test scripts.
Expand All @@ -98,7 +101,6 @@
<!--Local ROS package dependencies -->
<exec_depend>franka_description</exec_depend>
<exec_depend>franka_gazebo</exec_depend>
<exec_depend>panda_moveit_config</exec_depend>

<!-- Python dependencies -->
<exec_depend>gym-pip</exec_depend>
Expand All @@ -123,5 +125,8 @@
<gazebo_ros gazebo_model_path="${prefix}/resources/models"/>
<gazebo_ros gazebo_media_path="${prefix}/resources/models"/>
<gazebo_ros gazebo_resource_path="${prefix}/resources"/>

<!--Export gazebo plugin-->
<gazebo_ros plugin_path="${prefix}/../../lib"/>
</export>
</package>
2 changes: 2 additions & 0 deletions panda_gazebo/resources/worlds/empty.world
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
<projection_type>perspective</projection_type>
</camera>
</gui>
<!--Load Panda joint fixer Gazebo world plugin-->
<plugin name="panda_joint_locker" filename="libpanda_gazebo.so"/>
</world>
</sdf>
2 changes: 2 additions & 0 deletions panda_gazebo/resources/worlds/pick_and_place.world
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@
<projection_type>perspective</projection_type>
</camera>
</gui>
<!--Load Panda joint fixer Gazebo world plugin-->
<plugin name="panda_joint_locker" filename="libpanda_gazebo.so"/>
</world>
</sdf>
2 changes: 2 additions & 0 deletions panda_gazebo/resources/worlds/push.world
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@
<projection_type>perspective</projection_type>
</camera>
</gui>
<!--Load Panda joint fixer Gazebo world plugin-->
<plugin name="panda_joint_locker" filename="libpanda_gazebo.so"/>
</world>
</sdf>
2 changes: 2 additions & 0 deletions panda_gazebo/resources/worlds/reach.world
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
<projection_type>perspective</projection_type>
</camera>
</gui>
<!--Load Panda joint fixer Gazebo world plugin-->
<plugin name="panda_joint_locker" filename="libpanda_gazebo.so"/>
</world>
</sdf>
2 changes: 2 additions & 0 deletions panda_gazebo/resources/worlds/slide.world
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@
<projection_type>perspective</projection_type>
</camera>
</gui>
<!--Load Panda joint fixer Gazebo world plugin-->
<plugin name="panda_joint_locker" filename="libpanda_gazebo.so"/>
</world>
</sdf>
118 changes: 118 additions & 0 deletions panda_gazebo/src/panda_joint_locker_world_plugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* @file panda_joint_locker_world_plugin.cpp
* @brief A Gazebo WorldPlugin for controlling joint locking in a Panda robot.
*/
#include <gazebo/common/Plugin.hh>
#include <gazebo/physics/physics.hh>
#include <ros/ros.h>
#include "panda_gazebo/LockJoints.h"

namespace gazebo
{
const std::string MODEL_NAME = "panda";
const std::string SERVICE_NAME = "/lock_unlock_panda_joints";
const unsigned int JOINT_AXIS_INDEX = 0;

/**
* @brief A Gazebo WorldPlugin class for controlling joint locking in a Panda robot.
*/
class PandaJointLockerPlugin : public WorldPlugin
{
public:
/**
* @brief Construct a new Panda Joint Locker Plugin object.
*/
PandaJointLockerPlugin() : WorldPlugin()
{
}

/**
* @brief Load the plugin, initialize the ROS node and service, and store the initial max_force values for all joints.
*
* @param _world Pointer to the Gazebo world.
* @param _sdf Pointer to the SDF element.
*/
void Load(physics::WorldPtr _world, sdf::ElementPtr _sdf)
{
ROS_INFO("Loading PandaJointLockerPlugin");

// Make sure the ROS node for Gazebo has already been initialized.
if (!ros::isInitialized())
{
ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
<< "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
return;
}

// Create ROS node.
this->rosNode.reset(new ros::NodeHandle("panda_joint_control_plugin"));

// Create ROS service to lock and unlock specified joints.
this->rosService = this->rosNode->advertiseService(SERVICE_NAME, &PandaJointLockerPlugin::LockUnlockJoints, this);

// Store the pointer to the world.
this->world = _world;

ROS_INFO("Loaded PandaJointLockerPlugin");
}

private:
physics::WorldPtr world;
std::unique_ptr<ros::NodeHandle> rosNode;
ros::ServiceServer rosService;
std::map<std::string, double> oldLowerLimit;
std::map<std::string, double> oldUpperLimit;

/**
* @brief Lock or unlock the specified joints.
*
* @param req The service request, which specifies the joints to lock or unlock.
* @param res The service response, which indicates whether the operation was successful.
* @return true if the service was handled successfully, false otherwise.
*/
bool LockUnlockJoints(panda_gazebo::LockJoints::Request& req, panda_gazebo::LockJoints::Response& res)
{
auto model = this->world->ModelByName(MODEL_NAME);
if (!model)
{
res.success = false;
res.message = "Model not found: " + MODEL_NAME + ". Unable to lock/unlock joints.";
return true;
}

for (const std::string& joint_name : req.joint_names)
{
auto joint = model->GetJoint(joint_name);
if (!joint)
{
res.success = false;
res.message = "Joint not found: " + joint_name;
return true;
}

if (req.lock)
{
double current_position = joint->Position(JOINT_AXIS_INDEX);

// Store old limits and lock joint at current position.
this->oldLowerLimit[joint_name] = joint->LowerLimit(JOINT_AXIS_INDEX);
this->oldUpperLimit[joint_name] = joint->UpperLimit(JOINT_AXIS_INDEX);
joint->SetLowerLimit(JOINT_AXIS_INDEX, current_position);
joint->SetUpperLimit(JOINT_AXIS_INDEX, current_position);
}
else
{
// Unlock the joint by restoring the old joint limits.
joint->SetLowerLimit(JOINT_AXIS_INDEX, this->oldLowerLimit[joint_name]);
joint->SetUpperLimit(JOINT_AXIS_INDEX, this->oldUpperLimit[joint_name]);
}
}

res.success = true;
res.message = "Joints updated successfully";
return true;
}
};

GZ_REGISTER_WORLD_PLUGIN(PandaJointLockerPlugin)
} // namespace gazebo
6 changes: 6 additions & 0 deletions panda_gazebo/srv/LockJoints.srv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Service that can be used to lock/unlock specific joints of the robot.
string[] joint_names
bool lock
---
bool success
string message

0 comments on commit b0845a5

Please sign in to comment.