zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.61k stars 6.5k forks source link

RFC: Introduce Stepper Motor Controller API #68547

Closed jilaypandya closed 1 month ago

jilaypandya commented 8 months ago

Introduction

Zephyr at present does not have a provision to control stepper motors. Stepper Motor Controllers do have a set of common functions which can be bundled together in a API as presented in this PR. https://github.com/zephyrproject-rtos/zephyr/pull/68774

The original RFC was created on the basis of thisPR https://github.com/zephyrproject-rtos/zephyr/pull/68548, however, that idea has been dropped.

Problem description

There are quite a few stepper motor controllers out there which if upstreamed could benefit the community hugely, however, there is a no API present in the Zephyr for such controllers as of now.

Proposed change

This RFC aims to introduce a API allowing generalised access to stepper motor controllers along with establishing a common understanding as to how these devices should appear in a device tree.

Detailed RFC

The stepper motor controller api provides following base functions: Stepper Functions Diagram

The API offers a collection of functions to control the motor's movement in both absolute and relative positions. Stepper Functions Diagram


Device Tree Bindings

The DTS snippet below aims to depict the actual hardware setup i.e. a dual stepper motor controller is connected to a spi controller

In the example below, my_motor_controller is a motor controller node. All generic motor controller properties should be put in stepper-motor-controller.yaml. Presently some generic stepper motor device properties have been included in stepper-motor-controller.yaml.

&spi_controller {
  status = "okay";

  my_motor_controller: my_motor_controller@0 { 
    status = "okay";
    compatible = "my_motor,controller";
    reg = <0>;
    #address-cells = <1>;
    #size-cells = <0>;

    x_motor_controller: x_controller@0{ 
      status = "okay";
      reg=<0>;
      micro-step-res = <256>;
      stall-guard-setting = <6>;
    };

    y_motor_controller: y_controller@1{ 
      status = "okay";
      reg=<1>;
      micro-step-res = <128>;
      stall-guard-setting = <0>;
    };
  };
};

Bindings Example for trinamic TMC5041 motor-bindings

Dependencies

This change should not disrupt any existing component within the project.

github-actions[bot] commented 8 months ago

Hi @jilaypandya! We appreciate you submitting your first issue for our open-source project. 🌟

Even though I'm a bot, I can assure you that the whole community is genuinely grateful for your time and effort. 🤖💙

jilaypandya commented 8 months ago

@dipakgmx @FlorianGuhl-zeiss @rexut @tobiaskaestner

xingrz commented 8 months ago

I'm wondering, is this API also applicable to BLDC motors?

jilaypandya commented 8 months ago

I'm wondering, is this API also applicable to BLDC motors?

Yeah, to an extent. The inherent property of a stepper motor allows the motor to be driven in a fixed amount of steps. Hence, you have some positioning by default. Whereas i suppose a bldc motor would require maybe a hall sensor, quad encoder or some other mechanism for position feedback. Probably this API would have to be expanded a bit in order to allow the input from a positioning sensor. Exactly because of these questions we have kept the api in its early stage to bare minimum and just included stepper motors

yashi commented 8 months ago

Hi @jilaypandya,

Thank you for proposing Motor API. I've been using ST L6480 for a while. Here is a copy of the driver https://github.com/yashi/st-l6470

I'm by no means an expart of motors and motor drivers. But I've been using my device driver with ROS 2.

I'm writing this because I was confused by your definition.

  • Business or proprietary logic could be implemented using stepper motor device apiand does not have to be upstreamed
  • Community benefiting implementation of a stepper motor controller could be upstreamed

As I now understand, the first stepper motor device api is an API for a stepper motor itself. So your api defiens motor_run(), motor_stop(), motor_set_position(), etc.

The second API, stepper motor controller, is a common interface for motor controllers?

So Zephyr users will have

Am I understanding it right?

jilaypandya commented 8 months ago

Hi @yashi, thanks for reviewing the RFC, you are right, the idea is to separate motor functions from motor controller specific functions. The approach is to treat a motor controller as a bus(for instance SPI) controller, and a bus normally offers functions such as read, write and reset. These are offered by motor controller api

