-
Notifications
You must be signed in to change notification settings - Fork 411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Robot status topic via controller #141
Conversation
Update from upstream repo
@axelschroth wrote in #32 (comment):
The controller will only publish something if its You may have to add it to the |
fixes problem that no messages are published if robot program is not running
ur_robot_driver/package.xml
Outdated
@@ -38,6 +38,7 @@ | |||
<depend>ur_dashboard_msgs</depend> | |||
<depend>ur_msgs</depend> | |||
<depend>std_srvs</depend> | |||
<depend>industrial_robot_status_interface</depend> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a build_depend
only?
It's a header-only library, there is nothing at runtime there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're right
Would you not need to add |
Done with last commit. Thanks! Any further suggestions? |
void HardwareInterface::extractRobotStatus() | ||
{ | ||
// robot status bit 2: Is teach button pressed | ||
robot_status_resource_.mode = robot_status_bits_[2] ? RobotMode::MANUAL : RobotMode::AUTO; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I do have an additional comment: please use some constants here for the bit indices instead of magic nrs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really the right check? The robot can be in manual mode without the teach button being pressed, right?
I am aware, that usually on industrial robots manual and automatic modes have a different meaning than the one used on UR robots. But boiling it down to the teach button pressed feels misleading to me, as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fmauch: this was ported from ur_modern_driver
I believe.
Would you happen to have a suggestion on how to better determine whether the controller is in AUTO
or MANUAL
?
I don't even believe URs really have that concept.
When they're being "freedrived" though they are definitely not in AUTO
(or whatever we want to call the equivalent on URs).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't even believe URs really have that concept.
They do (on e-Series, on CB3 the same concept was called "running mode" and "programming mode"), but that concept is different (or a little less restrictive). In AUTO
mode (which you can activate after setting a password) one can only load and execute predefined programs. (See section "Operational Mode Selection" in the manual)
However, I am currently not aware of a method receiving this information. (which, of course, doesn't necessarily mean, that it doesn't exist)
When they're being "freedrived" though they are definitely not in AUTO (or whatever we want to call the equivalent on URs).
Yes, but it feels as if we would be misusing the field from the message for something semantically different. Which, as you reminded me often, not the best thing to do :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you happen to have a suggestion on how to better determine whether the controller is in AUTO or MANUAL?
Forgot to answer that... To be honest - I don't know. I think, using what UR calls manual and automatic operational mode comes closest to what other industrial robots semantically state with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with your points, but as you said @gavanderhoorn , this implementation is based on the interpretation of the ur_modern_driver.
I also thought about the issue when porting to the RTDE interface, but I didn't find any possibility to read this information about the Operational Mode over the RTDE interface (see RTDE Guide )...
Another point to think of: What would we do with the CB-series? I think in the old Polyscope versions, you have to use a configurable input to change to running mode. Yet we could use that as "robot mode" if we have the information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about limiting this PR to porting the ur_modern_driver
implementation, then using a potential follow-up PR after/if we get more information on what @fmauch mentions?
It would be a nice enhancement over the partial implementation from ur_modern_driver
.
@axelschroth: if you could address my comment about magic nrs which started this thread, I'd vote for merging it then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be happy about that, I will commit the changes about the magic nrs tomorrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about limiting this PR to porting the
ur_modern_driver
implementation, then using a potential follow-up PR after/if we get more information on what @fmauch mentions?
I'd be fine with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I addressed your suggestion using an enum in the rtde client, because this belongs to the rtde specification. Are you okay with that?
// note that e-stop is handled by a seperate variable | ||
robot_status_resource_.in_error = | ||
safety_status_bits_[UrRtdeSafetyStatusBits::IS_PROTECTIVE_STOPPED] ? TriState::TRUE : TriState::FALSE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I believe we could include in this PR: in_error
should be the union of anything which makes the controller go into an error state. Is IS_EMERGENCY_STOPPED
also a cause of IS_PROTECTIVE_STOPPED
? If not, then it would need to be ||
here I believe.
Any other causes we could add to in_error
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I can add this. Unfortunately I cannot test emergency stops, since I don't have a real robot here, just ursim. I don't know the behaviour of these bits, therefore I cannot tell which bits provide additional information regarding the error state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all of these should be used for that:
IS_PROTECTIVE_STOPPED = 2,
IS_ROBOT_EMERGENCY_STOPPED = 6,
IS_EMERGENCY_STOPPED = 7,
IS_VIOLATION = 8,
IS_FAULT = 9,
IS_STOPPED_DUE_TO_SAFETY = 10
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could make a short trip to the lab these days to test the behavior.
@@ -48,6 +48,29 @@ namespace ur_driver | |||
{ | |||
namespace rtde_interface | |||
{ | |||
enum UrRtdeRobotStatusBits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make this scoped enums as we use this all over the driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then I'd rather switch to constants like
static const uint8_t ROBOT_STATUS_BIT_IS_POWER_ON = 0;
and so on, because accessing the bitsets with scoped enums gets quite ugly..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe @fmauch already added a std::underlying_type<>
somewhere?
IS_POWER_BUTTON_PRESSED = 3 | ||
}; | ||
|
||
enum UrRtdeSafetyStatusBits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scoped enums, same as above
|
||
robot_status_controller: | ||
type: industrial_robot_status_controller/IndustrialRobotStatusController | ||
handle_name: industrial_robot_status_handle | ||
publish_rate: 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be added for the other controller files, as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! Thanks for reviewing
Thanks for iterating @axelschroth 👍 |
if (safety_status_bits_[toUnderlying(UrRtdeSafetyStatusBits::IS_PROTECTIVE_STOPPED)] || | ||
safety_status_bits_[toUnderlying(UrRtdeSafetyStatusBits::IS_ROBOT_EMERGENCY_STOPPED)] || | ||
safety_status_bits_[toUnderlying(UrRtdeSafetyStatusBits::IS_EMERGENCY_STOPPED)] || | ||
safety_status_bits_[toUnderlying(UrRtdeSafetyStatusBits::IS_VIOLATION)] || | ||
safety_status_bits_[toUnderlying(UrRtdeSafetyStatusBits::IS_FAULT)] || | ||
safety_status_bits_[toUnderlying(UrRtdeSafetyStatusBits::IS_STOPPED_DUE_TO_SAFETY)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be taking it too far, but: seeing as this set never changes, what about keeping a "mask" bitset
around, initialised once and then used as:
if ((safety_status_bits_ | in_error_bitset_).any())
...
std::bitset
supports the necessary operators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave that up to @axelschroth It is fine like that from my side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could ignore it in this PR, but seeing as this is run @ the controller's update rate (ie: 125 or 500 Hz), it's 7*500
vs 1*500
operations per second. I'm not sure the compiler will be able to coalesce all the bitset::test(..)
invocations into a single masking operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true... And it should be fairly quick to implement :-)
Thanks again @axelschroth I well test that in the lab ASAP |
Thank you guys for reviewing @gavanderhoorn and @fmauch! |
Testing results: Robot running:
EM-Stop hit:
EM-Stop released:
Protective stop:
After Bootup:
Switched on after bootup (not yet started):
|
|
Co-Authored-By: Felix Exner <felix_mauch@web.de>
robot_status_resource_.drives_powered = | ||
robot_status_bits_[toUnderlying(UrRtdeRobotStatusBits::IS_POWER_ON)] ? TriState::TRUE : TriState::FALSE; | ||
|
||
robot_status_resource_.motion_possible = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a union would be good here, as well. Best achieved by combination with the following safety status bits:
IS_PROTECTIVE_STOPPED = 2,
IS_RECOVERY_MODE = 3,
IS_SAFEGUARD_STOPPED = 4,
IS_SYSTEM_EMERGENCY_STOPPED = 5,
IS_ROBOT_EMERGENCY_STOPPED = 6,
IS_EMERGENCY_STOPPED = 7,
IS_VIOLATION = 8,
IS_FAULT = 9,
IS_STOPPED_DUE_TO_SAFETY = 10
Sorry for coming with that this late, it just came up while testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we check in_error
? Are there any bits in this list which are not in the other?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not propose IS_SAFEGUARD_STOPPED
for in_error
as I wouldn't consider that an error status. However, motion will not be possible, while this is active...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. Other industrial robots will report this as an error I believe.
If we don't, then we can run into the situation where in_error
is false
and motors_on
is true
, but motion_possible
is false
. That would at least be confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought, this would be exactly the purpose of this field. Otherwise it would be redundant, right?
But if that's the way this is usually being handled, I am absolutely fine with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then motion_possible
should be (pseudo):
motion_possible = not (in_error or (IS_SAFEGUARD_STOPPED in robot_status_bits_))
I believe.
Or if we want to be nice: it should also include the status of the external control program.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I will modify the expression for motion_possible shortly. However I don't have time to include the status of the external control program, this condition may be added later if that's okay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, absolutely!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
motion_possible = in_error or (IS_SAFEGUARD_STOPPED in robot_status_bits_)
I guess you mean the negated version of this expression. Motion is not possible if controller is in error or safeguard stop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, of course.
Updated.
I just tested this PR again and noticed one more issue: |
set motion_possible to true only of robot can be actually moved
Great, thank you! I merged your PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it's OK now.
👍 @axelschroth and thanks again for iterating.
Adding a check on the status of the control program can be done in a future PR.
Perfect, I'll give it another HW test tomorrow and then merge it in if everything is fine. Thanks again for your continuous effors @axelschroth |
Nice 🎉 |
Implements issue #32
Notes and limitations:
rostopic echo /robot_status
does not receive further messages.