VarSpeedServoRA4M1

VarSpeedServoRA4M1 is a library for Arduino (developed by Kaled Souky in 2024), based on the Servo library (developed by Michael Margolis in 2009) and VarSpeedServo library (developed by Korman in 2010 and updated by Philip van Allen in 2013). Specifically designed for the Renesas RA4M1 microcontroller architecture (Arm Cortex-M4), present on the Arduino UNO R4 Minima and Arduino UNO R4 WiFi boards.

VarSpeedServoRA4M1 is an interrupt-driven library using 16-bit timers, allowing the use of up to 12 servos moving asynchronously or synchronously. In addition to setting the position, you can set the speed of a movement, optionally wait until the servo movement is completed, and create sequences of movements that execute asynchronously or synchronously.

The 32-bit Renesas RA4M1 processor operating at 48 MHz elevates servo control to a new level, providing higher PWM resolution compared to the ATmega328P used in Arduino UNO R3. Thanks to this power, VarSpeedServoRA4M1 fully exploits the microcontroller's capabilities. With its simple and intuitive syntax, this library facilitates precise control over servo position and speed, even for beginners. Creating complex movement sequences is straightforward with just a few commands.

Download the library by clicking on the description below the video
or scan the QR code shown in the video

WARNING:
"External devices with a high current draw (e.g. servo motors) should never be powered via the 5 V pin. It is mainly intended for devices drawing lower current such as sensor modules".

TIP:
How to connect power and control servo motors with your Arduino board. Please check the link of Arduino official site:

Features:

  • Supports up to 12 servos.
  • Allows synchronous and asynchronous movement of all servos.
  • Allows you to configure the "position" and "speed" of each servo individually.
  • Includes a "wait" parameter to wait for the servo to complete its movement. Philip van Allen, in his update, incorporated it as a boolean variable within the write() function, and also as the independent wait() function. This parameter is not included as a variable in Korman's slowmove() function.
  • The write() function now includes the "speed" and "wait" parameters, which can optionally be used in conjunction
    with the "position" parameter to control servo movement.
  • The slowmove() function is retained for compatibility with the Korman version. It only handles the "position" and "speed" parameters. In this case, the waiting time must be configured (using, for example, the function delay(), delayMicroseconds(), micros() or millis()), so that the servo completes the position and maintains it for the desired time. The slowmove() function does not incorporate the "wait" variable introduced by Philip van Allen in the write() function.
  • Allows the creation of position sequences.

Class methods

A servo is activated by creating an instance of the VarSpeedServoRA4M1 class passing the desired pin to the attach() method. The servos are pulsed in the background using the value most recently written using the write() method

Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
The sequence used to seize timers is defined in the content of the "ServoTimers.h" file for Renesas of the Arduino Servo library.

VarSpeedServoRA4M1 - Class for manipulating servo motors connected to Arduino pins. Methods:

VarSpeedServoRA4M1() - Creates a new Servo object and prepares it for controlling a servo motor
attach(pin ) - Attaches a servo motor to an i/o pin
attach(pin, min, max  ) - Attaches to a pin setting min and max values in microseconds default min is 544, max is 2400  

write(value) - Sets the servo angle in degrees (invalid angle that is valid as pulse in microseconds is treated as microseconds)
write(value, speed) - speed varies the speed of the move to new position 0=full speed, 1-255 slower to faster
write(value, speed, wait) - wait is a boolean that, if true, causes the function call to block until move is complete

writeMicroseconds() - Sets the servo pulse width in microseconds 
read() - Gets the last written servo pulse width as an angle between 0 and 180 
readMicroseconds() - Gets the last written servo pulse width in microseconds (was read_us() in first release)
attached() - Returns true if there is a servo attached 
detach() - Stops an attached servos from pulsing its i/o pin 

slowmove(value, speed) - The same as write(value, speed), retained for compatibility with Korman's version

stop() - stops the servo at the current position

sequencePlay(sequence, sequencePositions) - play a looping sequence starting at position 0
sequencePlay(sequence, sequencePositions, loop, startPosition) - play sequence with number of positions, loop if true, start at position
sequenceStop() - stop sequence at current position
wait() - wait for movement to finish
isMoving() - return true if servo is still moving

