Differential Drive

KD01 Side View

This is the first in the multi-part series about the KD01 Robot ( 1 | … ).

As I described in my series of posts on the KR01 robot, I got back into robotics after watching a YouTube video of the DPRG‘s David Anderson demonstrating his robots, talking about the details of their design and how they work. I’m very happy to say that David and I are now friends and he’s been mentoring me and answering some of my more tedious questions with the patience of a very good teacher.

The basic design of a differential drive robot

The KR01 robot uses a motor controller running a pair of motors on the port side and a pair of motors on the starboard side. The motors are wired up in parallel, so the four motors are treated (electrically) like a single pair of motors. But performance-wise they don’t act like two motors.

If I program the KR01 to rotate in place, how it performs depends a lot on what surface the robot is on, as with four motors the robot relies upon the slippage of its black silicon rubber wheels to permit it to rotate at all. And how the robot’s weight is distributed influences which wheels slip and which don’t. On a relatively sticky surface like a wood floor the KR01 visibly shudders as it tries to rotate in place. If it rotates continually it tends to move randomly across the floor.

All of this is due to those four wheels, which provide a lot of stability and are great for four-wheeling out on my front deck, but not so great for precise navigation, or rotating in place. The solution for this is a different robot design, called a differential drive robot.

At about 2:30 in David’s video he says:

“The advantage of differential drive is a zero turning radius. Zero turning radius is what we humans have, so if you want to build a robot that can run around in the same space as humans run around in, it’s a useful thing to do. And that means we can turn around pretty much in our own space. There’s some tremendous advantages to being able to do that. It greatly simplifies your navigation software if you don’t ever have to back up.”

David Anderson’s SR04 robot
(image used with permission)

The other part of the design requirement for a differential drive robot in being able to turn in place is that the full extent of the robot fit within a circle, with its tail wheel placed on the perimeter of that circle. If the tail wheel or the robot frame extends beyond that circle the robot won’t be able to turn in place without bumping its big bum into something.

Now, I’ll still be using the KR04 for many of my robotics experiments, but I wanted to try out a differential drive robot. I realised the design I now had in my head looked remarkably like something I’d seen before. David’s robots are typically differential drive designs, such as his SR04, the robot that inspired me to start building robots again, and it now seems a bit like the older brother to my new robot, which I’ve dubbed the KD01, where the “D” is for Differential. I stilll can’t think where the “K” came from…

KD01 Requirements

So in addition to desiring a differential drive robot, I thought the new robot should be able to re-use wherever possible the existing ideas, components and parts from the KR01, including its motor controller and drive train: the OSEPP 9V 185rpm motors, annodised aluminum wheels, silicon rubber tires, and Hall effect motor encoders. As the encoders are designed to be mounted on the same beam as the motors, this entailed even the same OSEPP/MakeBlock chassis components.

The KR01 and KD01 drive train showing motors and Hall effect motor encoders (click to enlarge)

The KR01’s four motors and four wheels permit a substantial carrying capacity, but its Makita 18v 6.0Ah power tool battery weighs 760g (1.7lb.). By comparison, the KD01 without batteries weighs 1525g; having a battery weight half that of the robot seems a bit extreme. Also, two drive wheels and half the number of motors doing all the work suggested something a bit lighter, perhaps the Makita 12v 2.0Ah power tool battery, which weights a 263g, some savings in both weight and size.

The Integrated Front Sensor

The KR01’s Integrated Front Sensor (IFS) supports five Sharp 10-150cm analog infrared sensors and three pairs of small lever switches attached to a clear polycarbonate plastic bumper. I definitely didn’t want to have to build this another time if I could reuse it.

To be able to mount the IFS requires chassis compatibility with the KR01. Thankfully this is simple, as the IFS is attached to the front of the robot with two 5mm stainless bolts and to the Raspberry Pi via a single five-wire I²C connector. With this hardware compatibility I can transfer the IFS between the two robots and use much of the same sensor software I’ve already developed. All this will save me a lot of time and trouble. Re-use is good.

The overall design is based around the existing drive train, with its 18cm (~7 1/8″) wheelbase.

I thought about buying a fancy German-made caster, but decided to build my own from a spare OSEPP wheel mounted with some the roller bearings (that came with their tank robot kit) to a commercial caster swivel mount, even using a pair of chrome guitar strap buttons as spacers. The end result is quite tall, but means that the KD01 will use three wheels of the same size, no small back caster that might reduce the floor clearance.

