Andy's Blog

A handful of ramblings...
Font size: +
24 minutes reading time (4736 words)

Omnibot Custom Controller and Remote V1


Now that you have your new drive tray and new servo arms in place, you need a controller and remote. You could use a commercial RC hobby controller that has the ability to mix mecanum wheels. However, depending on your goals, you might miss out on some expandable options that can really only be done with a microcontroller such as controlling screens (as in the Omnibot Eyes project - yet to come).

This particular build is more of a proof of concept than a finalized build. However, the concepts that it tests will likely be incorporated in the next version of the controller and remote. Additional features that are in development may change the characteristics of this build as it is a PoC.

NOTE: This build is meant to demonstrate how to drive the new base motor drivers and new arm servos and as such this build is very likely to change between now and the next iteration.

NOTE: Currently, this build does not include the Omnibot Eyes additions but does reference some of the components used in the remote.

Parts List - Main Controller

Parts List - Remote Control

Tools Needed

  • 3D FDM printer or access to one
  • Appropriate screw driver for the screws listed above
  • Precision knife or deburring tool for 3D parts cleanup
  • Drill bits - 1/8in (3.18mm),
  • Drill

Pre-Build Notes

  1. Warning: Before we begin, you should know that this modification is not possible if you still want to use the original electronics. This build assumes that you will not be using the original electronics and tape drive.
  2. Note: You will want to retain and reuse the 8 original drive tray screws from the bottom of the Omnibot and the 3 screws that hold the tape drive in place.
  3. Note: This build describes what I used to control the robot however these motors can be controlled by all of the usual methods such as a hobby RC controller, microcontroller such as an Arduino, ESP32, Teensy, etc, or full blown PC GPIO control. What you use to control your system is up to you.
  4. Note: Go ahead and print your plastic parts from the kit linked above and clean up the prints before beginning. Each of the screw holes should be drilled out with the appropriate bit (M3 holes use the 1/8th in bit). Make sure that any stringing is removed and that burrs are also removed.

Step 1 - Prep Plastics

The link above to the 3D models of the tray and smaller parts is as follows:

  1. Remote control holder that fits in the front of the Omnibot where the tape deck originally was.
  2. Remote control enclosure that holds the remote circuit.
  3. Remote control cover that is held in place by two small screws.

First clear any stringing or burs from the printed parts. Generally, burs can prevent the remote from sliding easily into the holder or the remote cover from fully seating in the remote enclosure. Additionally, burs or stringing may prevent the PS2 thumb sticks from fully moving in their openings.

Step 2 - Main Controller Circuit

NOTE: I would strongly recommend two things going forward. First, build your circuit on a breadboard before soldering the circuit on your perfboard. This will highlight any wiring mistakes before it is difficult to fix. Second, I suggest mounting your ESP32 on the female headers and the MCP23017 in the DIP socket listed in the parts list above. These parts aren't cheap and you might want to reuse these in another project or on a different board as your project matures.

Another NOTE: To test your controller, you will need to upload the code to your controller ESP32 module. The section Code Overview below details what the code is doing and gives a reference on how to upload the code if you have never done so before.

Below you'll see the broad circuit connections in the Fritzing image. Some points to note are that your board will make use of the power module on each of your two L298N modules. One 5V rail will power your ESP32 and MCP23017. The other will power the servos through the servo male headers. Powering both from just one of the L298N modules will result in brown outs when using your servos. A future version of this will use a better power converter that can handle the power requirements of the two servos. However, as this is a proof of concept, this solution will get us by.

One other note is that in the image, two breadboards are used for easier reading. In reality, I used just one breadboard with the connections running to the pins under the ESP32 module. See image below.

Lastly, references to left and right are of the bot from the bot's perspective. So, as you are looking at the Omnibot from the back the left and right would alight with your left and right. If you are looking at the Omnibot from the front, left and right are reversed - same as if you were looking at another person face to face.

