This is a blog post in support of the RoadTest PicoScope 6424E Oscilloscope + Accessories . It is the fifth blog post in a series exploring the equipment in order to generate the content for the final RoadTest review.
My application pitch was to review the equipment while analyzing servo motor operation. I did a tutorial for a magazine publication back in June 2019, describing the operation of servo motors on a Raspberry Pi. The python scripts doesn’t work on a Pi today. What has changed? Servo motor operation on the Pi has be lack lustre in comparison to that of a microcontroller like an Arduino. My goal is to examine the pulse width modulation (PWM) signals that drive servo’s to look for a better understanding. The testing is detailed in PicoScope 6424E Oscilloscope + Accessories: Methodology
This blog post will provide:
- introduction to servo signals
- initial test using Arduino
- raspberry pi test
- what now
Introduction to servo signals
Before examining the signals using the scope, let's review the theory of servo operation. The servo is expecting a pulse width of between 0.5 -2.5 milliseconds every 20 milliseconds. 20msec in frequency is 1/.02=50Hz. The drawing combines the physical position of the servo with the signal that is needed.
Initial test using Arduino
Even though this project is investigating servo's on a Raspberry Pi, out of pure laziness the first test of displaying a servo signal on the PicoScope was done with an Arduino Nano. A legacy breadboard setup had Arduino installed. One USB cable for programming and they were ready to load code. I will demonstrate the Pi later. This test is a good initial test to understand the signals and confirm operation.
Two Arduino scripts were used to move the servo from 0 to 180 degrees. One script used the library servo.h to control the servo and the other generated the pulses manually to control the servo. I soon discovered what is published on the web doesn't necessarily mean it works. The servo.h script worked, the manual script code did not. The theory of the script to produces the pulses manually is sound. The code is intended to create a pulse of 0.5 msec at a rate of 50Hz. When the code is applied to a Arduino Nano or a Uno it doesn't work.
Below is a a snippet of the code that generates the pulse.
the void loop code:
// A pulse each 20ms
delayMicroseconds(600); // Duration of the pulse in microseconds
delayMicroseconds(18550); // 20ms - duration of the pulse
// Pulses duration: 600 - 0deg; 1450 - 90deg; 2300 - 180deg
Using the scope capture feature the following waveforms were produced.
The waveform at the top is generated using servo.h library. The script creates a pulse to move the servo to zero degrees. It represents a 50 Hz signal. The image at the bottom is of the Arduino output using the manual code. The pulse width is correct but it is not at 50Hz. To further the test, the Low value for the manual script above was reduced to 16,000 the following output signal was produced.
The signal is closer to a frequency of 50Hz but is still not correct. WHen the value is =>16,500 the pulse frequency is more erratic.
The waveforms provided by the PicoScope demonstrate what is actually happening. For the unsuspecting person who scraped the manual Arduino code from a web site, the understanding is that it should work. In practice the Arduino device using the manual code, was unable to deliver what was called for in the code but generated some other signal. The same test was performed on a Arduino Uno & Nano with the same results.
Raspberry Pi Test
It is with some embarrassment, I confess that the problem with not being able to successfully repeat the Pi servo test from the magazine tutorial I wrote a year ago, was related to the operator and not the Pi. I admit, if I had of taken the time to do a more thorough investigation, the problem(s) could have been resolved the issue without the aid of the scope. The scoped output made it easy! Viewing the scope output from the Pi provided immediate insight, that enable me to find the issues that were causing the problems.
There were two issues that prevented the Pi servo script from running. First the frequency parameter in the script were set incorrectly. I failed to recall that I modified the script to demonstrate pulse width modulation (PWM) using an LED or a servo. The frequency value was set for an LED. This was easy to see with the oscilloscope. With the working Arduino servo.h code waveform displayed on one channel and the Pi servo script displayed on the other it was evident the two signals were not the same frequency.
Using the timing graduals to measure the interval between pulses the signal on the left is approximately 20ms and the signal on the right is approximately 13ms. 20ms corresponds to 50Hz. Problem solved, correct? I then discovered, of the four servo's I have in the junk box three do not respond to a signal. How I managed to select the one working servo to use on the Arduino is surprising. With the correct signal displayed for the Pi, I tried the three remaining servos and they all failed to work. There was some noise from the motors but no movement. Using the servo from the Arduino the Pi I was able to move the servo 0-180 degrees using the Pi script with the correct frequency value.
The screen images shown above are generated using the PicoScope edit menu.
The Copy as Image selection only captures the display screen with the signal. The Copy Entire Window as Image provides all the screen button but also the gradual value display showing the values set on the screen.
The resolution to the Pi servo problem was rather disappointing. I had hoped to use more of the scope capabilities to resolve the problem. After some thought, I'm going to look at the scopes options to see if I can demonstrate why the Pi is not ideal for controlling servo's. The example will introduces the scope persistence view capabilities and option I am reading about and would like to explore.