Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

How to move a ur3 robot arm by using actions?

Dear community,

  1. I'm absolutely new to ROS, so please excuse my technically perhaps not always quite correct expressions.
  2. I'm running ROS Kinetic on Ubuntu 16.04 LTS and cloned the "universal robot" package from the following GitHub repository: (https://github.com/ros-industrial/universal_robot.git)
  3. After "building" my Catkin workspace by typing catkin_make everything worked fine so far and I could successfully launch a simulation of an ur3 robot in Gazebo by typing roslaunch ur_gazebo ur3.launch into a new terminal.
  4. What i wanted to do now, was to control the total of six joints of the ur3 without using MoveIt. So i did some research and found the following Link: Moving the arm using the Joint Trajectory Action So basically I wanted to try to control the ur3 in the Gazebo simulation via an action client. Since the description in the link above did not exactly fit to my robot, I tried to adapt the simple_trajectory.cpp file written there to the ur3 robot.

My "adapted" code file (without the included headers) now looks like shown below.

(The libraries I included by writing #include are the following: <ros/ros.h>; <control_msgs/FollowJointTrajectoryAction.h> and <actionlib/client/simple_action_client.h)


typedef actionlib::SimpleActionClient <control_msgs::FollowJointTrajectoryAction> TrajClient;

class Ur3Arm
{
    private:
        // Action client for the follow joint trajectory action used to trigger the arm movement action
        TrajClient* traj_client_;

    public:
        // Initialize the action client and wait for action server to come up.
        Ur3Arm()
        {
            // Tell the action client that we want to spin a thread by default:
            traj_client_ = new TrajClient("arm_controller/follow_joint_trajectory_action", true);

            // Wait for the action server to come up
            while(!traj_client_->waitForServer(ros::Duration(5.0))) 
            {
                ROS_INFO("Wait for the follow_joint_trajectory_action server");
            }
        }

        // Clean up the action client
        // -> Destructor of class Ur3Arm

        ~Ur3Arm()
        {
            delete traj_client_;
        }

        // Send the command to start a given trajectory

        void startTrajectory(control_msgs::FollowJointTrajectoryGoal goal)
        {
            // When to start the trajectory: 1s from now
            goal.trajectory.header.stamp = ros::Time::now() + ros::Duration(1.0);
            traj_client_->sendGoal(goal);
        }

        // Generates a simple trajectory with two waypoints, used as an example
        /* Note that this trajectory contains two waypoints, joined together as a single trajectory.
           Alternatively, each of these waypoints could be in its own trajectory - a trajectory can have one
           or more waypoints depending on the desired application.
        */

        control_msgs::FollowJointTrajectoryGoal armExtensionTrajectory()
        {
            // The goal variable:
            control_msgs::FollowJointTrajectoryGoal goal;

            // First, the joint names, which apply to all waypoints
            goal.trajectory.joint_names.resize(1);
            goal.trajectory.joint_names.push_back("shoulder_pan_joint");
            goal.trajectory.joint_names.push_back("shoulder_lift_joint");
            goal.trajectory.joint_names.push_back("elbow_joint");
            goal.trajectory.joint_names.push_back("wrist_1_joint");
            goal.trajectory.joint_names.push_back("wrist_2_joint");
            goal.trajectory.joint_names.push_back("wrist_3_joint");

            // In this simple case there asre only two waypoints in this goal trajectory
            goal.trajectory.points.resize(2);

            // First trajectory waypoint

                        int ind = 0; // Represents the number of the actual waypoint

                        // Positions:

                        goal.trajectory.points[ind].positions.resize(6);
                        goal.trajectory.points[ind].positions[0] = 0.0;
                        goal.trajectory.points[ind].positions[1] = 0.0;
                        goal.trajectory.points[ind].positions[2] = 0.0;
                        goal.trajectory.points[ind].positions[3] = 0.0;
                        goal.trajectory.points[ind].positions[4] = 0.0;
                        goal.trajectory.points[ind].positions[5] = 0.0;

                        // Velocities
                        goal.trajectory.points[ind].velocities.resize(6);
                        for(size_t i = 0; i < 6; ++i)
                        {
                            goal.trajectory.points[ind].velocities[i] = 0.0;
                        }

                        // To be reached 1 second after starting along the trajectory
                        goal.trajectory.points[ind].time_from_start = ros::Duration(1.0);

            // Second trajectory waypoint

                        ind += 1;
                        // Positions:
                        goal.trajectory.points[ind].positions.resize(6);
                        goal.trajectory.points[ind].positions[0] = 0.0;
                        goal.trajectory.points[ind].positions[1] = -1.5;
                        goal.trajectory.points[ind].positions[2] = 1.5;
                        goal.trajectory.points[ind].positions[3] = -3.0;
                        goal.trajectory.points[ind].positions[4] = 0.0;
                        goal.trajectory.points[ind].positions[5] = 0.0;

                        // Velocities
                        goal.trajectory.points[ind].velocities.resize(6);
                        for(size_t i = 0; i < 6; ++i)
                        {
                            goal.trajectory.points[ind].velocities[i] = 0.0;
                        }

                        // To be reached 2 second after starting along the trajectory
                        goal.trajectory.points[ind].time_from_start = ros::Duration(2.0);

                        // Function done, return the goal
                        return goal;

        }

        // Returns the current state of the action

        actionlib::SimpleClientGoalState getState()
        {
            return traj_client_->getState();
        }

};



int main (int argc, char** argv)
{
    // Init the ROS node
    ros::init(argc, argv, "robot_driver");

    Ur3Arm arm;

    // Start the trajectory
    arm.startTrajectory(arm.armExtensionTrajectory());

    // Wait for trajectory completion
    while(!arm.getState().isDone() && ros::ok())
    {
        usleep(50000); // Argument of usleep is given in miliseconds -> Wait fo 50s
    }

    return 0;
}

The code can be compiled succesfully and I can also run the action client by typing rosrun simple_trajectory simple_trajectory_action_client (My package ist named simple_trajectory)


The problem I have is, that the code obviously stucks at the following point

while(!traj_client_->waitForServer(ros::Duration(5.0))) 
            {
                ROS_INFO("Wait for the follow_joint_trajectory_action server");
            }
        }