The connections are as follows:

  • ESP32 VIN -> Leftside power rail connected to the left side L298N module 5V screw header.
  • ESP32 GND -> Connected to both left and right side ground rails and those to both L298N module Ground screw terminals.
  • ESP32 D21 -> MCP Pin 13 (SDA) I2C Data connection
  • ESP32 D22 -> MCP Pin 12 (SCL) I2C Clock connection
  • ESP32 D13 -> Right Side L298N ENA - Front Right Drive Motor
  • ESP32 D12 -> Right Side L298N ENB - Rear Right Drive Motor
  • ESP32 D14 -> Left Side L298N ENB - Rear Left Drive Motor
  • ESP32 D27 -> Left Side L298N ENA - Front Left Drive Motor
  • ESP32 D26 -> Right Arm Servo Data
  • ESP32 D25 -> Left Arm Servo Data
  • MCP23017 Pin 1-8 are not connected to anything (NC)
  • MCP23017 Pin 9 (VDD) -> 5V and ESP32 VIN
  • MCP23017 Pin 10 (VSS) -> GND
  • MCP23017 Pin 11 -> NC
  • MCP23017 Pin 12 (SCL) -> ESP32 D22
  • MCP23017 Pin 13 (SDA) -> ESP32 D21
  • MCP23017 Pin 14 -> NC
  • MCP23017 Pin 15 (A0) - > 5V
  • MCP23017 Pin 16 (A1) -> GND
  • MCP23017 Pin 17 (A2) -> GND
  • MCP23017 Pin 18 (RESET) -> 5V
  • MCP23017 Pin 19 -> NC
  • MCP23017 Pin 20 -> NC
  • MCP23017 Pin 21 (GPA0) -> Left Side L298N IN1
  • MCP23017 Pin 22 (GPA1) -> Left Side L298N IN2
  • MCP23017 Pin 23 (GPA2) -> Left Side L298N IN3
  • MCP23017 Pin 24 (GPA3) -> Left Side L298N IN4
  • MCP23017 Pin 25 (GPA4) -> Right Side L298N IN4
  • MCP23017 Pin 26 (GPA5) -> Right Side L298N IN3
  • MCP23017 Pin 27 (GPA6) -> Right Side L298N IN2
  • MCP23017 Pin 28 (GPA7) -> Right Side L298N IN1
  • Left Side L298N 12V Screw Terminal -> Barrel plug + screw Terminal
  • Right Side L298N 12V Screw Terminal -> Barrel plug + screw Terminal
  • Left Side L298N GND Screw Terminal -> Barrel plug - screw Terminal
  • Right Side L298N GND Screw Terminal -> Barrel plug - screw Terminal

In the project Omnibot 'Eyes' Modification, I discussed using two Waveshare round LCD Screens for digital eyes or other animations to replace the original red LED "eyes." These screens will need to use the hardware SPI pins with two different chip select pins. If you plan to follow me in this adventure, then you will want to reserve ESP32 pins D23, D19, D18, & D5 for this use.

Once you have successfully tested this configuration on a breadboard, solder this circuit on your perfboard. Placement of the components is not critical with this board except:

  • My layout takes advantage of the middle screw hole to mount the perfboard to the remote holder box.(See picture below)
  • I highly recommend that you use headers to connect any wire between the main controller board and a seperate device such as a servo or the 12 wires that run between the controller and the two L298N motor drivers. This will make installation much easier and reduces the chances of breaking wires at the solder points.

Also, I used the same kind of breadboard jumper wire to connect my circuits as I used on the breadboard. However, feel free to use small gauge stranded wire if that is more convenient.

Step 3 - Controller and Tray Assembly

Once you have assembled and tested your circuit on your protoboard, you can install it in the Omnibot. First slide in the remote holder into the opening that previously occupied the tape deck from the inside. Then replace the three screws that held the tape deck into the body of the bot.

Next, add the 10x2mm magnet in the recess in the back of the holder. If this isn't snug enough to hold the magnet, you can use a drop of CA glue or hot-glue to hold the magnet in place.

Next, insert the M3x10mm flat head screw through the hole in the front of the holder. The top of the screw should fit flush inside the recessed hole for the screw. This will secure the circuit board to the back side of the remote holder.

While holding the screw from the front of the bot, attach the circuit board through its middle screw hole to the screw on the back of the holder and affix with the M3 nut. The board will only fit vertically. I recommend that you keep the connections to the motor drivers and servos at the bottom of the board for ease of connecting them later.

