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

PWM duty cycle range not continuous on UNO R4 #113

Closed
ozangerger opened this issue Jul 7, 2023 · 10 comments · Fixed by #116
Closed

PWM duty cycle range not continuous on UNO R4 #113

ozangerger opened this issue Jul 7, 2023 · 10 comments · Fixed by #116
Labels
conclusion: resolved Issue was resolved topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project

Comments

@ozangerger
Copy link

Recently, I bought uno r4 and was planning to replace uno r3 to have more capacity for my hobby projects.

One thing I noticed is that when using servo library with uno r4 is that the motor throttle setting is no longer continuous and looked like it has 10 discrete speed setting. Unfortunately, I don't have an oscilloscope at home right now. My first suspicion was a change in the processor and clocks, which may affect the timers used in the libraries.

Do you have any idea what could be the reason?

@per1234 per1234 added type: imperfection Perceived defect in any part of project topic: code Related to content of the project itself labels Jul 8, 2023
@per1234 per1234 changed the title PWM issue with ESCs on uno r4 PWM duty cycle range not continuous on UNO R4 Jul 8, 2023
@eburgwedel
Copy link

As an Arduino newbie, I don't exactly know if the above observation is the reason for a problem I'm encountering: I've been trying to move a servo in a very smooth and slow way — no chance. While it works on a Mega, the same code on the Uno R4 results in a stuttery, jumpy servo motion. It's essentially unusable for smooth, precise servo control.

@EvanBottango
Copy link

I have seen the same behavior, smooth or slow performance on a servo was not possible with my Uno R4 Wifi. I reduced variables down to the built in "sweep" example sketch, and analyzed the outgoing pulse lengths themselves. Here is the Arduino forum post I made: https://forum.arduino.cc/t/trouble-with-servos-on-r4-wifi/1151749

@eburgwedel
Copy link

eburgwedel commented Aug 25, 2023

Yes, this is exactly what I'm observing. I tried writeMicroseconds() with the same result (to be expected, though).

@KurtE
Copy link

KurtE commented Aug 30, 2023

I believe the problem is on how the servo library is implemented on the Renesas boards.

That is the library is implemented using a FSP timer object. With a fixed timer rate of I believe
100us.

So using the defaults: the servo range is from 544 to 2400us to cover 180 degrees.
Which implies to move 1 degree, you would change the servo value by: 10.311us.
Which if your resolution is 100us that is about: 9.7 degrees
(Assuming my math is correct)

One solution is to increase the number of interrupts per second. Which may not be desirable.

Another solution would be to do like some of the other implementations, and that is when you receive the interrupt (callback) to complete a servo, you update the cycle time to time of the next servo and when you completed all of the servos, you delay up until the time to start the next servo frame.

I have experimented doing this with the Charlieplex code for the LEDs, as I have it setup to output the different LEDS for different periods as to change the intensity. I discuss some of this up on the forum thread:
https://forum.arduino.cc/t/experimenting-with-the-wifi-charlieplex-matrix-code/1159619/9
I can go into more details, but code is up at:
https://github.com/KurtE/UNOR4-stuff/tree/main/libraries/arduino_r4wifi_matrix_gfx/src

My first attempts were to use the FSP timer function to update the pulse width. The problem I ran into is that
this sets the buffered register. So it won't take effect until after the timer hits the current settings. So was always one behind.
Could potentially try to work around this, by looking ahead one each time, but instead, I turned off the buffer and set it
directly.
Turn off buffering.
https://github.com/KurtE/UNOR4-stuff/blob/main/libraries/arduino_r4wifi_matrix_gfx/src/arduino_r4wifi_matrix_gfx.cpp#L135

Update the clock period.
https://github.com/KurtE/UNOR4-stuff/blob/main/libraries/arduino_r4wifi_matrix_gfx/src/arduino_r4wifi_matrix_gfx.cpp#L135

Hope that helps
Kurt

@facchinm
Copy link
Contributor

facchinm commented Sep 1, 2023

@iabdalkader can you take a look?

@KurtE
Copy link