One might not necessarily want to upstream the implementation of a motor device driver, however, as shown here, a generalized implementation based on the controller could be upstreamed as well, serving as a good starting point

jilaypandya commented 7 months ago

Update

Another way to write stepper motor drivers would be as per this PR https://github.com/zephyrproject-rtos/zephyr/pull/68774.

To summarize, there are two approaches:

  1. bus:motorbased approach where a stepper_motor_controller would be a peripheral offering bus:motorand stepper_motor_devicewould appear as a device on this bus.https://github.com/zephyrproject-rtos/zephyr/pull/68548
  2. child-bindingsbased approach where Stepper-Motor-Controller has stepper-motor and corresponding properties in child-bindings https://github.com/zephyrproject-rtos/zephyr/pull/68774
bjarki-andreasen commented 7 months ago

I think the additions in this PR are too high level compared to the simplicity of a stepper motor. A stepper motor can:

This is all that should be exposed to the user regarding runtime features, hardware properties are const and should be in the devicetree, like

Anything more complex than this this should be part of a higher level subsystem :) A subsystem which could cover more "positional" motors, like BLDCs and servos, where the user would set an absolute rotational change, which would then be translated into a number of steps for a stepper motor, and an angle for a servo :)

carlescufi commented 7 months ago

Architecture WG:

jilaypandya commented 7 months ago

Update

There is merit in restructuring this API into a motor api, atleast at this point of time i dont have further arguments in defense of keeping this API strictly for Stepper Motors.

Each and Every motor would be instantiated as a device in itself. Thanks @bjarki-trackunit and @gmarull for showing as to how this can be achieved.

So I'll be starting with refactoring soon. However, before i start amending the PR #68774, i would like to have a consensus on how the bindings & api should look like.

Bindings

motor-bindings

API

The API should be consisting of the following functions atleast:

struct motor_position_in_degrees{
     int32_t integer_part,
     int32_t fractional_part,
};
  1. Enable/Disable Motor enable_motor(const struct device* motor, bool enable )
  2. Set current Angle motor_set_current_angle(const struct device* motor, const motor_position_in_degrees angle)
  3. Get current Angle `motor_get_current_angle(const struct device motor, motor_position_in_degrees angle)
  4. Set Absolute Angle motor_set_angle(const struct device* motor, const motor_position_in_degrees angle)
  5. Increment/Decrement from Current Angle motor_rotate(const struct device *dev, const motor_position_in_degrees angle)
  6. Freewheeling motor_freewheel(const struct device *dev, enum direction)
yashi commented 7 months ago

It's nice to have a generic motor API. But does it mean that you have to convert angle in float to steps when you want to control your stepper motors with steps?

FYI, Sensor API explicitly avoids float:

Values Sensor stable APIs return results as sensor_value. This representation avoids use of floating point values as they may not be supported on certain setups.

BTW, I'm not against using float at all.

bjarki-andreasen commented 7 months ago

Some comments:

Set current Angle motor_set_current_angle(const struct device* motor, const float angle)

APIs should use integer types, floating point calculations are slow, especially for soft float devices, and not supported in ISRs. They are generally an optional application level service, drivers and APIs should not use them. Replace with fixed point value, like microdegrees. Additionally, values that are copied should not be const, there is no reason to not allow the value to be reused from within the function call ;) This applies to all of the APIs.

Get current Angle `motor_get_current_angle(const struct device motor, float angle)

This should be renambed to motor_get_angle() :) "current" is implicit in any API, like rtc_get_time(), plus it matches the expectations of motor_set_angle()

Increment/Decrement from Current Angle motor_rotate(const struct device *dev, const float angle)

Not certain this one is needed, since it can be fulfilled by using motor_get_angle() and motor_set_angle() (get current angle, add angle, set angle)

Freewheeling motor_run(const struct device *dev, enum direction)

This API should take an angular velocity rather than direction, like motor_run(const struct device *dev, int32_t uds) (uds == micro degrees per second). Uncontrollably rotating a motor in a direction does not seem like desired behavior :)

