-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
add different virbrations tunes/patterns support as bzzzt for 50 or 35ms is boring #605
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: main
Are you sure you want to change the base?
Conversation
| constexpr MotorController::Tune MotorController::tunes[]; | ||
|
|
||
|
|
||
| MotorController::MotorController(Controllers::Settings& settingsController) : settingsController {settingsController} { | ||
| } | ||
|
|
||
|
|
||
|
|
||
| uint8_t MotorController::step = 0; | ||
| MotorController::TuneType MotorController::runningTune = MotorController::TuneType::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.
These variables only need to be declared in the header file.
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 get undefined reference to Pinetime::Controllers::MotorController::step, etc If I do not initialize 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.
Ah that's because these functions and variables are static. Usually in this project something like this is used to get around cases where a callback requires a static function.
void MotorController::Ring(void* p_context) {
auto* motorController = static_cast<MotorController*>(p_context);
motorController->RunForDuration(50);
}
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 step and runningingTune from static scope.
Would like to leave tunes[] as static. The probability is miniscule, that motorController will have multiple instances, but still.
| if (step >= tunes[runningTune].length || step >= 8) { //end of tune turn off vibration | ||
| nrf_gpio_pin_set(pinMotor); | ||
| return; | ||
| } | ||
|
|
||
| if (((1 << step) & tunes[runningTune].tune) > 0) { | ||
| nrf_gpio_pin_clear(pinMotor); | ||
| } else { | ||
| nrf_gpio_pin_set(pinMotor); | ||
| } |
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.
Any reason not to use RunForDuration() for the patterns as well? It would provide better abstraction.
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.
RunForDuration() is public facing API call, that is currently implemented as "just another tune to play". Would like to not add any more logic to the public facing API. Adding enableMotor() and disableMotor() calls would maybe make it more readable.
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.
RunForDuration() is public facing API call, that is currently implemented as "just another tune to play".
That's because you changed it that way. That function didn't necessarily have to be changed at all.
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.
Refactored the approach to use a unified ScheduleVibrationTimer call.
…e, moved some variables from static scope to instance scope
|
Would it be better to encode patterns as a simple list of delays between motor toggles? A pattern could be A zero could be used to detect the end of the pattern and stop the motor. I think doing it this way could be more flexible and simple. |
|
I find original pattern format (bit pattern, length & tempo) flexible and memory efficient enough. I can imagine that composing will be easier to change bit patterns than copypaste different numbers in an array. I would just increase the In case of longer tune the array representation will become worse to read I guess. Also it would need to have every "note" on a different line to see what is length and what is a pause. Now changing the speed will need to change all the values, or at lease 6 of them. The original approach might look like this and feels cleaner to me @akito45 Maybe I would suggest to read the bit pattern from the left (MSB) first. We read text from the left, cursor moves to the right when I press 0 or 1, notes are read from the left to the right, so for composing it will be much better. UPDATE:In hidsight after I tested both options. I changed my mind little and I'm not sure which approach for "composers" will be more friendly :) In case we stick with Riksu suggestion, I would just point out that we might not need millisecond precision and arrays could be |
|
The bit pattern is less wasteful on memory. If made MSB first, the .length could be eliminated, as the length can be calculated on runtime, by just ignoring the preceding 0's. I would side with the VIBRATE(X, Y) format, if we would have access to some kind of frequency component. The format would make sense for VIBRATE(freq, duration), but not so much for on/off. Not that familiar with the NRF platform, but can that pin output PWM? In that case VIBRATE(intensity, duration) would make some sense. Pauses could be encoded as VIBRATE(0, duration). If the majority decides to go with the VIBRATE(X, Y) format, I would advocate for VIBRATE(intencity, duration) for future proofing, not for VIBRATE (on_duration, off_duration) as it seems needlessly custom, for no seeable benefit. |
|
I don't think PWM is necessary because the length of the pulse is practically the same as intensity, and more often than not we would like the vibration to be more noticable than less. I'm also not sure if we should use a macro to combine the on and off period. We could just decide that one unit is 10ms for example and 10 is easy to work with. |
|
Right, PWM is possible on any gpio pin but it really does not make any effect on the motor that you would fell. Specially in these short vibrating pulses. 10ms resolution and no macro coulde be fine. However for code readability the macro would be better and self explanatory (with division by 10ms), rather than array of deci-millisecond values. |
|
Either I vote for the first, for memory conservation. It also is more intuitively readable for me. Altho I have 0 musical talent so it is not saying much. Maybe the stakeholders could cast their votes and I could implement the more popular version. |
|
Benefits of using an array of delays are that the code that plays the pattern would be simpler, more efficient and more flexible. Having a fixed tempo is more limiting, because each vibration has to land on a beat. This could be compensated by increasing the speed, but then the 32 bit limit forces the pattern to be short. Maybe it could be increased to 64 bits, but now it's no longer very memory efficient. The array of delays doesn't have this issue. Patterns can be any length and any precision, making it much more flexible. The array of delays is harder to read for sure, but splitting the pattern on multiple lines makes it much more readable. Now I can easily tell what this pattern is going to be like. |
|
I'm with riksu with 10ms granuality, so 5 = 50 ms if I got it right. |
|
Any chance of bringing this PR up to date and implementing the requested change to the pattern format @akito45 ? |
|
@kieranc Will blow the dust off the build env in the weekend. |
|
I'd also be interested in this PR being updated - I've subscribed to changes, but thought I'd throw out that there's another interested party Edit: I'm still very new to PineTime dev, but I read through this pull request and made an updated (but very simplified) version of it for a personal project of mine. I'm not sure if it'll help, but here's a link to the commit in my fork. |
|
Two thoughts... Another option for specifying the pattern could be to approach it like a step-sequencer (old school drum machines etc), and have an int to define step-interval (tempo, if you like) and then 16 or 32bits to define on or off for that step. Some experimentation would be required to see if that many bits is sufficient to give enough pattern length for a given number of intensity durations. Has anyone actually experimented with pwm on the pinetime motor pin? Varying the pwm frequency (esp at lower freqs) might give usable options. Also, I haven't done the math on it but the pwm controller onboard looks like it might do all the pattern stuff we might want, as it can read step patterns via DMA without loading the cpu - https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpwm.html Edit: This blog post has a little more info including code snippets (between lots of copy/paste from the spec) https://jimmywongiot.com/2021/06/01/advanced-pulse-width-modulation-pwm-on-nordic-nrf52-series/ Also some info on examples (included in the sdk?) at https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v11.0.0%2Fpwm_hw_example.html&cp=6_0_0_4_5_15 |
Things attempted