since this message appears on my terminal every five seconds. Of course each action client needs an action server, but like I understood the whole thing, the action server starts automatically by launching the ur3 robot in Gazebo, right? I think so, because after launching the ur3 robot in Gazebo I got the following output by typing rostopic list |grep arm_controller in a terminal:

/arm_controller/command
/arm_controller/follow_joint_trajectory/cancel
/arm_controller/follow_joint_trajectory/feedback
/arm_controller/follow_joint_trajectory/goal
/arm_controller/follow_joint_trajectory/result
/arm_controller/follow_joint_trajectory/status
/arm_controller/state

Can anyone tell me if this way to move the ur3 robots arm can work at all and if so, where the problem in my implementation is? I'd be very grateful for any help!

How to move a ur3 robot arm by using actions?

Dear community,

  1. I'm absolutely new to ROS, so please excuse my technically perhaps not always quite correct expressions.
  2. I'm running ROS Kinetic on Ubuntu 16.04 LTS and cloned the "universal robot" package from the following GitHub repository: (https://github.com/ros-industrial/universal_robot.git)
  3. After "building" my Catkin workspace by typing catkin_make everything worked fine so far and I could successfully launch a simulation of an ur3 robot in Gazebo by typing roslaunch ur_gazebo ur3.launch into a new terminal.
  4. What i wanted to do now, was to control the total of six joints of the ur3 without using MoveIt. So i did some research and found the following Link: Moving the arm using the Joint Trajectory Action So basically I wanted to try to control the ur3 in the Gazebo simulation via an action client. Since the description in the link above did not exactly fit to my robot, I tried to adapt the simple_trajectory.cpp file written there to the ur3 robot.

My "adapted" code file (without the included headers) now looks like shown below.