We need to include synchronization within the API, currently, if a user wants to move two motors at the same time, they must write their desired angles using motor_set_angle(), then constantly poll both motors until they both reach their desired rotation, this is inefficient :)

A function like motor_await_angle(const struct device *dev, int32_t ud, callback_t callback) (ud == micro degrees) allowing the application to set a desired angle, then get a callback once the angle is reached. or even better, make an async variant of motor_angle_set(), motor_angle_set_async(const struct device *dev, int32_t ud, callback_t callback)

jilaypandya commented 7 months ago

@yashi

It's nice to have a generic motor API. But does it mean that you have to convert angle in float to steps when you want to control your stepper motors with steps?

Yes, the driver will have to convert the angle to steps based on the information such gear_ratio & steps_per_revolution.

@bjarki-trackunit

Freewheeling motor_run(const struct device *dev, enum direction)

This API should take an angular velocity rather than direction, like motor_run(const struct device *dev, int32_t uds) (uds == micro degrees per second). Uncontrollably rotating a motor in a direction does not seem like desired behavior :)

There is a reason, why i have not included speed yet in the API. Certain drivers allow defining a ramp via various speed parameters. At this point i can only think of passing these parameters via device tree. Rotating motor incessantly in a direction and detecting stall is actually how homing can be done with certain drivers. Also for drones this would be required. Probably there could be a set_speed function defined seperately and we introduce both the functions motor_freewheel(const struct device *dev, enum direction) & motor_run(const struct device *dev, int32_t uds) (uds == micro degrees per second) as you mentioned

rexut commented 7 months ago

@yashi

It's nice to have a generic motor API. But does it mean that you have to convert angle in float to steps when you want to control your stepper motors with steps?

Yes, the driver will have to convert the angle to steps based on the information such gear_ratio & steps_per_revolution.

@jilaypandya:

That should never be the job of e simple low level HW driver and / or that level of any kind of a motion subsystem (framework) – keep it as simple as possible. A stepper motor is characterized by steps, never the angel. An angle is only the result of a mathematical equation, nothin else. So, when you talk about a motor api that provide access to a the special type of motors, the stepper, I as a user expect to let count steps by the API behind no angles. Why? It really simple. I as the user wants to hold the control over this mathematical equations, because there could be specific (my) system that needs non linear engle to stepp transfer functions. So a stupid low-level system that only translate angels to steps with a linear transfer function is completely useless.

The other point why you have to (really must) avoid floats in low-level APIs is the portability to systems that need a complete fix point arithmetic. It's not the job of a low-level API to force the system specification of systems you currently can not known. BTW. even this is the reason why the senso API has never transfer sensor values as float!

yashi commented 7 months ago

Yes, the driver will have to convert the angle to steps based on the information such gear_ratio & steps_per_revolution.

Hmm... It might not be a good idea for small MCUs. As @bjarki-trackunit noted conversions involving float are expensive for MCUs.

Can we have a layer for Stepper motors and a layer of unified Motor API on top of it? If a MCU only need to control steps, we can use Stepper motor API (without paying extra CPU cycle). If users want to control various motors with unified API, they can pay extra CPU power for it. @bjarki-trackunit, why did you only want to have Generic motor API? The current API seems to kill one of features of the stepper motor, Stepping. Wouldn't it be reasonable to have layers like the Storage API?

jilaypandya commented 7 months ago

The input angle would be in fixed point arithmetic like in sensors. However, if the input is in micro_degrees the input could be very well in int

@rexut The conversion of angle to steps would always follow the same equation for each stepper motor, which would be somthing like this motor_data->target_position = ((angle * motor_config->motor_gear_ratio * motor_config->motor_steps_per_rev) / 360)

Probably we could add such an inline function directly in the header. something like

struct motor_position_in_degrees{
     int32_t integer_part,
     int32_t fractional_part,
};
stepper_motor_get_steps_from_angle_in_udegrees(const struct device* dev,  const struct motor_position_in_degrees* position, int* steps);
bjarki-andreasen commented 7 months ago

@rexut