If you haven't already done so when assembling your motor tray, go ahead and connect each motor to the motor driver on that side of the tray.

At this point, I would recommend mounting the front of the bot to the front 4 mounting posts in the motor tray. Connecting the front half of the body to the motor tray will help hold things together while wiring.
DO NOT FULLY TIGHTEN THESE SCREWS YET! You will need to have the parts loosely connected in order to complete assembly later.

Begin connecting the motor driver wires to the posts next to the MCP23017 referring to the diagram below. Next, connect the servos to the female headers.

At this point you should test once again before attaching the back half of the body shell.

Lastly, push the barrel connector for your power through the opening in the battery compartment in the bot shell. Slowly and carefully, line up the alignment pins between the two halves of the body shell making sure that your arm servo mounts slide centered in their respective openings. Once you get the two halves together, insert the remaining four motor tray screws from the bottom.

Step 4 - Remote Control Circuit

NOTE: Same as above, I would strongly recommend two things going forward. First, build your circuit on a breadboard before soldering the circuit on your perfboard. This will highlight any wiring mistakes before it is difficult to fix. Second, I suggest mounting your ESP32 on the female headers listed in the parts list above. These parts aren't cheap and you might want to reuse these in another project or on a different board as your project matures.

Another NOTE: To test your remote, you will need to upload the code to your remote ESP32 module. The section Code Overview below details what the code is doing and gives a reference on how to upload the code if you have never done so before.

One additional note, I use PS2 replacement modules that are not on breakout boards. These are meant to be soldered into a breadboard that has appropriate hole placement for the large ground pins on the metal chassis. These will not work in a breadboard. You can solder wires to each of the pins on the two variable resistors for each of the two joysticks you will need for this project. If you happen to have a couple joysticks on breakout boards, then by all means use those in your tests. However, my layout below uses the raw joysticks. Using the breakout board modules will require changes to the remote enclosure and the perfboard.

Before we get into the circuit board build, let's take a look at the circuit. First, for the MCU I used a HiLetgo ESP32 with battery connector and charging circuit as linked in the parts list above. I chose this over the Adafruit HUZZAH32 because the HiLetgo module has more of the ESP32's I/O pins broken out which gives me more flexibility as I continue to experiment with the remote. You could easily use Adafruit HUZZAH32 (which is the module used in the Fritzing diagram below) if you want for this stage of the development. You will just need to make one change to the code to adapt to the missing pin reference on the HUZZAH32 which is described below.

Unlike the controller protoboard which uses traces like a breadboard to connect holes, you will need to make your circuit board from perfboard and directly solder your wires to pins. In this sense, the perfboard is primarily used as a firm structural component rather than a circuit board.

The circuit itself is really simple and straightforward at this point. You may include the parts for the future Omnibot Eyes project if you wish but they are not required to drive the bot or move the arms. They are also not connected to the MCU yet and have no reference in the code for this version of the project.

The connections are as follows:

  • ESP32 D25 -> 5mm LED anode
  • ESP32 D34 ->  Right (directional) joystick X MCU Pin (See image)
  • ESP32 D35 HiLetgo (ESP32 D39 HUZZAH32) ->  Right (directional) joystick Y MCU Pin (See image)
  • ESP32 D34 ->  Right (Directional) joystick X MCU Pin (See image)
  • ESP32 D36 ->  Left (Strafing) joystick X MCU Pin (See image)
  • ESP32 EN ->  Switch pin1
  • ESP32 D33 ->  Right slider wiper pin (See image)
  • ESP32 D32 ->  Left slider wiper pin (See image)
  • 5mm LED cathode -> 220ohm resistor -> ESP32 GND
  • Right (Directional) joystick 3.3V pin -> ESP32 3.3V
  • Right (Directional) joystick GND pin -> ESP32 GND
  • Left (Strafing) joystick 3.3V pin -> ESP32 3.3V
  • Left (Strafing) joystick GND pin -> ESP32 GND
  • Switch pin 2 -> ESP32 GND
  • Right Slider 3.3V -> ESP32 3.3V (See image)
  • Right Slider GND -> ESP32 GND (See image)
  • Left Slider 3.3V -> ESP32 3.3V (See image)
  • Left Slider GND -> ESP32 GND (See image)


