This graph shows pulse time vs. servo speed. The graph’s horizontal axis shows the pulse width in microseconds (µs), and the vertical axis shows the servo’s response in RPM. Clockwise rotation is shown as negative, and counterclockwise is positive. This particular servo’s graph, which can also be called a transfer curve, ranges from about -48 to +48 RPM over the range of test pulse widths from 1300 to 1700 µs. A transfer curve graph of your servos would be similar.
With this sketch, you can check servo RPM speed (and direction) for pulse values from 1375 µs to 1625 µs in steps of 25 μs. These speed measurements will help make it clear how servo control pulse durations in the 1400 to 1600 µs range control servo speed. This sketch starts by displaying the pulse duration that it’s ready to send as a servo control signal. Then, it waits for you to send the Arduino a character with the Serial Monitor before it runs the servo. It runs the servo for six seconds, and during that time you can count the number of full turns the wheel makes. After that, the for loop repeats itself, and increases the pulse duration by 25 for the next test.
/* Robotics with the BOE Shield – TestServoSpeed Send a character from the Serial Monitor to the Arduino to make it run the left servo for 6 seconds. Starts with 1375 us pulses and increases by 25 us with each repetition, up to 1625 us. This sketch is useful for graphing speed vs. pulse width. */ #include <Servo.h> // Include servo library Servo servoLeft; // Declare left servo signal Servo servoRight; // Declare right servo signal void setup() // Built in initialization block { tone(4, 3000, 1000); // Play tone for 1 second delay(1000); // Delay to finish tone Serial.begin(9600); // Set data rate to 9600 bps servoLeft.attach(13); // Attach left signal to P13 } void loop() // Main loop auto-repeats { // Loop counts with pulseWidth from 1375 to 1625 in increments of 25. for(int pulseWidth = 1375; pulseWidth <= 1625; pulseWidth += 25) { Serial.print("pulseWidth = "); // Display pulseWidth value Serial.println(pulseWidth); Serial.println("Press a key and click"); // User prompt Serial.println("Send to start servo..."); while(Serial.available() == 0); // Wait for character Serial.read(); // Clear character Serial.println("Running..."); servoLeft.writeMicroseconds(pulseWidth); // Pin 13 servo speed = pulse delay(6000); // ..for 6 seconds servoLeft.writeMicroseconds(1500); // Pin 13 servo speed = stop } }
The sketch TestServoSpeed increments the value of a variable named pulseWidth by 25 each time through a for loop.
// Loop counts with pulseWidth from 1375 to 1625 in increments of 25. for(int pulseWidth = 1375; pulseWidth <= 1625; pulseWidth += 25)
With each repetition of the for loop, it displays the value of the next pulse width that it will send to the pin 13 servo, along with a user prompt.
Serial.print("pulseWidth = "); // Display pulseWidth value Serial.println(pulseWidth); Serial.println("Press a key and click"); // User prompt Serial.println("Send to start servo...");
After Serial.begin in the setup loop, the Arduino sets aside some memory for characters coming in from the Serial Monitor. This memory is typically called a serial buffer, and that’s where ASCII values from the Serial Monitor are stored. Each time you use Serial.read to get a character from the buffer, the Arduino subtracts 1 from the number of characters waiting in the buffer.
A call to Serial.available will tell you how many characters are in the buffer. This sketch uses while(Serial.available() = = 0) to wait until the Serial Monitor sends a character. Before moving on to run the servos, it uses Serial.read( ) to remove the character from the buffer. The sketch could have used int myVar = Serial.read( ) to copy the character to a variable. Since the code isn’t using the character’s value to make decisions, it just calls Serial.read, but doesn’t copy the result anywhere. The important part is that it needs to clear the buffer so that Serial.available( ) returns zero next time through the loop.
while(Serial.available() == 0); // Wait for character Serial.read(); // Clear character
Where is the while loop’s code block?
The C language allows the while loop to use an empty code block, in this case to wait there until it receives a character. When you type a character into the Serial Monitor, Serial.available returns 1 instead of 0, so the while loop lets the sketch move on to the next statement. Serial.read removes that character you typed from the Arduino’s serial buffer to make sure that Serial.available returns 0 next time through the loop. You could have typed this empty while loop other ways:
while(Serial.available() == 0) {}
...or:
while(Serial.available() == 0) {}; .
After the Arduino receives a character from the keyboard, it displays the “Running…” message and then makes the servo turn for 6 seconds. Remember that the for loop this code is in starts the pulseWidth variable at 1375 and adds 25 to it with each repetition. So, the first time through the loop, servoLeft is 1375, the second time through it’s 1400, and so on all the way up to 1625.
Each time through the loop, servoLeft.writeMicroseconds(pulseWidth) uses the value that pulseWidth stores to set servo speed. That’s how it updates the servo’s speed each time you send a character to the Arduino with the Serial Monitor.
Serial.println("Running..."); servoLeft.writeMicroseconds(pulseWidth); // Pin 13 speed=pulse delay(6000); // ..for 6 seconds servoLeft.writeMicroseconds(1500); // Pin 13 speed=stop
You can use the table below to record the data for your own transfer curve. The TestServoSpeed sketch’s loop can be modified to test every value in the table, or every other value to save time.
for(int pulseWidth=1375; pulseWidth <= 1625; pulseWidth += 25)
…to:
for(int pulseWidth=1300; pulseWidth <= 1700; pulseWidth += 20)