The tall back caster required a stepped platform with enough clearance for the caster to swivel 360 degrees. With the battery mounted just slightly behind the wheel axis, just getting everything onto the robot platform was a challenge. I ended up locating the ThunderBorg motor controller and the board holding the connections to the encoders underneath the battery, with the Raspberry Pi at the back of the robot, as was done with the KR01.

With all that I took to paper. Design is largely juggling all the requirements and constraints. and this was no exception.

The KD01 Differential Drive Robot

Things came together pretty quickly once I’d finalised the design on paper. I cut the two chassis pieces out of 3mm black Delrin plastic, using L-shaped aluminum for other parts of the frame and to provide a bed for the battery above some of the electronics.

The boards are held together using 3mm Lynxmotion anodised black aluminum hex standoffs. These are lightweight and strong, and permit the robot to be disassembled easily. I’ve been using M3 (3mm) stainless nuts and bolts for pretty much everything now.

The KD01 from above

The photo above shows the Raspberry Pi 3 B+ and a Pimoroni Breakout Garden hat at the rear (left), the Integrated Front Sensor at front (right), and the PiBorg ThunderBorg motor controller underneath where the battery sits. It’s currently sporting an Adafruit BNO085 IMU on a sparkly red nylon mast (made from a cutting board), and another Adafruit FXOS8700+FXAS21002 IMU mounted on a small black breadboard, affixed to the robot using small velcro dots. I’m currently doing some experiments with two IMUs. I also decided it was helpful to have a tiny Adafruit 135×240 Mini Pi TFT display screen as I had one in my inventory, so this was mounted on a 3mm Lynxmotion standoff using some bits of L-shape aluminum to provide a 3D swivel adjustment.

While the drive wheels and caster fit within a 212mm circle, the Integrated Front Sensor does extend outside of the circle, but not by much. This does mean that rotating in place could potentially catch the edge of the polycarbonate bumper on something as the robot turns. David’s SR04 is similar in this regard. He solved this in a later robot called the RCAT, which uses a curved plastic front bumper that fits within the extent of that circle. A great design.

Rotate in Place

Well, how did we do mechanically? I took the robot out onto the front deck and tried it out with a rotate-in-place.py test. On the deck the robot’s wheels hitting the spaces between its boards seemed a distraction, so I tried it again on a piece of smooth particle board. The result was posted to the NZPRG YouTube channel:

A Problem Exposed

Running a test sometimes exposed other problems. This was evident when running the KD01’s port wheels counter-clockwise: the encoder outputs were way out of range. Normally (such as on the two encoders of the KR01 or the starboard encoder of the KD01) there’d be almost exactly 494 steps per wheel rotation, but the port encoder on the KD01 was registering an inconsistent 337-342 steps per rotation but only when running counter-clockwise. I pulled out the trusty ol’ Iwatsu oscilloscope and wired it up to the encoder outputs with the robot on the bench.

Hardware debugging using the Iwatsu SS-5710 (circa 1991)

The only thing that seemed obviously different about this encoder is that the offset between the A and B waveforms’ falling edges was very close together.

The A and B waveforms before (left) and after (right)

In the image on the left you can see that the distance between the falling edge of the A (top) and B (bottom) waveforms almost coincides. This means that when the quadrature measurement occurs, the alternate waveform may not be in its opposite state and the tick count won’t change. On the other three encoders the two waveforms are significantly more offset.

It’s good to have some friends with experience. In this case, on today’s video conference with the DPRG I asked Carl, Doug, David and the other experts and they totally knew the problem was with that offset, or the lack thereof.

So I turned the KD01 upside down, pulled the little disk magnet off of the motor shaft, and very very carefully bent one of the tiny three-wire encoder sensors very very slightly, maybe a tenth of a millimeter. While its distance to the magnet seemed okay, it wasn’t quite parallel with the surface of the magnet. I then put everything back together, wired things up again and guess what? That fixed it. The image on the right shows the waveform after the adjustment. The offset between the two waveforms is now almost exactly 90 degrees, and the edge transitions now occur a long way from each other.

To check, I hand-rotated the port and starboard wheels while counting the encoder ticks with my motors_test.py program. The port encoder now turns -4941 ticks over ten clockwise turns of the wheel, and +4939 ticks over ten counter-clockwise rotations. Or 494 ticks per wheel rotation in either direction.