Step 5 - Remote Assembly

Likely the more challenging part of this build is the custom board shape for the remote. You will want to cut the board just close enough to the full inside dimensions to cover the ledges inside the remote enclosure without making it too tight to easily get in and out. Plus the perforated nature of the board makes exact measurements difficult.

NOTE: Make sure to test your component placement before soldering down your joysticks, thumb sliders, etc.

NOTE: You will need to remove the posts on the joysticks and the thumb sliders before fitting them to the board. (see images)


The perfboard maximum dimensions are shown below. First, you will need to cut down the board to the larger rectangular shape of 126 +/-1 mm wide by 57 +/-1 mm long. The easiest way to trim perfboard is to score a groove on either side of the board at the same spot using an exacto knife or similar, then bending the board at that scoring line.

Next, the corners along the top edge will need to be removed these are each 18 +/- 1mm wide by 14 +/-1mm long removed from either top corner. For these inside cuts, deeper scoring may help. If you wind up with a diagonal break, you might use a Dremmel tool or serrated bladed to clean up your corners. This should give you the overall rough shape. Test fit it now. If it needs trimming along a side then a file or other rasping tool may help.

You'll notice in my images that there is a slot cut into the perfboard on the upper left side. this is to accomodate the longer rocker switch that I am using. If you choose a shorter rocker switch, then this groove may not be needed. However, you will want to cut a small notch to allow the two wires from this switch to pass from the front of the enclosure to the back.

Lastly from the scrap cut off the side of the board you should have enough for a smaller board that the MCU will be soldered to. The dimensions are 33mm x 70mm . This will be held up and away from the larger board by two standoffs as mentioned in the parts list. On this board you will mount one 20 pin female header and one 16 pin female header spaced 10 spaces apart for the HiLetgo module OR one 16 pin female header and one 12 pin female header spaced 9 spaces apart for the HUZZAH32 module.

Final Wiring and Assembly

After creating your perfboards and testing the layout of the joysticks, sliders and the status LED, go ahead and solder those items in place through the board. Next, go ahead and wire up all of the components per your earlier breadboard tests by the wiring diagram above. After this is completed, go ahead and push the rubber thumb grips on your joystick posts.

Note: It is really easy to reverse your wiring when looking at your components from the bottom of the perfboard. I would start with all of the grounds first. If it helps, you can draw out your pins and wiring as seen from the bottom of the board.

One other note is to give yourself a bit of extra wire from the front switch on the case to the board. You will want enough wire so that you can pull the assembly all the way out for maintenance and connecting the battery.

Before you put the board in the case, make sure to connect your LiPo battery. The board assembly should slide into the remote enclosure easily - making sure to line up your status LED. Holding the assembly in place, check that the joysticks move easily throug the openings and that the sliders are centered.

Next you will need to use three of the small 2mm wood screws to secure the main board to the inner shelves inside the enclosure. Don't use an automatic or power driver for this - insert these by hand being careful not to strip the screws through the plastic.

Code Overview

Preparing to Upload

First, you will need the code. You can find the code under my Git project This project has both the Controller and the Remote code as two folders under the same project. You can download the whole project by clicking the green <>Code button and selecting Download ZIP.

You will also need to use the Arduino IDE or some other compiler to upload the code to the modules. If you are new to the Arduino IDE and using an ESP32 module, then stop here and take a look at this article that describes how the were's and hows of installing the Arduino IDE and adding the references to the ESP32 board libraries:

For the main controller, you will need to choose the module named "DoIt ESP32 Devkit V1" and choose the port that appears when you plug your module to your computer via a USB cable.

For the remote using the HiLetgo module, you will need to choose the module named "DoIt ESP32 Devkit V1." If you are using the HUZZAH32 module, then you will look for the module named "Adafruit ESP32 Feather."


When working with Mecanum wheels, you need to have a feel for what they are doing in order to understand how to drive them. In the video below, the history and physics of a mecanum wheel set is explained better than I could in text here.