Examples of use:

Sample code 1: Sweeps a servo motor from 0 to 180 degrees at fast speed and back from 180 to 0 degrees at slow speed, in an infinite loop.

The write() function now includes the "speed" and "wait" parameters, which can optionally be used in conjunction with the "position" parameter to control servo movement.

The "wait" parameter is used to wait for the servo to complete its movement. It is also available as a standalone wait() function.


#include <VarSpeedServoRA4M1.h> 
 
VarSpeedServoRA4M1 myservo;  // create servo object to control a servo 
// A maximum of twelve servo objects can be created

const int servoPin = 9;  // the digital pin used for the servo

void setup() { 
  myservo.attach(servoPin);  // attaches the servo on pin 9 to the servo object
  myservo.write(0,127,true);  // set the servo to its initial position at fast speed, wait for completion
} 

void loop() {
  // write(degrees 0-180, speed 1-255, wait to complete true-false)
  /* On the RC servos tested, speed differences above 127 
     cannot be noticed due to the mechanical limitations of 
     the servo. However, feel free to experiment with the 
     speed value that best suits the response of your servo 
     based on its mechanical and electronic characteristics 
  */
  myservo.write(180,127,true);  // move the servo to 180, fast speed, wait until done
  myservo.write(0,30,true);  // move the servo to 0, slow speed, wait until done
} 

Sample code 2: Sweeps a servo motor from 0 to 180 degrees at fast speed and back from 180 to 0 degrees at slow speed, in an infinite loop.

The slowmove() function only handles the "position" and "speed" parameters. In this case, the wait time must be set (using, for example, the delay(), millis(), micros(), or delayMicroseconds() functions) to ensure the servo completes the position and maintains it for the desired time. The slowmove() function does not incorporate the "wait" variable.

This example demonstrates the use of the delay() function as a timeout with slowmove(). The exact delay value may require some experimentation (usually in the millisecond range) to ensure that the servo has enough time to reach its target position and hold it for as long as necessary, until receiving the next instruction.


#include <VarSpeedServoRA4M1.h> 
 
VarSpeedServoRA4M1 myservo;  // create servo object to control a servo 
// A maximum of twelve servo objects can be created 
 
const int servoPin = 9;  // the digital pin used for the servo
 
void setup() { 
  myservo.attach(servoPin);  // attaches the servo on pin 9 to the servo object
  myservo.slowmove(0,127);  // set the servo to its initial position at fast speed
  delay(1000);  // sets the time the servo needs to reach the position and stay there
} 

void loop() {
  // slowmove(degrees 0-180, speed 1-255)
  /* On the RC servos tested, speed differences above 127 
     cannot be noticed due to the mechanical limitations of 
     the servo. However, feel free to experiment with the 
     speed value that best suits the response of your servo 
     based on its mechanical and electronic characteristics 
  */
  myservo.slowmove(180,127);  // move the servo to 180, fast speed
  delay(1000);  // sets the time the servo needs to reach the position and stay there
  myservo.slowmove(0,30);  // move the servo to 0, slow speed
  delay(3700);  // sets the time the servo needs to reach the position and stay there
} 

Additional examples are included in the distribution and are available in the Arduino IDE Examples section.

NOTE:
The VarSpeedServoRA4M1 library is not included in the standard Arduino distribution. You must download and install it separately.

There are two methods to achieve this:

  • Import a ZIP library
  • Manual installation

These methods are described on the official Arduino site:

ko-fi

1 Like
wait() - wait for movement to finish
isMoving() - return true if servo is still moving

As there is no feedback from the servo to the sketch, how do these functions work ?

Hi friend,

The wait() function blocks the program until the servo has reached the desired position. You can find it implemented in the VarSpeedServoRA4M1Test example.

The boolean function isMoving() checks if the servo is still moving without blocking the program, allowing other tasks to run while the servo status is checked. Ideal for use with millis() for non-blocking code.

How does the wait() function know that the servo has reached the desired position when there is no feedback from the servo ?

