-
Notifications
You must be signed in to change notification settings - Fork 13
Add example for can with watchdog timer handling #3
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
base: master
Are you sure you want to change the base?
Conversation
samuelsadok
left a comment
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 can see the point of demonstrating watchdog feeding. I would actually argue that it can be added to can_simple.py, because I expect that it's possible by adding only ~5 more lines of code or so. And feeding the watchdog is not a special message, it's just sending setpoints continuously, which most users would do anyway. This would save us from having to maintain two very similar scripts.
Can you make a version that addresses the comments below, but integrates it into can_simple.py?
examples/can_simple.py
Outdated
|
|
||
| while True: | ||
| t = time.time() | ||
| velocity_setpoint = math.sin(2 * math.pi * f * t) # turns / s |
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 do not really comment on the sinusoidal signal we supply the ODrive with, but I think its calculation should be straightforward. I also imported the whole module math instead of importing sin and pi. Looks OK to me.
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.
since the math is not what we're showing off, we can compress this into one line. Also use time.monotonic() instead of .time().
| velocity_setpoint = math.sin(2 * math.pi * f * t) # turns / s | |
| velocity_setpoint = math.sin(2 * math.pi * 0.5 * time.monotonic()) # turns / s |
examples/can_simple.py
Outdated
|
|
||
| while True: | ||
| t = time.time() | ||
| velocity_setpoint = math.sin(2 * math.pi * f * t) # turns / s |
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.
since the math is not what we're showing off, we can compress this into one line. Also use time.monotonic() instead of .time().
| velocity_setpoint = math.sin(2 * math.pi * f * t) # turns / s | |
| velocity_setpoint = math.sin(2 * math.pi * 0.5 * time.monotonic()) # turns / s |
examples/can_simple.py
Outdated
| # Define an asynchronous listener to handle and print encoder feedback | ||
| def encoder_listener(msg): |
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.
| # Define an asynchronous listener to handle and print encoder feedback | |
| def encoder_listener(msg): | |
| # Handler for incoming CAN messages to print encoder feedback | |
| def on_rx_message(msg: can.Message): |
examples/can_simple.py
Outdated
| Example for controlling an ODrive via the CANSimple protocol with watchdog handling. | ||
| Puts the ODrive into closed loop control mode, sends a velocity setpoint of 1.0 | ||
| and then prints the encoder feedback. | ||
| Puts the ODrive into closed loop control mode, sends periodic sinusoidal velocity | ||
| setpoints, and asynchronously prints the encoder feedback. The regular velocity | ||
| setpoint update resets the watchdog, which is a safety feature that disengages | ||
| the axis if no valid commands are received within the configured timeout period, | ||
| avoiding uncontrolled behavior. |
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.
The way I think about it, watchdog handling is just a side effect of continuous setpoints. There's nothing that's explicitly for watchdog handling and it works just as well with the watchdog disabled. So we don't have to mention it in the headline and most of the description can stay as it was (except that it's now a sine function instead of constant vel).
You can mention the watchdog as a side thought in just a small paragraph, such as:
If the watchdog is enabled on the ODrive, it is fed implicitly by the continuous velocity setpoint message and the motor will stop when the script is terminated. The heartbeat interval should be shorter than the watchdog timeout to ensure timely confirmation of the axis entering closed loop control mode without triggering the watchdog.
…_rx_message, and updated docstring for watchdog handling and assumptions
|
Hello, Samuel! I apologize for the long delay in responding, it took quite long to return to this. Thank you for your suggestions regarding the docstring, monotonic time, math simplification, and renaming the notifier callback. They all make sense. I believe I have addressed all of them in the latest commit. Please take a look when you have a moment! |
|
Looks good now! Can you confirm on real hardware that the script works as intended and the axis moves at sinusoidal velocity? For these demo scripts we don't have automated tests right now. |
I believe it might be useful to add an example demonstrating how to handle the watchdog timer. While I understand the motivation for keeping the original
can_simple.pyexample truly simple, I consider it necessary to illustrate safe practices when working with motors and to demonstrate the concept of the watchdog timer and its proper handling. I did not find a similar example in this repository; please direct me to it if I have overlooked one, and I apologize in advance.Note: This example uses the deprecated
bustypeparameter for bus initialization, consistent with existing scripts. This should be updated tointerfaceif my prior pull request addressing the deprecation is accepted and merged.The script has been tested on Python 3.14 with python-can 4.4.0.
I welcome feedback and am available to make further adjustments. Thank you for considering this contribution.