diff options
Diffstat (limited to 'posts/building-the-a1')
-rw-r--r-- | posts/building-the-a1/main.md | 144 | ||||
-rw-r--r-- | posts/building-the-a1/meta.json | 4 |
2 files changed, 148 insertions, 0 deletions
diff --git a/posts/building-the-a1/main.md b/posts/building-the-a1/main.md new file mode 100644 index 0000000..e2c3e27 --- /dev/null +++ b/posts/building-the-a1/main.md @@ -0,0 +1,144 @@ +Building the A1 Differential Drive Robot +======================================== + +![Robot](/img/robot.png) + +Recently I embarked on a project to build a differential drive robot +from commercial parts. I intend to eventually use this platform for +testing sensor fusion, localization, and mapping techniques. Initially, +I built a platform to accomplish a simpler goal; to navigate along a +user selected path. + +## System Design + +![Robot with Labeled Components](/img/robot_labeled.png) + +### Motor Selection and Mounting + +The robot was designed to navigate through an indoors environment at a +speed of 40 cm/s which seemed reasonable. I was also concerned with +selecting motors to achieve a smooth drive, especially when navigating +over high friction surfaces like carpet. I searched for motors which +could sustain around half a newton of force tangent to the wheel +continuously. Often, one would consider continuous rotation servos in +this case since they provide a gear motor with built-in closed-loop +control. Continuous rotation servos which operate in this range can be +quite expensive so I opted for a 110 rpm 5 kg cm DC gear motor. The +motor came with a quadrature encoder that I used to provide feedback for +a closed-loop control algorithm. + +To mount the motor to the drive base, I created two mounting plates +with a motor cage. This cage mounted to the bottom of the base plate +with M3 screws. I also attached a passive caster to the base plate +through a 3D printed offset. The base plate was made of 2 mm +polycarbonate. + +### Electronics + +To control the motors, I ended up using two Arduino Nanos because each +motor requires two interrupt pins for each quadrature signal. A single +Arduino Mega could be used to trigger interrupts but I had Arduino Nanos +on hand. The Nanos interfaced with a TB6612FNG H-Bridge to provide speed +control from a 12 V supply. A RPi 3B+ was used to perform the path +calculations. The Nanos only have 2.5 kB of SRAM so the paths are stored +on the RPi and fed over the I2C bus. Or at least, that was the idea. The +current version stores the paths in flash. More on that later. + +To power the robot, I used a three cell LiPo battery. This was +connected to a BMS which provided over current and over discharge +protection. The BMS output distributed power to each motor and a 5V +buck-boost converter. Each was protected by a fuse. + +## Control Algorithms + +The motion pipeline are composed of three stages: + +1. Trajectories are generated on the RPi. These are provided to the + motor controllers over the I2C bus. +2. The encoder signals are decoded and the position estimation is + updated. +3. The trajectory and current motor position are used to calculate the + input voltage for the motors. + +### Trajectory Generation + +The paths are specified parametrically in the form `<x(k), y(k)>` +This is transformed into a trajectory `<x(t), y(t)>` by time +parametrizing it. This is a non-trivial problem since the rotational and +forward velocities of a differential robot are intertwined: if motors +are operating at their maximum velocity, an increase in the rotational +velocity requires a decrease in the forward velocity. To plan a +trajectory along a path, the maximum forward (tangent) velocity was +calculated at each position `k` along the tangent path. This velocity +limit varies with the curvature; the higher the curvature, the slower +the robot can navigate along the path. Numerically, the forward velocity +limit imposed by a single wheel (left or right) is proportional to the +derivative of the tangent arc length with respect to the wheel arc +length where the constant of proportionality is the max motor velocity. +This provides a ceiling on the tangent velocity. The initial and final +velocities along the path are known. This same process can be used to +bound acceleration. The exact forward velocity transitions can be +determined by a motion profile tuned to stay within the boundaries of +these constraints. In my case, I used a simple trapezoidal profile. The +tangent velocity function can be used to identify the position +trajectories of each wheel. (In terms of path length.) These wheel +position trajectories were fed to each motor controller. + +### Encoder Feedback + +In order to provide accurate motion control, the system monitors the +position of the motor and uses this information to make more informed +estimates of the input voltage required to reach the target position. +Quadrature encoders emit square waves on two channels A and B. +Transitions in the signals A and B encode changes in the motor +position. For instance, when A transitions from low to high while B is +low, this indicates that the motor has moved one section of an arc in +the forward direction. If B made the transition before A, the encoder +would move in the opposite direction. To decode the signal, the +algorithm keeps a running tally of the number of arcs recorded. Each +signal state is encoded in two bits. Following each state transition, +the two bits representing the prior state and the two bits representing +the current state query a lookup table containing the eight possible +states. The counter is incremented or decremented according to the table +entry. This maintains an accurate record of the encoder position. I\'ve +seen similar techniques in use elsewhere. In my case, this routine was +triggered by a hardware interrupt. Triggering on interrupts ensures the +algorithm doesn't miss a state transition while carrying out other +control tasks. + +### Position Control + +Armed with the trajectories, each motor controller was tasked with +providing the correct input voltages to reach the designated positions. +To accomplish this, it used feed forward motion control. Using this +technique, the algorithm makes a crude initial guess at the input +voltage. Then, it uses the known position, as obtained by the encoder, +to correct this initial guess. A PID controller is used to make this +correction. PID controllers are used commonly in industrial +applications. Feed forward techniques, while less common, increase the +responsiveness of the system to changes in the input position. + +``` +voltage = k_vf * v_setpoint + k_fa * a_setpoint + k_p * err + k_d * derr/dt +``` + +## Known Issues + +There are two main challenges with the current design. The first is +that the 2 mm polycarbonate is flexible causing distortions in the width +of the drive base. To mitigate this while testing, I added additional +support to prevent the base board from flexing. A simple fix would be to +combine both motor mounts into a single 3D print to add additional +support. The second more significant issue is that the motors cause EMI +on the I2C bus. I find it highly likely that this is due to high ground +currents. I am currently experimenting with bus isolators to prevent the +noise from affecting the bus. + +## Results + +The result is a robot which can follow an input trajectory with +surprising accuracy. I tested the robot against cosine, ellipse, and +figure eight trajectories. In my testing, the robot generally deviated +less than a centimeter along a five meter path. + +![Results GIF](/img/results.gif) diff --git a/posts/building-the-a1/meta.json b/posts/building-the-a1/meta.json new file mode 100644 index 0000000..a9edc7d --- /dev/null +++ b/posts/building-the-a1/meta.json @@ -0,0 +1,4 @@ +{ + "name": "Building the A1 Differential Drive Robot", + "lastUpdated": "2022-05-30" +}
\ No newline at end of file |