Users will want to be able to exchange types of motors, without changing the application. Think of an application controlling a CNC router or 3D printer. Whether stepper motors or BLDCs are used makes no difference to the application, it simply wants the rotation to be as close as possible to the desired angle. All types of servo motors have some tolerance (resolution), for steppers, this is the nearest step, for BLDCs, this would be the encoders resolution. There is no actual value in setting a step, rather than the nearest angle. if the angle happens to line up perfectly with a step, it is just as accurate as setting it in steps...

The motor API is not targeting the motor directly, its targeting the motor controller. The purpose of the user facing APIs is to be as simple and portable as possible. Splitting the specific motor technology into separate APIs if this does not provide additional utility is antithetical to this goal :(

bjarki-andreasen commented 7 months ago

@jilaypandya

struct motor_position_in_degrees{
     int32_t integer_part,
     int32_t fractional_part,
};

is nearly identical to (lower min/max values, but we will have to handle rollover event gracefully in any case)

int64_t fractional_parts;

it will just lead to unnecessary conversions from the struct format to the integer format, like https://github.com/zephyrproject-rtos/zephyr/blob/5dad8d72ee739df5ef1b0369a5cf45ff800dec12/drivers/sensor/bmi323/bmi323.c#L100-L109 its not even faster if you want to convert it to floating point format

float angle = ((float)fractional_parts) / 100000;

is identical to https://github.com/zephyrproject-rtos/zephyr/blob/5dad8d72ee739df5ef1b0369a5cf45ff800dec12/include/zephyr/drivers/sensor.h#L1197-L1200

rexut commented 7 months ago

@rexut

Users will want to be able to exchange types of motors, without changing the application. Think of an application controlling a CNC router or 3D printer.

Exactly, that's the goal. For this we need a "Common Motion Subsystem for Zephyr" – not only a simple motor / stepper / (BL)DC / FOC API. Let's start with one of them and yes let's call it Low Level Stepper API. It handle the (Stepper) Motor Busses, propagate the number and characteristics of each configured (Stepper) Motor as defined in DTS, and so on. The Motion Subsystem then have to handle all the common mathematics so that users application can be completely independent of hardware specifics. Yes, with such kind of Motion Subsystem you will have a chance to change a stepper motor to BLDC motor with encoder or even better example from the wilde life: you wants to go out from your lab with a few milli-Nm motors to the real heavy industry with the big power kilo-Nm motors. In this case you change the parameters in Low Level (Stepper) Motor API.

That's all a dream, only a idea and not yet part of this RFC as I understand. We should not dream of it. We should come together and create some motor specific Low Level APIs and in parallel the new "Motion Subsystem for Zephyr". Where are NXP / TI / STM / Trinamic (AD) experts for their motor divers technology? Even the missed "Motion Subsystem for Zephyr" is the reason why other RTOS then Zephyr are sooo successful in the industry.

Time to change! Time work together!

Whether stepper motors or BLDCs are used makes no difference to the application, it simply wants the rotation to be as close as possible to the desired angle. All types of servo motors have some tolerance (resolution), for steppers, this is the nearest step, for BLDCs, this would be the encoders resolution. There is no actual value in setting a step, rather than the nearest angle. if the angle happens to line up perfectly with a step, it is just as accurate as setting it in steps...

That's true for the motors itself as a single white box in an complex system of elektronics, mechanics, optics, whatever. All subsystems will have an coupling in between and rarely with a linear transfer function only. So in my world (my be I'm completely wrong here): a stepper motor is defined by steps per revolution (angle is mathematical ratio), a BLDC / FOC / AC motor is defined by rotation per minute and only with a encoder system really usable for position – then I see exactly the same: swap steps with pulse –> pulses per revolution (angle is mathematical ratio).

So there is no reason why a Low Level (Stepper) Motor API should handle angels. It's enough to handle steps for stepper and speed for other motors and (later in future) pulses for encoder. The (not existent) "Motion Subsystem for Zephyr" have to handle this translation. And a generally valid formula can be used per default (e.g. steps = f(angle) = f(x) = a * x). The user on application level have to decide if he needs another transfer function (e.g. a complex motion profile with anti-slip compensation). Also the "Motion Subsystem for Zephyr" would have a special component for acceleration and braking behavior when there is no "Intelligent Motor Controller" on the motor bus (e.g. instead a fancy and expansive Trinamic chip your DC or stepper motor will driven by simple and cheap H-bridge). Then you need the complete speed and stepp control in software. Should this part of a Low Level (Stepper) Motor API. I think no, or not?

