Robotics StackExchange | Archived questions

How to know when each point in the trajectory was executed?

I'm new to ROS. I wrote the code below to execute a trajectory using SimpleActionClient. I need to know when each point in the trajectory was executed while the trajectory is being executed. I thought to use the feedback callback from action client's send_goal method, but it's never called. The done_cb and active_cb are called, but not feedback_cb. Then, I thought since each point has time_from_start field I could listen to /feedback_states topic (see list of topics below) and check the the time_from_start field (see the feedback_state output below). But, it's always 0.

What am I doing wrong? Or, even better, is this how to get what I need or is there another better way?

UPDATE1

Just to clarify, I want to control the Yaskawa hc10 robot from ROS AND be able to know what trajectory point it's currently executing. After the research I saw that I should use motoman driver. I found some python example and continued from there. So, the first part seems to work. But, now I need to make the second part to work. To do that I decided to check the time_from_start field from the message from /feedback_states topic since I assign time_from_start to each point when I build the trajectory object. But, when I do rostopic echo /joint_states I can see that time_from_start is always 0 and doesn't have the values I assigned.

Therefore, I decided a different approach - listen to joint_states topic and do the following:

For each received point:

Does this make sense? I'll post the issues I have with this approach if needed, unless you already know what can be the issues.

Code

client = actionlib.SimpleActionClient('/joint_trajectory_action', FollowJointTrajectoryAction)
        if not client.wait_for_server(rospy.Duration(5.0)):
            raise RuntimeError("Action server not available!")

def _create_trajpoint(self, joint_positions, time_from_start, velocities) -> JointTrajectoryPoint:
        point = JointTrajectoryPoint()
        point.positions = joint_positions
        point.time_from_start = rospy.Duration(time_from_start)
        point.velocities = velocities

        return point

def _execute_trajectory(self, traj):
        self._send_trajectory_to_controller(traj)
        self._wait_for_traj_to_complete()

    def _send_trajectory_to_controller(self, traj):
        print("Sending trajectory")

        goal = FollowJointTrajectoryGoal()
        goal.trajectory = traj

        self._action_client.send_goal(goal, feedback_cb=my_feedback_cb, done_cb=my_done_cb, active_cb=my_active_cb)
        self._action_client.wait_for_result(rospy.Duration(2.0))

        print("Trajectory sent")

    def _wait_for_traj_to_complete(self):
        print('Waiting for trajectory to complete')

        wait_time = 0.1
        no_motion_total = 0
        no_motion_timeout = 1
        traj_state = self._action_client.get_state()
        while traj_state == actionlib.GoalStatus.ACTIVE:
            rospy.sleep(wait_time)

            traj_state = self._action_client.get_state()
            robot_status = self.get_robot_status()
            if robot_status.in_motion.val == 0: 
                no_motion_total += wait_time
                if no_motion_total > no_motion_timeout:
                    raise RuntimeError(f'Robot hasn\'t moved for {no_motion_timeout} sec. TrajState={traj_state}')
            else:
                no_motion_total = 0

        if traj_state == actionlib.GoalStatus.PREEMPTED:
            raise OperationCanceledExepction('Trajectory goal was canceled')
        if traj_state != actionlib.GoalStatus.SUCCEEDED:
            raise RuntimeError(f"Failed to complete trajectory. TrajState={traj_state}")

feedback_states

rostopic echo /feedback_states

header: 
  seq: 265925
  stamp: 
    secs: 1687457226
    nsecs:  28453125
  frame_id: ''
joint_names: 
  - joint_1_s
  - joint_2_l
  - joint_3_u
  - joint_4_r
  - joint_5_b
  - joint_6_t
desired: 
  positions: []
  velocities: []
  accelerations: []
  effort: []
  time_from_start: 
    secs: 0
    nsecs:         0
actual: 
  positions: [-0.5130592584609985, 0.45683741569519043, 0.9317458271980286, -1.008545994758606, -1.255672812461853, -1.8192806243896484]
  velocities: []
  accelerations: []
  effort: []

Topics

/feedback_states
/joint_path_command
/joint_states
/joint_trajectory_action/cancel
/joint_trajectory_action/feedback
/joint_trajectory_action/goal
/joint_trajectory_action/result
/joint_trajectory_action/status
/robot_status
/rosout
/rosout_agg
/tf
/tf_static

Asked by arisigor on 2023-06-22 13:24:59 UTC

Comments

Quick note: I don't believe you can. From the messages you show, this looks like motoman_driver. Due to how caching works on the MotoROS1 side (it has an internal queue, and the underlying Yaskawa controller code has yet another internal queue), you can't rely on what the driver tells you -- at least not about the state of the action server. What you could do is look at the joint_states topic and derive progress from that. That's non-trivial though, as "loops" in a trajectory would make comparisons difficult.

