-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
RFC: Change Stepper API to use step interval #83726
base: main
Are you sure you want to change the base?
Conversation
Did not include it yet, but the |
5090c7c
to
d09f9cb
Compare
The API Change and then relevant changes in shell, drivers, tests should be squashed in one commit. |
include/zephyr/drivers/stepper.h
Outdated
|
||
static inline int z_impl_stepper_run(const struct device *dev, | ||
const enum stepper_direction direction, | ||
const uint32_t velocity) | ||
const uint64_t step_interval_us) |
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 see now that passing step interval again over here is just redundant.
User would set_interval
->enable
->run
const uint64_t step_interval_us) | |
static inline int z_impl_stepper_run(const struct device *dev, | |
const enum stepper_direction direction) |
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.
Yeah thats also true.
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.
But with this you can stop the motor - maybe thats worth keeping?
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.
moved the stopping of the motor to the set_step_interval
function.
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 we need to handle this in a different manner. Setting step_interval to zero in theory means that the motor spins at inf speed, hence setting step_interval to zero should not in theory stop the motor. If anything 0 is -EINVAL.
setting velocity to zero in drivers as of now does not power down the coils and is in hence some sort of hold mode. This could be done using stepper_hold(device, HOLD_MODE)
or stepper_stop(device)
where HOLD_MODE could even include stuff like passive_braking when it is supported by 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.
Right, I reverted that part back setting interval 0
returns -EINVAL
again. For the holding though I suggest maybe making another 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.
Yep it has to be another PR. Was just thinking out Loud :)
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.
Some libraries out there use an extra setVelocity function to set the maximal possible velocity where the api is supporting acceleration/deceleration. Since acceleration ramp is not part of zephyr (yet?), setVelocity as such is redundant to the run parameter at the moment. Also it is not instantly clear to the user what would happen if the stepper motor is already moving. would it then change the velocity? or does it require another call to run
?
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.
Yeah the idea is to decouple setting velocity from run. Run shall only do running in a given direction.
d09f9cb
to
38f96d2
Compare
About the squashing - don't know whats the proper ettiquette for it. Did not do that many treewide changes as of now. |
when we recently shifted to I would have had one commit for |
You should really squash the API change with the code update to use the new API, basically no commit should break the build. Doc update can be on its own. In this case it does make it harder to review but that's how it should be done. |
38f96d2
to
7b61f11
Compare
static inline uint32_t tmc5xxx_calculate_velocity_from_hz_to_fclk(uint64_t velocity_hz, | ||
uint32_t clock_frequency) | ||
static inline uint32_t | ||
tmc5xxx_calculate_velocity_from_step_interval_to_fclk(uint64_t step_interval_us, |
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.
Nit: can the argument name be shortened in order to atleast have the function name and return type in a single line
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.
Needed to change the function name for that to work, done.
@@ -20,10 +20,10 @@ typedef int (*stepper_timing_source_init)(const struct device *dev); | |||
* @brief Update the stepper timing source. | |||
* | |||
* @param dev Pointer to the device structure. | |||
* @param velocity Velocity in microsteps per second. | |||
* @param step_interval_us The new step interval in microseconds. |
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.
Step interval in microseconds
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.
Done.
include/zephyr/drivers/stepper.h
Outdated
* @details If velocity > 0, motor shall be set into motion and run incessantly until and unless | ||
* stalled or stopped using some other command, for instance, motor_enable(false). | ||
* This function is non-blocking. | ||
* @details The motor shall be set into motion and run incessantly until and |
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.
continuously instead of incessantly
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.
Done.
8cadbdf
to
facdd26
Compare
{ | ||
const struct tmc5041_stepper_config *config = dev->config; | ||
const struct tmc5041_config *tmc5041_config = config->controller->config; | ||
const uint32_t clock_frequency = tmc5041_config->clock_frequency; | ||
uint32_t velocity_fclk; | ||
int err; | ||
|
||
velocity_fclk = tmc5xxx_calculate_velocity_from_hz_to_fclk(velocity, clock_frequency); | ||
if (step_interval_us == 0) { |
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.
return -EINVAL?
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.
yeah missed that one. done :^)
{ | ||
__ASSERT_NO_MSG(clock_frequency); | ||
__ASSERT_NO_MSG(step_interval_us); | ||
|
||
uint32_t velocity_hz = 1e6 / step_interval_us; |
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.
Max possible speed here is then limited 1MHz, which is not much since 256 usteps * 200 steps/rev = 51200 usteps/rev
, so over here we will be limiting the speed to somewhere around 2rps
. At this point i can only see that we need to allow both the interfaces.
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.
Maybe use nanoseconds instead of microseconds?
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.
Also 1e6/51200 is about 20rps, or am I missing something?
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.
No that's correct, although 20 rps is still i would say on the slow speed spectrum.
Let's do it this way since step_interval
serves majority of the drivers, let's keep it, i think microseconds timebase is good enough.
I think going in nanoseconds timebase would just be to accomodate drivers like tmc5041, or?
For drivers like tmc5041, this function shall return -ENOTSUP, as there is also a way to set speed via ramp as can be seen over here
int tmc5041_stepper_set_ramp(const struct device *dev, |
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.
There are also 0.9° steppers which are also very common especially for projects requiring precise positions. This would half the RPM additionally. But on the other hand, the use case where you step at 1/256 uSteps and want to achieve very fast speeds at the same time are very rare. In this case dynamic microstepping can be used, where you change the uStep resolution for slow and fast velocities can be used (this would be responsibility of the application code, since it would introduce to much complexity into the stepper driver in zephyr). This is what we are doing in OpenAstroTech. We switch to something like 1/32 for fast slew movements and then back to e.g. 1/128 for slow and precise tracking rotations.
In general tmc2209 needs a STEP pin input timing of at least 100ns. Disregarding other factors this would result in maximal frequency of 10MHz.
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.
so i suppose we need to go to nanoseconds timebase.
For controllers like tmc5041 with internal ramp control we cannot ascertain step_interval
due to acceleration/deceleration, we can more or less only set_max_velocity
, also the reason why this API was designed like this.
stepper_set_step_interval(const struct device*, uint64_t step_interval_nsec)
it is :-)
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.
For drivers like tmc5041, this function shall return -ENOTSUP, as there is also a way to set speed via ramp as can be seen over here
How would that condition look like? The issue is if you want to be faster then 1 step_interval_us but since its a uint64_t you can not attempt to go faster, right?
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.
Sorry it is -ENOSYS, i mean that the tmc5041 driver shall not implement stepper_set_step_interval, ofcourse with uint64_t tmc5041 could go faster, what i was trying to say that when i set a step interval, i expect that every step shall be exactly that interval apart, which cannot be ascertained with drivers like tmc5041 which have internal ramp motion controller which is reponsible for stepping intervals.
Hence the stepper_set_step_interval
shall not be supported by the tmc5041 driver.
Change the stepper API to instead of changing the stepper speed based on the velocity in microsteps per second to use the delay in usec between successive steps. Also remove the velocity from the `stepper_run` function as typical API usage is enable -> set step interval -> run. Signed-off-by: Fabian Blatz <[email protected]>
Migrates the peripherals documentation to the new step interval based APi instead of the velocity one. Signed-off-by: Fabian Blatz <[email protected]>
Adds a two bullet points explaining the change of the velocity based API towards an step interval one. Signed-off-by: Fabian Blatz <[email protected]>
facdd26
to
f194f0b
Compare
static inline int z_impl_stepper_set_max_velocity(const struct device *dev, | ||
const uint32_t micro_steps_per_second) | ||
static inline int z_impl_stepper_set_step_interval(const struct device *dev, | ||
const uint64_t step_interval_us) | ||
{ | ||
const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; | ||
|
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.
In conjuction to #83726 (comment)
if (api->set_step_interval == NULL) { | |
return -ENOSYS; | |
} |
As discussed in the original RFC issue: Change the stepper API to accept the interval to wait at a minimum in between executing consequtive steps. This allows for a more granular control then the previous interface.
Resolves #83591