The motor API is not targeting the motor directly, its targeting the motor controller. The purpose of the user facing APIs is to be as simple and portable as possible. Splitting the specific motor technology into separate APIs if this does not provide additional utility is antithetical to this goal :(

I'm not really sure, what this RFC really target, too. A specific motor controller or a collection of stepper motors or a mixture of both? I think, that should be clarified.

rexut commented 7 months ago

The conversion of angle to steps would always follow the same equation for each stepper motor, which would be something like this motor_data->target_position = ((angle * motor_config->motor_gear_ratio * motor_config->motor_steps_per_rev) / 360)

@jilaypandya and how can a upper level software avoid this formula when this mathematic is not applicable for the user, for systems you currently can not have in mind? Again, steps are the main characteristic for discret controlled actuators (stepper) and speed (better electrical current) for continuously controlled actuators (DC/AC motors). Special cases are linear motors, then it depends on construction. The angle is a representation of characteristic parameters and should be handled one level above a low level (stepper) motor API. The low level API have to provide all the information (e.g. steps per revolution) so that a higher level API can do this calculation. The higher level API can also provide application code with optional callbacks to change the default mathematics.

bjarki-andreasen commented 7 months ago

@rexut To reiterate, the motor API is for motor controllers, which use higher level APIs to control the motors. The author specifically included this controller https://www.analog.com/media/en/technical-documentation/data-sheets/TMC5041_datasheet_rev1.16.pdf , it implements a higher level API which matches the API in this PR.

The aim here is to control the motor by interacting with a motor controller, and motor controllers are designed to provide a higher level API to abstract the underlying technology away.

We can (and should) write a few generic drivers which support L298N style interfaces, and TB6600 style interfaces, which implement the motor API. The value this adds to the user is immense, and I am yet to hear why we should force this work onto the user, when a generic driver can do the work (most likely safer and better due to reuse). The author already did this in the PR #68774

jilaypandya commented 7 months ago

Hi @rexut,

Let me classify probably the drive shafts in a system, there are:

  1. Motor Shaft
  2. Final/Transmission Shaft

Now if you have a non linear transmission from Motor Shaft to Final Shaft you can use the motor api considering that the input_angle is motor_shaft angle and then the gear_ratio is "1". Further calculation can be done as the system requires in application code.

If you have a linear transmission then you can use motor_api for the Final Shaft angle or Motor Shaft angle. I hope this addresses your concerns?

yashi commented 7 months ago

The aim here is to control the motor by interacting with a motor controller, and motor controllers are designed to provide a higher level API to abstract the underlying technology away.

I think this assumption is the root cause of these disagreements. Yes, there are some higher-level motor controllers that hide motor technologies. However, a motor controller is, by definition, a piece of hardware that drives the motor, thus called a "motor driver" (do not confuse it with device drivers in software though). Many motor controllers for stepper motors are indeed controled by steps and do not hide the underlying technology.

Providing angles-only APIs for users of stepper motors is just adding an unnecessary layer and making the whole thing complex without any gain.

Please note: I do agree that a higher-level API (which hides underlying technologies) provides great benefits for users. We should have a unified general motor API. I just want to say that we should also provide a stepper motor API along with it.

jilaypandya commented 7 months ago

Update

tobiaskaestner commented 7 months ago

First of all, I think Zephyr really opens itself towards a lot of applications by introducing some sort of motor control. Having scanned through the discussion up to this point I think it makes a lot of sense to start small and for that matter specific to the control of stepper motors. Different motor types, e.g. Stepper vs DC/BLDC vs. Servo vs AC have typically different fields of applications and thus different physical parameters that the operator may wish to control, i.e.

From this it seems quite (if not too) ambitious trying to come up with a have-every-need-covered-from-the-get-go API.

Instead having a working stepper motor control API to cover everything from SW bit-banging a discrete H-bridge to all singing and dancing trinamic ICs and all the Allegros and TI DRV88xx inbetween would already be a fantastic starting point.

From such simple drivers (integer values close to the HW to count steps) a higher level motion (sic!) control subsystem may eventually emerge to also allow for closed-loop control via limit switches or algorithms for ramps etc. It will then become the responsibiltiy of this motion subsystem to combine whatever motor driver and sensor feedback is needed for a particular application (position control, rpm control, angle control, ...) So eventually doing positioning with a BLDC and a rotary encoder becomes realizable, yet later and without blocking a useful addition of a stepper motor control API today.

jilaypandya commented 7 months ago
  • @bjarki-trackunit At this point using angle_input and having a unified motor api seems to be a long shot. In the first draft i would like to limit the discussion to API for stepper_motor_controllers.

@tobiaskaestner Thanks for your input. As i had mentioned earlier. In the first step i am only targeting to introduce a stepper motor controller api.

Check out the Stepper Motor Controller API over here.

carlescufi commented 7 months ago

Architecture WG:

jilaypandya commented 7 months ago

@carlescufi I would like to keep the reference to stepper motor controllers, because there are high end controllers like the ones from trinamic and st (which I know of) who have in-built Sensorless Stall Detection, Absolute Positioning and so on. So the API we are presenting is targeting these kind of controllers alongwith basic controllers like DRV8825 which basically only have a STEP/DIR Interface

wkhadgar commented 4 months ago

Nice to see that motors are getting some attention, I was wondering why there wasn't yet any sort of stepper motor drivers in Zephyr since a lot of projects benefit of them.

How's the progress of this RFC? I would be glad to contribute with some drivers as well, I'm currently working on a motorized equatorial mount and having Zephyr as the framework would ease so much of the development. I also have plans to add ASCOM integrations as part of the subsys in the future if possible, but it would need some groundwork like this motor RFC. Would be really nice to get a follow-up on the progress of this RFC!

jilaypandya commented 4 months ago

Hi @wkhadgar, The API is kind of halfway there. Most probably, it would be brought up in one of the architecture WGs and then we will be able to finalize if it can be merged in the current state or not with an implemented Driver alongwith it.

wkhadgar commented 4 months ago

If I can be of any help, please let me know! Really refreshing to see it will be ready soon!

adrienbruant commented 4 months ago

As a user of stepper motors on zephyr, I'm excited to see interest in this area. Our approach was super ad hoc so there isn't much I can share except our experience.

The discussion seems to lean towards introducing a low level stepper API, to be eventually integrated in a broader motion subsystem. I would like to add a few points to this discussion.

More states than just enable/disable

I see you've considered enable/disable, which I understand would mean:

You might want to do this instead:

STEP/DIR

We should aim for an API that works well for STEP/DIR controller. This is a common electrical interface to many controllers. The DIR signal is generated with GPIO and STEP can be generated with a hardware timer/counter/pwm (whatever they call it on your MCU). I don't see anything problematic in this RFC but it's just something to keep in mind.

Async API

Not every stepper controller is as smart the TMC5041 and integrates an acceleration curve. To apply an acceleration / deceleration, the future motion subsystem will want to know how much the motor has moved. On a servo, a pulse or index signal will be generated by the encoder. With a stepper, we have an open loop:

I think the stepper interface should have an async API that would allow preloading the next number of steps to move, and the velocity for these steps. This would allow seamless transitions from one velocity to another to achieve smooth acceleration. The actual loading can then be handled by an interrupt or a DMA.

wkhadgar commented 4 months ago

Totally agree with that. Simple drivers (which turn to be the ones most people have) like A4988 only have a STEP/DIR interface that depends on pulses, easily generated from an MCU PWM or similar approach. Not to be discarded the more advanced drivers with UART controls, those are also common, and should be counted for. I can see a similarity with how modem gave birth to the GNSS subsys. We have timers/counters/PWM drivers already, that with an implementation touch can turn into the base for a stepper API.

Although I'm not sure about a general motor controller API, since it would require a deeper thought on many levels, personally I would easily set apart steppers from other motors since they cover arguably different use cases, and if needed, could make an entire controller of their own for BLDC and its variations.

Steppers are extremely useful and make a major part of a lot of dynamic embedded systems, that would benefit greatly from the possibility of having an official Zephyr support. I think everyone that has used Zephyr for a motorized application got to a point of wondering how is it possible that we don't have stepper/motor API yet. Many possibilities will flourish from this RFC and I can't wait for it to be a reality on the upstream! 😀

digiexchris commented 4 months ago

I agree with all of this, I REALLY need stepper control. Just my two cents, and I see the discussion has covered this, but I really need the ability to input steps, and have the motor move that exact number of steps. It would be nice if I could set an acceleration rate, and the controller figures out how fast it needs to ramp up the speed to get it there. I've been using other libraries like FastAccelStepper for esp32, but I'm lacking a lot of things like that when trying to move to a more hardware agnostic platform like zephyr.

And yes, there is use cases for using step pulses to run the motor at a defined speed without a defined stopping point (ie. run continuously without a distance set). I am setting up a surface grinder right now, and it requires that the motor runs forever at a defined speed, until an endstop is triggered, which the application then needs to command a stop to occur, reverse direction, and run continuously to the other stop. Planers would do this too. I use a stepper instead of a BLDC because it requries very precise control of speed while under the grinding wheel, +- 5rpm would be disastrous, whereas common inexpensive AC and brushless motors exhibit a small amount of lag as load changes.

The same grinder requires a different stepper to move a specific distance of steps and stops (the Z axis). It does not move continuously, and behaves more like a CNC axis. Steps is important because it's tied to a leadscrew, and there is a simple relationship between number of steps and the axis moving a specific distance in millimeters. Converting to angle makes that confusing and I am concerned about losing steps to floating point rounding error.

Regardless, not having to implement this from scratch in every zephyr project I make would make zephyr a much easier choice for me on new projects. I agree with starting simple, we need to control steppers now, and perfect is the enemy of done!

wkhadgar commented 4 months ago

@digiexchris Yup, they are stepper motors for a reason, the granularity of steps should be the focus. Fine, it is a simple direct relation from steps to angle, but that can be covered with macros, the main focus when handling steppers is the step resolution, and as far as I have experienced, most applications refer to the movements on a step basis. We already have the macro-magic that we all love, and it shouldn't be hard to switch between movement on steps or arcminutes/arcseconds.

TL;DR: Since steppers have a "hardware defined" resolution, even when micro-stepping, referring to the amount of steps is more natural and easier to correlate, and setting by angle is an easy implementation with macro conversions for those who may need it.

digiexchris commented 4 months ago

it shouldn't be hard to switch between movement on steps or arcminutes/arcseconds.

with an important distinction made for floating point rounding error on applications where losing a single step is not acceptable, staying in integers is preferred so angle as the primary input falls apart in that use case, due to the most common full-step angle being 1.8 degrees. Also, I have one driver that supports dynamically changing the microstep ratio at runtime, allowing for lower steps per revolution at high speed and higher steps per resolution at low speed to better manage torque vs smoothness. That's much easier to deal with in steps per second. Not arguing, I think we're agreed here.

Slightly off topic, I ran into an interesting crossover the other day, I found a DC treadmill motor controller (non-stepper/servo motor, not brushless, simple apply-dc voltage and it turns) that accepts a PWM signal to determine the rpm set point, and the controller would use rpm feedback and manage current to keep the rpm there (the input PWM wasn't applied to the motor directly). Could be controlled by an interface designed to drive the step pin on a simple stepper driver! But that's an accidental coincidence, not something we should plan for.

jilaypandya commented 1 month ago

Arch WG (20.08.2024):

carlescufi commented 1 month ago

@wkhadgar @digiexchris @adrienbruant the corresponding PR, #68774 is now merged. If you'd like to modify, expand or otherwise change in any way the API please open new Pull Requests. The API is experimental and thus subject to change at any time, so don't hesitate to propose your changes.

carlescufi commented 1 month ago

I am now closing this RFC since https://github.com/zephyrproject-rtos/zephyr/pull/68774 has been merged. Please open new PRs to continue the discussion.