Preface
The SUPER200 servo1,2,3 on the surface looks pretty sweet for its price and specification: 12v, 200kg/cm torque, standard servo input. Unfortunately, like many other products from fleabay, the low price often hints at a potentially major issue. Brief testing with a servo tester shows that it has a terrible accuracy of about +-10degs. What use does one have for an inaccurate servo? It turns out that the PCB isn't too hard to understand and the easiest option is to extract the signal from the angle sensor and create a feedback loop with an external dollarduino4. The external duino allows me to obtain a more accurate positioning of the output shaft with 1-deg precision. The only downside is that the time to settle into the target position is not as quick as I have hoped. The goal is to get a decent heavy-weight servo without spending on an expensive Dynamixel equivalent. The code for the external -duino is up on my Bitbucket5, and I've also thrown in the ability to control the servo over both USB and serial connection.
Fig 1. Real size of this beast compared to a typical Asian hand.
Teardown
The exterior look and feel of the servo itself is pretty good: aluminium horn secured with a set screw, steel D-shaft, aluminium gear housing, with very little gear backlash (< 1deg?). I can't tell if it's using ball bearings or a bushing, but it shouldn't matter as far as hobbyist application goes. The rest of the shell is just plastic which could shatter when dropped.
Preliminary testing with a servo tester and 12V power supply shows that the servo is pretty strong, but just fails to be accurate. This result suggests that the internal feedback loop implementation uses only the P-component, instead of the full PID6. It takes a standard 1-2ms servo pulse width and seems to work fine at 50Hz, 150Hz and 250Hz.
Time to butcher it to see what makes it crappy tick.
Fig 2. Top-cover off!
All it takes is removing 6 long screws and off goes the cover. It is nice to see rubber grommets around the power and signal cables, but overall it does jack in terms of waterproofing due to the obvious gaps between the plastic shell and metal gearbox. The wires also move freely so you could potentially break a wire off its solder joint if you pull the wire too hard. Nice thick wires, traces and solder pads are used for the high-current paths.
The plastic screws holding down the PCB are pretty bad. They are loose and just cannot be tightened due to terrible quality resulting in stripped threads. I replace them with M3 5mm countersunk screws instead.
The two trimmers at the bottom are used to adjust the speed of movement and maximum angle. By default they are at the fastest and widest settings, potentially useful if you want to reduce its movement speed/range, at the expense of reduced accuracy. Note the solder-bridges at the bottom left for 360-mode (continuous rotation) and VR (variable resistor) input. I've not tried the VR input (notice it is not soldered there), but the 360-mode is less than desirable. Depending on the input pulse width, it goes into "full speed clockwise", stop, (it actually uses inductive braking) and "full speed anti-clockwise". It'd be more useful if there were some form of speed control proportional to the input.
There are other unsoldered pads R, C, S, V which I couldn't figure out what they're for. C and V are Common (GND) and +5V respectively, whereas R and S seem to route towards the two trimmers.
Fig 3. PCB Top-side
At the heart of the servo is an STM8F003F3 microcontroller7 (MCU) and upon inspection the first thing that comes to mind is: where is the crystal? It turns out that the MCU uses its internal 16Mhz RC clock source. Doesn't the RC suffer from timing inconsistencies? Well, for a hobbyist product, I can't expect much out of it, can I?
Even though the documentation states that you could use the 5V line from the servo, you probably don't want to put any large loads on it. Both the on-board 12V and 5V regulators are linear, and I don't think it's a good idea to draw more than 200mA on the 5V line.
Fig 4. PCB Bottom-side.
The bottom of the PCB has the 4 MOSFETs forming an H-Bridge for driving the motor. It's good that there is a generous amount of thermal paste applied to ensure decent thermal contact between the MOSFETs and the aluminium body. While I am not too interested in the other 8-legged MOSFET drivers and logic gates, it is worth noting that they do use an AS5600 magnetic position sensor8! This means that we could potentially have a great positional feedback system.
Now here comes the kicker.
The AS5600 device supports I2C, PWM, and analog signal output, proportional to the angle of the magnet (attached to the rotating output axle) with respect to the device. As it turns out, the original designer/engineer have chosen to use the analog output instead of the digital outputs which the MCU is totally capable of accepting! It's like buying a car which supposedly has a 2.4L engine but eventually has a 1.4L equivalent through some poor design choices.
As I examine the analog output I find that it is very noisy (I wish I have a scope, but I don't; so I just print out numbers on the screen). It is now no surprise to me as to why the on-board feedback loop is implemented in such a terrible manner. Adding a wide input deadband means that you could get away with a noisy signal while still able to have a functional product.
My initial suspects for the terrible signal condition are the lack of proper separation between the grounding used for the motor and that used for low voltage signalling, with both coming to a single point close to the negative wire, and the presence of a high current path for MOSFET switching that runs in parallel to the signal. It is evident that there have been no attempt to correct these fundamental flaws.
Approach
Considering that I want to spend as little time as possible figuring out how to make this servo more useful than being an inconveniently odd-shaped paperweight, the obvious solution is to drop in a cheap Arduino-compatible device. I happen to have a handful of Pro Micros9, often used as electrical glue to stick some disobedient electrons where I want them to be. The modification only requires a single wire soldered onto the PCB, tapping the analog output of the AS5600. Reprogramming the AS5600 (if at all possible) is deemed too much of a hassle at this time.
Fig 5. Where to tap the analog signal
I reuse the red servo wire as I have do not intend to draw 5V from the servo. The wire is pulled over, soldered to the point and hot-glued down for sanity. It can be done with a reasonable amount of skill without removing the PCB.
Fig 6. Schematic -- you can use pretty much anything as long as the code is modified appropriately.
I first have to tame the noisy positional signal coming from the AS5600. By chance I find that simply adding a 1uF cap and 10K resistor allows me to get a decently stable reading on analog input A0.
D9 is then used to send a servo-compatible PWM output back to the servo.
I thus create a secondary feedback loop in an attempt to compensate for the flawed accuracy by:
- taking a desired position via USB/serial
- taking the current position from the AS5600
- sending the desired movement signal back to the servo
The secondary feedback loop makes use of all three PID tuning constants, albeit slightly different values for clockwise and anticlockwise movement due to the peculiarities of the servo. The movement parameters for executing a large swing vs small adjustment are also different thanks to quirks in the servo. A relatively large I constant also helps with fine-tuning when driving loads with heavy resistance.
After a few iterations of manual tuning, I conclude that there is a lower limit to the settling time due to the inherent latency within the servo. The settling time is around 1-2 seconds and no oscillation is observed. The constants in the code should be relatively easy to tweak should there be any minor variation in different batches of the same product.
I decide to stop here as I have already achieved a positional accuracy of ~1 deg and I have reached my goal of not needing to use an expensive Dynamixel10 of similar torque (well, the highest I could find).
Future Work
- Reprogram the AS5600 to output at least a PWM signal instead of analog. Not too sure if this is possible without de-soldering.
- Refactor the code into a class/library for easy reuse across multiple servos.
References:
2. https://world.taobao.com/item/529399911190.htm?spm=a312a.7700714.0.0.lKZSfe#detail
4. A low cost arduino-compatible MCU, often costing a single-digit dollar.
5. https://bitbucket.org/yongkimleng/sillyservocompensator/
(Note that it was not tested after cleanup and removal of debug code and may have bugs)
6. https://en.wikipedia.org/wiki/PID_controller
8. http://ams.com/eng/Products/Magnetic-Position-Sensors/Angle-Position-On-Axis/AS5600
10. http://www.trossenrobotics.com/p/mx-106t-dynamixel-robot-servo.aspx