Electronic – arduino – How to detect servo stall with an Arduino

arduinocurrentcurrent measurementfeedbackservo

I am controlling a standard 5-volt servo with an Arduino with PWM.

My objective is to rotate the servo until it physically gets stalled (feels resistance) and then stop. Then I want the Arduino to store the degree at which the servo stopped at.

To do this, I have this idea in my mind…

  1. A variable (servoPos) is declared.
  2. Arduino increments servoPos one degree at a time and writes it to the servo.
  3. Arduino simultaneously reads the current drawn from the servo.
  4. IF the Arduino sees a current spike, then it stops the servo.
  5. The Arduino stores the servo position in a new variable.

I am doing this for a project that emphasizes on low-cost. Therefore, I want to refrain from using motor encoders, op-amps, or any proprietary component.

Please show me how I can detect servo stall with an Arduino by reading the current. If you have a better/cost-effective idea, that would be appreciated too!

Thanks in advance!

Best Answer

The cheapest dodgiest thing you can do is use a low-side current-sense resistor (0.1ohm will do) and use the Arduino's ADC input with a 1-10K series resistor, over-voltage clamp, and ensure the servo is clamped too.

Let me make some assumptions/recommendations first:

Power your Arduino and the rest of your system from a rechargable Lipo/NiMH battery pack over 7V volts (which means a 2 cell Lipo or ~4 cell NiMH). The battery can power the Arduino Uno as it has an onboard regulator for it's own 5V needs, but I suggest you put the servo on it's own 7805 or better/newer technology linear regulator in order to separate it from the Arduino's supply a little bit, and also in general to have more reliable and safer results from the servo. Most hobby servos are 5-6V recommended input anyway.

The general premise is to use a low-side current shunt resistor, of a low value as to not be too limiting to the system you are measuring, but enough that you can sense the current stress from the stall condition reliably enough with the 5V 10-bit ADC on the Arduino.

schematic

simulate this circuit – Schematic created using CircuitLab

I have shown in the schematic above a 2-cell fully charged (8.4V, 4.2V per cell, with 2 in series) Lithium Ion battery, going to a 7805 (or if you can find a better one, please do. LDO style would give better long-term results as the batteries drain into the drop-out region of older models like the 7805) with appropriate input and output capacitors, and then off to the servo. The servo has "close by" a 100uF and 1000uF (1mF) capacitors so that large amounts of current can be provided without tanking the 7805 or the battery too much for short periods of time. Obviously a continuous short/stall it will still affect the system "up stream".

There is a clamping/flyback schottky diode D3, parallel across the servo + and - connections. Not shown is the servo's signal/control input, but you should know how that works. By the way, I suggest you use Arduino's Servo library, not "standard" PWM as the frequencies are too high.

The clamping diode D4 is to protect the Arduino's ADC pin from negative voltages. The series resistor R1 is input current limiting combined with filter cap C5 to form a little bit of low-pass passive filtering, helping avoid false positives for current spikes during the normal operation of the servo.

As current through the servo increases, the voltage across our sense resistor R2 will increase. I set the resistor to 100mOhm, which will allow us to use Ohm's law to see what voltage will be across it during an arbitrary current.

I actually looked at it from the Arduino and code viewpoint, thinking the ADC is 10-bit, meaning 1024 steps. The reference is usually 5V, so 5000mV/1024 is 4.88mV per "unit" of the ADC in the code. Lets say to avoid detecting something small, lets aim for an ADC reading of 20+ to trip the stall current detection code.

Lets say for a value of 25 read on the ADC, 25 Units * 4.88mv/Unit is 122mV on the ADC input in the real world. The required current through the sense resistor to get 122mV across it follows Ohm's law. V = IR, so 0.122V = I * 0.1, which is 1.22 Amps.

I believe that 1.22 Amps is reasonable enough for a stall current on a hobbyist servo, and it may be more than this, but certainly normal movement will not be anywhere near this.

The last thing to note is, if you find the ADC values with 0.1Ohm are not good/high enough, you can easily just double the resistor to 0.2Ohms. Remember that you do not want to limit the servo from normal operation though, but 5V/0.2Ohm is still allowing a short circuit of the servo of a hefty 25 Amps so we are not anywhere near affecting it's operation yet.

The ADC reading code should have some kind of timer/time-out period where if the ADC values are consistently above 20->25 or whatever you choose as your limit (you can tune it later), perhaps for 5 samples in a row, taken at 5ms intervals gives you a response time of just over 25 milliseconds to a legitimate stall condition. That should be plenty! Remember every time a servo starts up, or changes direction, it WILL draw this amount of current for short periods. Try to avoid tripping the "stall" condition too fast.