ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
2

gazebo set joint angles by ROS

asked 2016-04-27 09:19:56 -0500

JohnDoe2991 gravatar image

Hi everyone!

I have a robot arm model in Gazebo with several "revolute" joints. I simply want to set the angles of the joints by a ROS service, topic or whatever WITHOUT any closed-loop controller. Just enter an angle and the robot jumps to that position. Is that possible?

Background: I have a real robot arm, from which I can read the joint angles. These angles should be sent to Gazebo, where the simulated arm follows the movement of the real arm. In the simulation I want to recreate a special environment with several sensors for the robot arm to test my ROS nodes.

edit retag flag offensive close merge delete

4 Answers

Sort by ยป oldest newest most voted
0

answered 2016-04-28 06:22:45 -0500

JohnDoe2991 gravatar image

Ok, here is what i found: You can set the position and orientation for every Gazebo model with the service "setModelState", but if you really want to set the joints' angles of a model, you have to write a Gazebo Plugin as F.Brosseau has stated in his answer.

My solution is based on the following three webpages and some experimenting. It is probably a quite bad solution, but the only one I came up with in the last few hours. Feel free to use and improve it. I won't take any responsibility for it.

http://gazebosim.org/tutorials/?tut=plugins_hello_world

http://gazebosim.org/tutorials?tut=plugins_model&cat=write_plugin

http://gazebosim.org/tutorials?cat=guided_i&tut=guided_i6

