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:
- I consider 6-joint values as a vector.
- Now, I have the target point (6-joint values) that I want the robot to reach and current positions that I receive from
joint_states
topic. Therefore,
For each received point:
- Calculate distance between current point and target point (
numpy.norm(current_point - target_point)
) - As the arm approaches the target point, the distance (
norm
) value should decrease. If current distance is greater than previous distance, I consider that it has reached the target 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 thejoint_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 thepositions
inactual
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
I'm not sure I understand what you mean by this. Which product are you referring to?
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 inros(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
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