DFRobot Devastator DIY Driver Circuit
A DIY circuit to wirelessly drive the DFRobot Devastator tank.

Introduction
These were the requirements I set out at the start of the project:
1. High motor driving efficiency
2. Able to run off NiMH batteries
3. No ICs apart from the microcontroller
4. Wirelessly controlled
5. Can build on perfboard
Initial work
To design the electronics, we need to focus on the motor parameters. The motors have the following specifications (from the manufacturer's page):
- Rated Voltage: 6 V
- Operating Voltage Range 2~7.5V
- Gear reduction ratio: 45:1
- D output shaft diameter: 4 mm
- No-load speed: 133 RPM @ 6 v
- No-load current: 0.13 A
- Locked-rotor torque: 4.5 kg.cm
- Locked-rotor current: 2.3 A
H-bridge control

For the MOSFETs, I decided to have a bit of fun and make a kind of "H-bridge module" out of three SOIC-8-packaged MOSFETS - two single P-channel MOSFETs and one dual N-channel MOSFET. I chose this configuration since for the same size, P-channel MOSFETs usually have a higher resistance, so to be in the same class of on-resistance, you usually need P-channel to be larger than N-channel MOSFETs. This meant that I could fit all three packages on one SOIC-28-to-DIP-28 adapter. I also made a custom KiCAD symbol for this module explicitly labeling the sources, gates, drains, body diodes, and pairs of the module:

The driving circuit was one area that required some thought. As I chose no ICs, I didn't have the ability to use an external gate driver to drive P-channel MOSFETs. This led to an issue that many people reach in such circuits - your MCU outputs 3.3V to 0V. When you use any motor of a decently high voltage, the P-channel MOSFET needs to go up to the full supply voltage or even higher to turn off. If you try to control your MOSFET with the MCU pins, you can't actually turn it off.
One traditional solution is to use a gate driver, which allows you to treat the P-channel MOSFET like any other N-channel MOSFET. It handles the voltage translation for you and stands between your P-channel MOSFET and MCU pins. Most gate drivers also have a higher drive power, allowing you to have more precise control over turning your P-channel MOSFET on or off without staying in the linear region, resulting in lower power losses. This is great, but it's also an IC, which I didn't want to use.
The simpler alternative - which trades off performance for simplicity - is to use a small N-channel/NPN transistor with a pull-up resistor. When the MCU wants to turn off the P-channel MOSFET, it outputs a LOW/0V, the N-channel/NPN doesn't turn on so it's an open circuit, so through the pull-up resistor, the gate voltage is equal to the source voltage and the P-channel MOSFET is turned off. When the MCU wants to turn on the MOSFET, it outputs a high voltage, turns on the N-channel/NPN, this brings the gate of the P-channel MOSFET to ground, and so it turns on. This alternative is much slower to turn off because the MOSFET gate charges through a pull-up resistor, so it is not used in circuits where the P-channel MOSFET needs to switch often.
For the N-channel MOSFETs connected to the motor, I chose to drive them from the MCU pins through a 100 ohm resistor to protect the MCU pins from current spikes and ringing. Additionally, the N-channel MOSFETs have their gates connected to ground with a 10k resistor to avoid random voltages accidentally turning them on. In retrospect, the 100 ohm resistor may have been too high. I recommend replacing it with a 10-47 ohm resistor.
This is what the final schematic ended up looking like:

1. AOSP21321 for the P-channel MOSFETs (rated 11A continuous)
2. AO9926B for the N-channel MOSFETs (rated 7.6A continuous, 1.8V minimum input logic level)
3. 2N3904 for the NPN
All of the MOSFETs comfortably exceeded both the current and voltage requirements for the motors. Yours should too.
Note 2: the voltage in the circuit is labeled as 9V since that is the absolute highest possible for my configuration of 6x NiMH cells in series. The NiMH voltage curve is very steep at high voltages, so the 9V (more commonly 8.4V) condition during max charge decreases down to 7.2V quickly. A compatible configuration would be 4x 1.5V alkaline cells or 2x Li-Ion cells.
Note 3: you can substitute the STM32 with any microcontroller you want. Initially, I was going to do this with a PIC16, but I wanted much more code and processing capacity to be able to make the algorithm more complex in the future. With the current configuration, even a PIC12 could probably do the job.
Control microcontroller
Due to the asymmetry of my MOSFETs (P-channel turn on/off very slowly, N-channel rather quickly), I decided to implement a type of PWM control called "sign-magnitude control". This means that instead of switching both the P-channel and N-channel MOSFETs rapidly - as is traditional PWM - I turn on the P-channel MOSFET fully and switch the N-channel MOSFET only. This table shows the tradeoffs of this:

Note that in the sign-magnitude configuration, the P-channel body diodes do flyback protection, but that recirculates at every PWM cycle during the off-time. This is a regular diode with a 0.7-0.8V voltage drop, which is an inefficiency. This can be mitigated by placing Schottky diodes in parallel, and almost completely eliminated with synchronous rectification (or in other words, the full independent PWM variety).
The code is very standard - it just implements this type of control using the STM32's built-in PWM channels + timers. The PWM operates at 20kHz, which is a frequency just above the audible range, so the motors don't make an annoying sound when driven.
However, here I came into my first major roadblock - I wanted to have a decoupled system where the MCU could either be controlled through a local wired interface or a wireless one. I needed to implement both a second microcontroller with wireless capabilities and a protocol to safely communicate between them. Neither of these are trivial issues - wireless control is a notoriously tricky problem and communication protocols with vehicles always carry the risk of the communication breaking and the vehicle continuing to move and being unable to stop or receiving a malformed command and moving in an incorrect direction. For simplicity, I decided to use UART as the physical layer between the microcontrollers and designed a protocol on the levels above.
My custom designed protocol implemented two major fixes to the aforementioned issues:
1. The secondary microcontroller had to send a heartbeat signal every 500ms. If it didn't, the motors would be shut off. This meant that if the secondary microcontroller shut off and the motors were moving, they wouldn't continue moving after communication stopped.
2. The microcontrollers had to communicate with synchronization bits so that each packet begins with a sync/preamble byte for framing, followed by the payload and a CRC. Essentially, this made it so that the primary microcontroller would be certain that it received what the secondary microcontroller intended to send. If either of these checks failed, the motors would stop.
The choice of the secondary microcontroller was limited to the wireless controller I had available - the wonderful DualShock 4. Despite Sony never publishing information about its operation, the BluePad32 project (https://github.com/ricardoquesada/bluepad32) reverse-engineered all of the necessary code to allow a standard ESP32 to connect and fully read from the DualShock 4 (as well as many other controllers). Pairing to and reading from the controller was trivial. I implemented the custom protocol on the ESP32 end and connected it to the STM32. It worked from the first try. All code is included in this project.
Note: I ported the STM32 code from PlatformIO to STM32CubeIDE and am publishing the code for STM32CubeIDE since I believe most users prefer that workflow and would prefer to have an original MCU.
Note 2: I use the standard original ESP32(-WROOM) DevKit as my ESP32 board. The Arduino library lists all of the supported variants.
Assembly and soldering
The soldering process was nothing special. I put on a documentary in the background and followed the principles of making a good, thick ground and voltage rail, minimizing length and using resistor legs to jump over most of the board. I mounted the MCU board on female pin headers to be able to remove it later.

I used JST-XH connectors for all battery connections (because it's locked and can only be plugged in one direction) and regular pin headers for the motors (to allow for reversing physically). I got both from a Lidl crimping kit, which I sincerely recommend.
For the battery pack, I made a separate board where I connected individual AA battery holders in series and added a 1000uF capacitor to smooth voltage drops when the motor switches direction.

3D-printed mounting shrouds

Since there was no space for the ESP32, and it won't be permanently in the design, I designed a separate shroud to sit on the top of the tank. I made an oversight in the printing - the thin and tall features failed to print after a certain height, so I canceled the upper vertical half of the print, but the structural part of shroud had already printed. The design should be revised. If you print this, print up until half of the height or even less. Nevertheless, the bottom part of the top mounting shroud works well:

The screw holes of the DFRobot Devastator are all 3mm. I used Torx screws with a wide head and the print's holes are nominally 3mm, which in my experience allows for an adequately strong connection. This is what the top came out looking like:

Observations
Conclusion

Diskussion (0 Kommentare)