In the case of the wait() function, the microcontroller knows that the servo has reached its desired position by using the read() or readMicroseconds() methods in combination with the while loop. Here is a more detailed breakdown:

  • For positions less than MIN_PULSE_WIDTH :
    • The read() method is used, which returns the current servo position in degrees.
    • The while loop continues to run as long as the current servo position, obtained with read(), is different from the desired position (value).
  • For positions greater than or equal to MIN_PULSE_WIDTH :
    • The readMicroseconds() method is used, which returns the current pulse length in microseconds.
    • The while loop continues to run as long as the current pulse length, obtained with readMicroseconds(), is different from the desired pulse length (value).

The microcontroller constantly checks the current servo position and compares it to the target position. When both match, the loop breaks and the program continues with the next instruction.

Greetings, my friend, I hope I have been helpful and have clarified your doubts.

I am sorry, but it cannot do that. The best that it can do is to check the current position that the servo has been commanded to move to. That is not the same thing

If it works like my old ServoEx library: part of my Phoenix Parts project:
Arduino_Phoenix_Parts/ServoEx at master · KurtE/Arduino_Phoenix_Parts)

I used this something like 10-15 years ago for running my old Lynxmotion robots. It worked similar to the Lynxmotion (now Robotshop) servo controller (SSC-32).

How it worked, was, it kept tract of the last location you told each of the servos to go to and a new location and you would like it to go at some speed or get there in N microseconds.

What the code would do, lets say you tell it to move to postion 2500 and it was at 1500 and you want it done in lets say 200ms.

The code would: See that you want to move it 1000us and if the servo cycle time is 20us (or 50 times per second), The servo should take 10 cycles to get there. And as such you would increment the PWM width by 1000/10 or 100 us.
So after it reached its requested position, it would report that it is done...

Note: this is not 100% correct as you don't actually know if the servo actually makes it to that position....

Also some servos are more advanced and include things like ramp up speed and ramp down speed, but was good enough for what I needed

Thank you for the detailed explanation. It was the sort of logic that I was expecting but as you say,

Hence my comments

Very true for most RC servos... But for most things worked well enough, except the startup, where it has no idea where the servos are. (Or if you allow the servos to go limp). Which is why I usually had a startup position, I moved the servos to safe spot, before startup...

Which is one of the reasons I quit using RC servos. Actually, I have not done much with servos for a couple of years, but, when I do I mostly use Robotis Dynamixel Servos, also used some of the smarter Lynxmotion Smart servos (LSS)

I understand your observation about the physical verification of the servo position. However, my reasoning focused on how the code handles waiting until the desired servo value matches the expected value. In the case of the wait() function, the microcontroller uses the read() or readMicroseconds() methods in combination with the while loop. Here is a more detailed breakdown:

For positions below MIN_PULSE_WIDTH:

  • The read() method is used, which returns the current position of the servo in degrees.
  • The while loop continues to execute while the current position of the servo, obtained with read(), is different from the desired position (value).

For positions greater than or equal to MIN_PULSE_WIDTH:

  • The readMicroseconds() method is used, which returns the current pulse length in microseconds.
  • The while loop continues to execute while the current pulse length, obtained with readMicroseconds(), is different from the desired pulse length (value).

The microcontroller constantly checks the current position of the servo and compares it with the target position. When they match, the loop breaks and the program moves to the next instruction.

Although I recognize that these methods do not physically verify the actual position of the servo, my explanation focuses on the behavior of the code and how it handles waiting based on the values it has. Standard servos generally do not have direct access to the potentiometer for feedback that allows the microcontroller to know the resistance variation and thereby verify its exact physical position. Therefore, although the code waits for the desired value to match the servo's "expected" value, there is no guarantee that the servo has reached that physical position.

To obtain an accurate verification of the physical position, you would need a servo with a direct feedback system to the internal potentiometer or an external feedback system that can read the actual position of the servo, such as a potentiometer or an encoder.

Best regards!

KurtE, greetings and many thanks on behalf of the entire community for your incredible work with the Servo.h library for Arduino, especially regarding the Renesas architecture. You have truly done a phenomenal job. My deepest respects, maestro. Best regards!