The plugin will subscribe to a special named topic for every "revolute" joint it can find in the model. You can find the topic names with "rostopic list" after you started a model with this plugin. The topics consist only of a Float32 value, which correspond to the angle in [rad]. If you publish a topic with the joint name and an angle, the joint will be forced to this angle and hold in place.

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.3)
project(force_joint)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
find_package(roscpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)
find_package(gazebo REQUIRED)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${GAZEBO_INCLUDE_DIRS} ${roscpp_INCLUDE_DIRS} ${std_msgs_INCLUDE_DIRS} src)
link_directories(${GAZEBO_LIBRARY_DIRS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}  ${GAZEBO_CXX_FLAGS} -std=c++11")

add_library(force_joint SHARED src/force_joint.cpp)
target_link_libraries(force_joint ${Boost_LIBRARIES} ${GAZEBO_LIBRARIES} ${roscpp_LIBRARIES})

force_joint.cpp

#include <ros/ros.h>
#include "ros/callback_queue.h"
#include "ros/subscribe_options.h"
#include "std_msgs/Float32.h"

#include <gazebo/gazebo.hh>
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <gazebo/physics/physics.hh>
#include <gazebo/common/common.hh>
#include <thread>
#include <memory>
#include <map>

namespace gazebo
{
    class force_joint : public ModelPlugin
    {
    public:
        force_joint() : ModelPlugin(){}

        //read every joint of model and initialize ROS topics
        void Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf)
        {
            this->model = _parent;
            this->updateConnection = event::Events::ConnectWorldUpdateBegin(boost::bind(&force_joint::OnUpdate, this, _1));
            physics::Joint_V jointVector = this->model->GetJoints();

            // Initialize ros, if it has not already bee initialized.
            if (!ros::isInitialized())
            {
                int argc = 0;
                char **argv = NULL;
                ros::init(argc, argv, "gazebo_client",
                ros::init_options::NoSigintHandler);
            }

            // Create our ROS node. This acts in a similar manner to the Gazebo node
            this->rosNode.reset(new ros::NodeHandle("force_joints"));

            // Create a named topic, and subscribe to it for every joint
            for(physics::Joint_V::iterator jit=jointVector.begin(); jit!=jointVector.end(); ++jit)
            {
                //test if revolute joint ... i think ...
                //if not, ignore joint
                if((*jit)->GetType() != 576)
                    continue;
                std::string modelName = this->model->GetName();
                boost::algorithm::replace_all(modelName, " ", "_");
                std::string jointName = (*jit)->GetName();
                boost::algorithm::replace_all(jointName, " ", "_");
                std::string subPath = modelName + "/" + jointName;
                ros::SubscribeOptions so = ros::SubscribeOptions::create<std_msgs::Float32>(subPath,
                                                                            1,
                                                                            boost::bind(&force_joint::OnRosMsg, this, _1, (*jit)->GetName()),
                                                                            ros::VoidPtr(), &this->rosQueue);
                this->rosSubList.push_back(this->rosNode->subscribe(so));
                joints.push_back((*jit)->GetName());
                jointAngles[(*jit)->GetName()] = (*jit)->GetAngle(0).Radian();
            }

            // Spin up ...
(more)
edit flag offensive delete link more

Comments

Hi John Doe, As you mentioned above i created a package and included the above files in the catkin workspace, I also included it in my robot model, but when start gazebo it could not load the libforce_joint.so. but the libforce_joint.so exists in libforce_joint folder. This is the exact error i get

vjothi gravatar image vjothi  ( 2016-11-28 15:28:42 -0500 )edit

Take a look at the first link at "Using a Plugin": You either have to use the full path in your model file, add the path to the GAZEBO_PLUGIN_PATH or copy libforce_joint.so to /opt/ros/indigo/lib/ (that's what I did). Hope I could help.

JohnDoe2991 gravatar image JohnDoe2991  ( 2016-11-29 00:41:06 -0500 )edit
6

answered 2017-10-17 05:20:07 -0500

updated 2019-06-09 13:40:16 -0500

rosservice call /gazebo/set_model_configuration is far better than the solutions posted here so far, no plugin needed. Here is a complete example of how to achieve this from terminal:

rosservice call /gazebo/set_model_configuration "model_name: 'acrobat'
urdf_param_name: 'robot_description'
joint_names:
- 'joint1'
joint_positions:
- 3.3"

Tested on Gazebo 7, ROS kinetic and Ubuntu 16.04 with the acrobat robot

edit flag offensive delete link more

Comments

This worked for me...!!!! more info here: http://gazebosim.org/tutorials?tut=ro...

ivan_calle gravatar image ivan_calle  ( 2017-11-17 07:58:51 -0500 )edit

I'm facing the same issue as this question where I can set the robot pose after pausing gazebo, but after unpausing, the robot pose snaps back to the original pose.

I ended up having to do it this way

Rufus gravatar image Rufus  ( 2020-09-02 22:41:55 -0500 )edit
1

answered 2016-04-28 01:56:56 -0500

F.Brosseau gravatar image

Yes it's possible.

If you make a gazebo plugin attached to your robot model, you can use the setPosition function in the Gazebo API https://osrf-distributions.s3.amazonaws.com/gazebo/api/dev/classgazebo_1_1physics_1_1Joint.html.

edit flag offensive delete link more

Comments

I hopped there would be an easier solution than writing a plugin for gazebo

JohnDoe2991 gravatar image JohnDoe2991  ( 2016-04-28 03:09:34 -0500 )edit
0

answered 2018-11-14 11:47:13 -0500

aschaefer gravatar image

updated 2018-11-29 12:08:02 -0500

Yes, it is possible! In order to control your robot in Gazebo without setting up controllers, you have to follow these steps:

  1. Convert your robot to a Gazebo actor. An actor is a model that is not affected by Gazebo's physics engine. To this end, convert your URDF file to SDF and then replace the <model> tag by <actor>.
  2. Write a Gazebo plugin that listens to ROS transformations and sets the poses of the actor links accordingly.
  3. Include a reference to your plugin in the SDF.
  4. Upload the SDF to Gazebo.

You can do all the steps yourself, or you can download the gazebo_tf_injector package, which contains both the Gazebo plugin and a script to convert your URDF to an actor SDF. It also comes with lots of documentation and a ready-to-use example, which should get you started quickly.

edit flag offensive delete link more

Question Tools

4 followers

Stats

Asked: 2016-04-27 09:19:56 -0500

Seen: 6,951 times

Last updated: Jun 09 '19