KurtE commented Sep 1, 2023

@facchinm @iabdalkader

I have started playing with the code, to update it to not used fixed timer period, but instead update the timer period for each servo as well as the end of the servo cycle period.

It is starting to work. So far only tested with one servo in the sweep sketch.

Current code is up at:
https://github.com/KurtE/Arduino_Servo/tree/unor4_timer_period_updates

Let me know what you think.

Warning so far the code will only handle GPT timers. I have yet to run into case where it will go to the other timer type

Edit: I have tested it with two servos sweeping. I also updated the code to disable the simple debug output code I had
to get an idea of resolution.

@iabdalkader
Copy link
Contributor

@KurtE Thank you! I wrote this a while ago, so will need to refresh my memory, reproduce the issue and test your PR, will get back to you asap.

@per1234 per1234 added the conclusion: resolved Issue was resolved label Jan 9, 2024
@oracid
Copy link

oracid commented Feb 24, 2024

Usually I use an Arduino Nano. I have a little experience with using servos, I make quadrupeds (look for Oracid on YT).
I tried using an UNO R4 and I am having problems with the servo.attach(pin, min, max) function.
The max parameter seems to be taken into account while the min parameter is not taken into account at all.
Overall, I have a lot of doubts about the compatibility of Servo.h

@KurtE
Copy link

KurtE commented Feb 25, 2024

@oracid - Sorry I don't and have not used the Servo library (or RC servos in general) for a long time now (probably a decade).

Nor done much with Nano boards. Except I have played some with a few of the ones like the 33IOT and BLE. Hopefully someone who uses RC servos and Nanos can help.

If there is some compatibility issue with this library on the UNO R4, you might want to raise a new issue against the library, such that hopefully the owners of the library will take a look at it. You might include in it some additional information, including things like: Which nano you normally use (AVR? RPI? IOT? BLE?) Also, what the actual problem is. On these boards when I do X it does this and on the R4 it does that...

As far: as servo.attach(pin, min, max)

The min and max are saved away into: servo->period_min, servo->period_max)
And these are used in places like the write methods, to either map angles in degrees into microseconds, using the map function.
like:

void Servo::write(int angle)
{
    if (servoIndex != SERVO_INVALID_INDEX) {
        ra_servo_t *servo = &ra_servos[servoIndex];
        angle = constrain(angle, 0, 180);
        writeMicroseconds(map(angle, 0, 180, servo->period_min, servo->period_max));
    }
}

Or constrains the range used when you write in microseconds, like:

void Servo::writeMicroseconds(int us)
{
    if (servoIndex != SERVO_INVALID_INDEX) {
        ra_servo_t *servo = &ra_servos[servoIndex];
        servo->period_us = constrain(us, servo->period_min, servo->period_max);
        servo->period_ticks = us_to_ticks(servo->period_us);
    }
}

I have noticed for example, that the write(value) is not fully compatible with the AVR version. For example, on
the AVR version if you do: myservo.write(1500);
It will see that value is > MIN_PULSE_WIDTH which is 544 and will pass it directly to: writeMicroseconds.

On the R4, it will see that 1500 > 180 and then decide to constrain the value to 180 and then map it to period_max,

So probably on R3 if you passed in 1500, it will move the servo to typically about the mid point, but on R4 to the max range defined for the servo. If this is your issue, you can convert to using writeMicroseconds.

Or maybe the developers such as: @iabdalkader might fix some compatibility issues. But your chances would likely be improved, if more detailed explanation of the problem raised in a new open issue.

Good luck

@oracid
Copy link

oracid commented Feb 25, 2024

Thank you very much for your answer.
My Nano is an AVR Nano. A basic Nano.
I also use the writeMicroseconds() function associated with the map() function. I don't use the constrain() function, but it's a great idea.
You can see here my video for beginner where I show how to program a servo, https://youtu.be/OYC-iuB75KA?si=Pb8J3kXnViEhlMlK

@arduino-libraries arduino-libraries locked as resolved and limited conversation to collaborators Feb 25, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
conclusion: resolved Issue was resolved topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants