Skip to content
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

Add service to clear errors. #14

Closed
wants to merge 3 commits into from
Closed

Conversation

liborw
Copy link

@liborw liborw commented Mar 15, 2024

Service that sends Clear_Errors command, fixes #13 and #9.

Usage:

$ ros2 service call /odrive_axis0/clear_errors odrive_can/srv/ClearErrors "identify: 0"

@liborw liborw changed the title Add service to clear errors, fixes #13 and #9. Add service to clear errors. Mar 15, 2024
Copy link
Member

@samuelsadok samuelsadok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to (or instead of?) an explicit service call to clear errors, I think it would be nice to autoclear errors when entering CLOSED_LOOP_CONTROL. (Especially since on ODrive S1 this is required to re-enable the brake resistor after undervoltage.)

To do that, you could add this snippet to ODriveCanNode::request_state_callback(), before the state request is sent:

    struct can_frame frame;
    frame.can_id = node_id_ << 5 | CmdId::kClearErrors;
    frame.can_dlc = 0;
    can_intf_.send_can_frame(frame);

(if you're already set up for testing it would be cool if you could try this)

In fact, do you feel it's strong requirement for ClearErrors to be an explicit call? If yes, see my other comments in the review, but if not, it might be better to stick to autoclearing until explicit clearing is requirement for someone.

src/odrive_can_node.cpp Outdated Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
frame.can_id = node_id_ << 5 | CmdId::kClearErrors;
{
std::unique_lock<std::mutex> guard(axis_state_mutex_);
write_le<uint8_t>(identify_, frame.data);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can hardcode the identify field to 0 instead of exposing it to ROS. The reason is that this field is intended for interactive commissioning, whereas the scope of the ROS node is intended to be runtime (rather than setup-time).
For interactive commissioning, there are ROS-independent example scripts linked here.

(This also allows to remove clear_errors_mutex_)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about auto clearing, I'm just starting with odrive by the way. My idea is that when I start the some controller, I would clear errors as I know what I'm doing, but I do not want them cleared during the run as they might be sign of something bad happening. However, autoclearing could be optional. I will implement your sugestions in this PR...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I don't mean autoclear during the run (while the motor is active). What I mean is, your ROS application explicitly requests a state change from IDLE to CLOSED_LOOP_CONTROL to enable the motor. Since this request is explicit, it means that by this time your application had an opportunity to read potential errors and to decide that it's ok to re-enable the motor. Therefore I think it makes sense for the ROS node to clear errors by itself on this transition.
Once the ODrive is in CLOSED_LOOP_CONTROL, it will go back to IDLE by itself as soon as there's a new error.

In addition, on the ODrive S1, clearing errors makes sure the brake resistor is active (in case it previously got disarmed due to undervoltage). Requesting CLOSED_LOOP_CONTROL otherwise causes a BRAKE_RESISTOR_DISARMED error. To avoid this error, I think in this case it's especially nice if the ROS node sends ClearErrors by itself.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither did I. Actually the break resistor is good example, when the state change command implicitly clears errors, you would newer know about the undervoltage, with explicit call to clear errors you can chose to ignore it or somehow deal with it...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In both cases the user can check errors before entering CLOSED_LOOP_CONTROL, and handle them accordingly. The usage would be like this:

  • Without auto-clearing in ROS node:
    1. Check errors
    2. Clear errors
    3. Request CLOSED_LOOP_CONTROL
  • With auto-clearing in ROS node:
    1. Check errors
    2. Request CLOSED_LOOP_CONTROL

I think what you might be referring to is more about educating the user, rather than client code capability: An uninformed user might indeed miss errors in the second variant, but an informed user can read them in both cases.

However regarding that, I should clarify the semantics of errors and ClearErrors: The error variable disarm_reason does not prevent the ODrive itself from re-entering CLOSED_LOOP_CONTROL. The only reasons to call ClearErrors are:

  • re-enable brake resistor (S1 only)
  • be sure that when disarm_reason indicates an error at a later time, it was newer than the last call to ClearErrors
  • make the LED not be red

This change in semantics was a conscious choice that dates back to the early days of odrivetool: Everyone just got used to calling odrv0.clear_errors() before odrv0.axis0.requested_state = AxisState.CLOSED_LOOP_CONTROL, without even looking at the errors. So we decided to do it automatically on the ODrive, but just missed the three points above.

Copy link
Member

@samuelsadok samuelsadok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now. The merge conflicts are probably because some files recently got moved to "odrive_node/" and "odrive_base/". Do you mind taking a look?

@kenconnor kenconnor mentioned this pull request Sep 9, 2024
@kenconnor
Copy link

@samuelsadok , @liborw
Could you give me the permission to push so I can take over this PR?
I think I have fixed the conflict and I would like you to review my commits.

@samuelsadok
Copy link
Member

Thanks for taking over. This PR seems to be abandoned, so I would recommend to just open a new PR from your own fork and we can close this one when done. I see you already did that but then closed it again for some reason?

(Btw quick comment from a preliminary look: I saw quite a bit of formatting noise (whitespace changes). It's better to keep that out of the PR, or if your IDE insists, put it in a separate commit at least.)

@kenconnor kenconnor mentioned this pull request Sep 12, 2024
@kenconnor
Copy link

@samuelsadok
I closed #25 because it is better to use existing PR (and I did not use merge, making logs messy).
And now I opened new PR #27 .
I would appreciate it if you take a look at it.

@samuelsadok
Copy link
Member

Superseded by #27

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How to reset errors
3 participants