(The libraries I included by writing #include are the following: <ros/ros.h>; <control_msgs/FollowJointTrajectoryAction.h> and <actionlib/client/simple_action_client.h)


typedef actionlib::SimpleActionClient <control_msgs::FollowJointTrajectoryAction> TrajClient;

class Ur3Arm
{
    private:
        // Action client for the follow joint trajectory action used to trigger the arm movement action
        TrajClient* traj_client_;

    public:
        // Initialize the action client and wait for action server to come up.
        Ur3Arm()
        {
            // Tell the action client that we want to spin a thread by default:
            traj_client_ = new TrajClient("arm_controller/follow_joint_trajectory_action", true);

            // Wait for the action server to come up
            while(!traj_client_->waitForServer(ros::Duration(5.0))) 
            {
                ROS_INFO("Wait for the follow_joint_trajectory_action server");
            }
        }

        // Clean up the action client
        // -> Destructor of class Ur3Arm

        ~Ur3Arm()
        {
            delete traj_client_;
        }

        // Send the command to start a given trajectory

        void startTrajectory(control_msgs::FollowJointTrajectoryGoal goal)
        {
            // When to start the trajectory: 1s from now
            goal.trajectory.header.stamp = ros::Time::now() + ros::Duration(1.0);
            traj_client_->sendGoal(goal);
        }

        // Generates a simple trajectory with two waypoints, used as an example
        /* Note that this trajectory contains two waypoints, joined together as a single trajectory.
           Alternatively, each of these waypoints could be in its own trajectory - a trajectory can have one
           or more waypoints depending on the desired application.
        */

        control_msgs::FollowJointTrajectoryGoal armExtensionTrajectory()
        {
            // The goal variable:
            control_msgs::FollowJointTrajectoryGoal goal;

            // First, the joint names, which apply to all waypoints
            goal.trajectory.joint_names.resize(1);
            goal.trajectory.joint_names.push_back("shoulder_pan_joint");
            goal.trajectory.joint_names.push_back("shoulder_lift_joint");
            goal.trajectory.joint_names.push_back("elbow_joint");
            goal.trajectory.joint_names.push_back("wrist_1_joint");
            goal.trajectory.joint_names.push_back("wrist_2_joint");
            goal.trajectory.joint_names.push_back("wrist_3_joint");

            // In this simple case there asre only two waypoints in this goal trajectory
            goal.trajectory.points.resize(2);

            // First trajectory waypoint

                        int ind = 0; // Represents the number of the actual waypoint

                        // Positions:

                        goal.trajectory.points[ind].positions.resize(6);
                        goal.trajectory.points[ind].positions[0] = 0.0;
                        goal.trajectory.points[ind].positions[1] = 0.0;
                        goal.trajectory.points[ind].positions[2] = 0.0;
                        goal.trajectory.points[ind].positions[3] = 0.0;
                        goal.trajectory.points[ind].positions[4] = 0.0;
                        goal.trajectory.points[ind].positions[5] = 0.0;

                        // Velocities
                        goal.trajectory.points[ind].velocities.resize(6);
                        for(size_t i = 0; i < 6; ++i)
                        {
                            goal.trajectory.points[ind].velocities[i] = 0.0;
                        }

                        // To be reached 1 second after starting along the trajectory
                        goal.trajectory.points[ind].time_from_start = ros::Duration(1.0);

            // Second trajectory waypoint

                        ind += 1;
                        // Positions:
                        goal.trajectory.points[ind].positions.resize(6);
                        goal.trajectory.points[ind].positions[0] = 0.0;
                        goal.trajectory.points[ind].positions[1] = -1.5;
                        goal.trajectory.points[ind].positions[2] = 1.5;
                        goal.trajectory.points[ind].positions[3] = -3.0;
                        goal.trajectory.points[ind].positions[4] = 0.0;
                        goal.trajectory.points[ind].positions[5] = 0.0;

                        // Velocities
                        goal.trajectory.points[ind].velocities.resize(6);
                        for(size_t i = 0; i < 6; ++i)
                        {
                            goal.trajectory.points[ind].velocities[i] = 0.0;
                        }

                        // To be reached 2 second after starting along the trajectory
                        goal.trajectory.points[ind].time_from_start = ros::Duration(2.0);

                        // Function done, return the goal
                        return goal;

        }

        // Returns the current state of the action

        actionlib::SimpleClientGoalState getState()
        {
            return traj_client_->getState();
        }

};



int main (int argc, char** argv)
{
    // Init the ROS node
    ros::init(argc, argv, "robot_driver");

    Ur3Arm arm;

    // Start the trajectory
    arm.startTrajectory(arm.armExtensionTrajectory());

    // Wait for trajectory completion
    while(!arm.getState().isDone() && ros::ok())
    {
        usleep(50000); // Argument of usleep is given in miliseconds -> Wait fo 50s
    }

    return 0;
}

The code can be compiled succesfully and I can also run the action client by typing rosrun simple_trajectory simple_trajectory_action_client (My package ist named simple_trajectory)


The problem I have is, that the code obviously stucks at the following point

while(!traj_client_->waitForServer(ros::Duration(5.0))) 
            {
                ROS_INFO("Wait for the follow_joint_trajectory_action server");
            }
        }

since this message appears on my terminal every five seconds. Of course each action client needs an action server, but like I understood the whole thing, the action server starts automatically by launching the ur3 robot in Gazebo, right? I think so, because after launching the ur3 robot in Gazebo I got the following output by typing rostopic list |grep arm_controller in a terminal:

/arm_controller/command
/arm_controller/follow_joint_trajectory/cancel
/arm_controller/follow_joint_trajectory/feedback
/arm_controller/follow_joint_trajectory/goal
/arm_controller/follow_joint_trajectory/result
/arm_controller/follow_joint_trajectory/status
/arm_controller/state

Can anyone tell me if this way to move the ur3 robots arm can work at all and if so, where the problem in my implementation is? I'd be very grateful for any help!


Edit: Hi jschornak,

First of all thank you very much for your quick help! You made me understand the whole thing a little bit better now. After fixing the wrong implementation of the line where I create the new action client to

 traj_client_ = new TrajClient("/arm_controller/follow_joint_trajectory", true);

I can now succesfully run the action client without stucking at the point, where the client waits for the action server. So your advice could fix my original problem! So far, so good!...


Unfortunately, I now have the problem that after starting the action client by typing

rosrun simple_trajectory simple_trajectory (package an file are both named like this)

the terminal gets "busy" for about one second while the action client "executes", but the robots arm doesn't seem to get any moving commands in Gazebo. After this short period of time, my simple_trajectory.cpp file has been completely executed, the terminal where i executed the file gets "free" again and nothing happened. I really hope, I made my problem clear at this point.

Can you or anyone else tell me where the problem is?

Thank you in advance!