I'm sorry there isn't something nicer to write, but I believe it's a fundamental limitation of how the system is implemented (and technically, any driver / robot controller with (an) internal queue(s) would make really knowing how much of a trajectory has been executed impossible, not just in the case of Yaskawa. I only know of Staubli which has functionality to track this sort of thing).

Asked by gvdhoorn on 2023-06-22 14:30:41 UTC

Btw, if you're specifically interested in detecting whether the robot has moved or not, the robot_status topic carries that information.

Asked by gvdhoorn on 2023-06-22 14:33:14 UTC

What about /feedback_states or /joint_trajectory_action/feedback topics? Why only the positions in actual section is filled but all other is empty? What's the point of these topics then if they don't report data?

Asked by arisigor on 2023-06-22 14:45:00 UTC

You'd have to ask the original developers I'm afraid. I can't answer that.

Asked by gvdhoorn on 2023-06-22 14:45:49 UTC

sorry, do you know where would I ask? I thought ROS community is the place to ask.

Asked by arisigor on 2023-06-22 14:53:37 UTC

That would be a post on ros-industrial/motoman/discussions. Note though: motoman_driver is really old, almost 12 years now. Only one of the original developers would maybe respond, and I don't know whether he'd still remember.

Asked by gvdhoorn on 2023-06-22 14:55:58 UTC

Can I ask what's your recommendation to control the Yaskawa from ROS? Yaskawa have a dedicated driver, but it's not free. If I use ROS, what's my alternative to motoman_driver?

Asked by arisigor on 2023-06-22 15:01:46 UTC

Yaskawa have a dedicated driver, but it's not free

I'm not sure I understand what you mean by this. Which product are you referring to?

If I use ROS, what's my alternative to motoman_driver?

I would not know of an alternative.

Asked by gvdhoorn on 2023-06-22 15:05:13 UTC

sorry, I meant SDK.

Asked by arisigor on 2023-06-23 03:29:21 UTC

You mean MotoPlus? motoman_driver uses MotoPlus (well, the part running on the robot controller does).

Asked by gvdhoorn on 2023-06-23 03:32:48 UTC

Note btw: even the "most popular" implementation of a follow_joint_trajectory controller -- the one in ros(2)_control -- does not really make "which trajectory point is being executed" available.

See ros-controls/control_msgs#65 and ros-controls/control_msgs#67.

Asked by gvdhoorn on 2023-06-24 10:42:47 UTC

Do you know how anyone deals with it in the industry? I'm new to ROS. So, what do you mean by "follow_joint_trajectory controller"? What are other implementations except ""follow_joint_trajectory controller"?

Asked by arisigor on 2023-06-26 10:29:33 UTC

Do you know how anyone deals with it in the industry?

I don't know what you mean by "it".

Asked by gvdhoorn on 2023-06-26 10:39:22 UTC

I meant do you know how anyone deals with detecting "which trajectory point is being executed" in the industry? Or no one does such thing?

Asked by arisigor on 2023-06-26 10:45:52 UTC

I can obviously not answer how others "in industry" do things. I'm only one person.

Perhaps if you could describe what you're trying to achieve, we could discuss a way that doesn't look at the data you report as missing.

Asked by gvdhoorn on 2023-06-26 12:57:58 UTC

since the formatting didn't work for me when I tried to leave a comment, I added the clarification and what I've tried in the post under UPDATE1 section. Can you take a look please?

Asked by arisigor on 2023-06-26 14:25:44 UTC

This will sound pedantic, but when I wrote "I don't know what you're trying to do", I was wondering why you need to track trajectory execution in the manner you describe. It's unlikely you're doing this "just because".

It was already clear you want to do it, but without knowing why, it's hard to suggest alternative approaches.

Asked by gvdhoorn on 2023-06-27 02:58:50 UTC

We have UI application through which we send sequence of trajectory points to the robot. A user needs to visually see what trajectory point is currently being executed. We cannot just wait till the robot stops and then compare if the current position equals to the last trajectory point just to know if the whole trajectory succeeded. We want to show the user in "real time" the feedback.

Asked by arisigor on 2023-06-27 11:01:53 UTC

Ok, thanks for that description.

For that purpose the approach you describe ("calculate joint distance based on joint_states and determine progress using that") seems sufficient. It's basically what I wrote in my first comment.

As I wrote, it's non-trivial to have the driver publish which specific trajectory segment is being executed, as there are various buffers which feed each other. Changes would be needed at the lowest level of MotoROS (and then brought up through all the involved layers) to accurately track what the status of the motion is.

That's not trying to gold-plate things, just giving a possible explanation for why it isn't supported.

Asked by gvdhoorn on 2023-06-27 12:26:57 UTC

Answers