The Remote Code

Let's start with the code for the remote, it will help in understanding what the main controller is doing later.

After watching how these wheels work in the video above, how do we control them easily in a way that makes sense? Idealy, we want to control how much each of the 4 wheels turn and in what direction to get the maximum amount of control. However using 4 controls (one per wheel) isn't at all intuitive. When we control things we think about them moving forward backward and left and right - like a car. However, in this case you can move just as easily laterally (to each side) as you can forward and backward. This is called strafing. You can also mix your forward and lateral movement to get diagonal movement. This can be handled with one joystick.

What about turning? How do I rotate the bot around it's center? In our code, that is what the other joystick is used for - rotation around center. So, what happens if you rotate and strafe? Then you would expect to mix these two controls and get a turn around a circle, not the center of the bot.

You are probably beginning to see that this code is getting complicated. Fortunately, there is a short video that does a pretty good job explaining all of this:

The code in the video is from the equiment that is used in the First Robotics competitions. To use this on the ESP32 to drive the the L298N motor drivers, we will need to do a couple of things. First, the remote takes the analog inputs and converts their voltages into values from -1 to 1 with a zero center. Second, it is important to note here that the potentiometers on these joysticks aren't all identical and can differ slightly between two joysticks. So, some calibration may need to be done.

After the values of the joysticks are mapped, the calculations for the polar coordinates are then performed and each wheel's speed and direction is calculated before sending to the main controller. This is done on the remote to spread some of the compute time between the devices.

Additionally, the position of the two thumb slides is determined and also packaged up to be sent to the main controller on the robot.

The communication between the remote and the controller is done by ESPNow. This is a wireless protocol that is built into all Espressif ESP microcontrollers and is used for short range small packet communication. It is very fast and simple to implement.

For a deep dive on ESPNow you can use these two resources: 

Main Controller

The main controller (currently) drives the 4 mecanum wheels and drives the two servos to raise and lower both arms. Later, more functions and features will be added so, the goal here was to keep processing as simple as possible.

Once a packet of remote data is received, the controller parses this data into 6 variables - 4 wheel variables and 2 arm servo variables. The servo data is really simple and is directly mapped to the position of the servo based on where the slider on the remote is. The higher the slider, the higher the servo. However, one value of the two servos will need to be inverted, since it will be moving opposite to the other. The wheel values on the other hand will need to be converted to a direction and power.

The L298N driver takes 3 bits to operate - for each wheel there are two pins that drive the direction and one pin to enable or turn on the driver. Holding a high signal on one of the two and a low on the other will turn the wheel one way and reversing those pins will turn it in the opposite direction. These are simple on and off bits

The third signal to the EN pin will be a PWM (Pulse Width Modulation) signal that will turn on the driver for a period of time and then turn it off again for a period of time. The longer it is on than off the faster the wheel will turn. If it is on constantly, then that is full speed. If it is off constantly, then the wheel is stopped.

NOTE: The code contains comments to detail what each code block is doing.


  • ESP32 General Resources - (Random Nerd Turorials) Introduction to ESP32 coding topics with information covering almost all of  the features exposed via the Arduino driver library.
  • Mecanum Coding - (YouTube - Gavin Ford) Overview of a coding strategy for mecanum wheels that is used in FIRST Tech Competitions. Much of the code that I wrote for this project is an adaptation of this video and it's pinned comment correction.
  • Mecanum Coding - ( Overview of a coding strategy for mecanum wheels.
  • Mecanum Coding - (A. Gfrerrer - Geometry and Kinematics of the Mecanum
    Wheel) A deep dive into the physical characteristics of mecanum wheels.
  •  Adafruit HUZZAH32 -
  •  Github Project Repository - (My Github project page) Code and pictures from this project.



Related Posts


Comments 2

Guest - John on Monday, 05 February 2024 22:31

Great inspiring stuff!!

Great inspiring stuff!!
Andrew Hoover on Wednesday, 07 February 2024 11:09

Thank you! I appreciate it.

Thank you! I appreciate it.
Already Registered? Login Here
Tuesday, 23 July 2024

Captcha Image