Introduction: Wemos D1 Mini WIFI Robot (MQTT & UDP)

About: I am a Ham Radio operator, computer geek, robotic hobbyist. I've been "playing" with microcontrolers for the last several years, basic stamps, arduinos, and arduino like controllers, Raspberry PI, PICs & PICax…

This project uses a Wemos D1 mini to control a robot. In it's current state it is little more than a remote controlled "car" on a robot chassis.

I am using MQTT from the robot to the display and controller for status updates. The remote uses UDP to send commands to the robot.

The remote is also a D1 mini with a OLED screen, and 5 way toggle switch.

The display is a ESP8266 with OLED on board (Sometimes called a D-duino, the one I'm using has a 18650 battery connector on the back, and Sits nicely as a desktop display). The screen is bigger than the remote control screen, so it makes it a little nicer to see the information - but it pretty much displays the same information the remote control does.

It should be noted that right now I am using a public MQTT broker, and that can be slow. Plans are to add a raspberry pi running a private broker later.

Step 1: Parts, Tools and Skills Needed.

PARTS LIST:

Most of these items can be found on eBay or Aliexpress for a decent price. The Radio Shack Ultrasonic is getting harder to find, but still available.

(2) Wemos D1 MINI ESP8266 NodeMCU boards https://www.aliexpress.com/item/ESP8266-ESP-12-USB...

(2) Wemos Dual Base Shields for the D1 Mini https://www.aliexpress.com/item/Free-shipping-Dual...

(1) Wemos D1 MINI Motor Shield https://www.aliexpress.com/item/1Set-Motor-Shield-...

(1) Wemos OLED shield for the D1 MINI https://www.aliexpress.com/item/Free-shipping-OLED...

(1) Wemos Battery Shield for the D1 MINI https://www.aliexpress.com/item/Battery-Shield-For...

(1) D-Duino with 18650 battery holder (Only needed if you want to have a second display) https://www.aliexpress.com/item/Wemos-ESP8266prefl...

(1) Pololu Romi Chassis about $30.00 https://www.pololu.com/product/3500 (There are other colors available)

(1) Set Pololu Romi Wheel Encoders about $9.00 https://www.pololu.com/product/3542

(1) Radio Shack Ultrasonic https://www.ebay.com/sch/i.html?_from=R40&_trksid=...

(1) 5 way toggle switch https://www.ebay.com/itm/5-Way-5-channel-Tactile-S...

Batteries (Various the Romi uses 6 AA, the display a 18650, and the remote I used a small battery from a small quad copter)

Other Miscellaneous Items needed:

small bread board, some miscellaneous screws, nuts, washers, and standoffs, DuPont wires F/M and M/M

*** A USB to Serial board (FTDI board) that has 3v output MAY or MAY NOT be needed. While not needed for the project itself. Some of the motor driver boards ship with bad firmware, it easy to fix but you do need a USB to Serial board to do it. ***

* Do your own home work on sellers, and prices. What is listed here is only a guide.

TOOLS:

Basic tools are needed to complete this project.

A soldering iron, small screw driver, a pair of needle nose pliers, small scissors.

Solder, and solder paste or flux. (may come in handy)

SKILLS:

there are a number of pins that need to be soldered, they are spaced pretty good, but some of the solder pads are small.

Patiences, and the ability to look at code and make changes as needed.

General troubleshooting skills could come in handy as well.

Step 2: The Pololu Romi Robot Chassis Build....

I choose to use the Romi Chassis because a local company had it on sale for a good discount, (I wish I had bought more now).

The kit comes with motors (120:1 HP offset output with extended motor shaft which is important later) and wheels which were designed to work with the Romi encoders we will be using later.

A different chassis can be used, but you may have some problems using the encoders.

The Romi Chassis is a easy to build, snap together kit - it also un-snaps pretty easy making it easy to expand, and replace parts.

It's made from a soft plastic material, and has plenty of holes for mounting various controllers and other item. Unfortunately for our build none really matched up with the D1 Mini Dual Base shield. (Which is easy to over come. but that is later in the instructable.)

First let's just build the chassis. The above video shows my build, which took about 20 mins to do - with the longest time spent on getting the rubber 'O' ring on the wheels.

The Pololu Romi Page has great build instructions. https://www.pololu.com/product/3500/resources

Step 3: The Romi Wheel Encoders.

The Wheel encoders I choose to use were made for the Romi Chassis. These are quadrature encoders, have two hall effect sensors, and a small magnetic disc that has 6 poles. The solder to the back of the motors, and the magnet disc pushes on to the long motor shaft (out the back).

Power is needed for the hall effect sensors, they work between 3 and 18v DC - I choose to use 5v for them.

They provide M1 and M2 (IN) pins, these pins are connected to the motor drive. And they provide and Out A and Out B pin, these are the hall effect sensors. To use both encoders, we need 4 pins on D1 Mini, we are going to setup two interrupts for the "A" pins, and take a snap shot reading of the "B" pins when the interrupt is triggered.

Doing this we can tell if the motors are moving forward or reverse (Clockwise or Counter Clockwise) We can do this because the hall effect sensors are slightly out of phase with each (they don't trigger at the same time), and by reading the "B" encoder and comparing that with the "A" we can figure out if it triggered first or 2nd. and that tells us direction of rotation.

There are a number of tutorials on how these work, this is a pretty simple understanding of it:

http://www.dynapar.com/Technology/Encoder_Basics/Q...

Pololu says we get 12 counts per revolution of the motor shaft (6 pole disc, 2 hall effect = 12) - turns out for one full rotation of the wheel, we get a pulse count of 360.

With this information, we can start to slow the motors down and even stop them at or near a count or a full wheel rotation. This speed doesn't matter the one full wheel rotation is always a count of 360 - there is a little jitter in them and sometimes it's 358 or 362 - but it's close enough that later we can add in some calculations to have these turn at any degree we need. (Or go a certain distance).

My Code: First we need to setup some variables

//Setup Encoder Pins

//It appears the interrupt handler needs the GPIO numbers

const int M1A = 13;

const int M1B = 12;

const int M2A = 14;

const int M2B = 0;


//setup direction flag

volatile int m1dir = 0;

volatile int m2dir = 0;

long m1steps, m2steps;

Next we need to set the pins with the internal pull up resistors (The data sheet provide by Pololu also says this, but it is easy to miss). We need to setup our interrupts this can either be a RISING or a FALLING edge - I choose RISING (No real reason, that is just what I choose)

void setup() {

Serial.begin(9600);

pinMode(M1A, INPUT_PULLUP);

pinMode(M1B, INPUT_PULLUP);

pinMode(M2A, INPUT_PULLUP);

pinMode(M2B, INPUT_PULLUP);

attachInterrupt(M1A, m1achange, RISING);

attachInterrupt(M2A, m2achange, RISING);

setup_wifi();

// WiFiManager wifiManager;

// wifiManager.autoConnect();

Udp.begin(localPort);

client.setServer(mqtt_server, 1883);
}

And finally the code for the interrupts:

void m1achange() {

detachInterrupt(M1A);

int snap2 = digitalRead(M1B);

if (snap2 == 0) {

// encoder channels are the same, direction is positive

m1dir = 1;

m1steps++; } else {

// encoder channels are not the same, direction is negative

m1dir = -1;

m1steps--;

}

attachInterrupt(M1A, m1achange, RISING);

}
void m2achange() {

detachInterrupt(M2A);

int snap2 = digitalRead(M2B);

if (snap2 == 0) {

// encoder channels are the same, direction is positive

m2dir = -1;

m2steps--; } else {

// encoder channels are not the same, direction is negative

m2dir = 1;

m2steps++;

}

attachInterrupt(M2A, m2achange, RISING);

} /*

* Gives both a speed (rotation count - 360 equals one full rotations for the Romi motor and wheels)

* and a direction.

* Direction 0 (zero) is not moving.

* 1 (one) is moving forward

* -1 (negitive one) is moving backward

*

*/

You might notice that the code is the same, but opposite each other, So the interrupt for motor 1 adds to the count if Encoder B is LOW (zero). And Motor 2 interrupt subtracts if Encoder B is LOW (zero). This is because the motors are physical opposite each other. And the A & B pins on each motor are physical opposite each other.

You will also notice that we detach the interrupt while we are inside the interrupt handler. We don't want the interrupt to trigger while we are inside the handler and we need to take a quick snap shot of what the B pin is doing on each encoder. The handler code should be small, and execute quickly, so detaching the interrupt shouldn't cause any problems with the code.

* Notes about soldering - it's important the encoder boards keep straight, they align pretty easy with these motors, but it something to be aware of. The motor pins are delicate, and care should be made to not over heat them (They are thin metal, and could melt, seriously I've seen that happen before, they could also get hot enough to melt the plastic housing - or melt the very small internal wire of the motor) It shouldn't take much to solder to them.

The pins provide with the encoders are short, they will work with the standard DuPont wires, but it's something to be aware of. If you plan on leaving the robot together, or planning on never updating or adding the power board. You might consider soldering standard size header pins on them. I decide to use them as they are because you never know, I might one day want to change and use the 32U4 board or something. I did solder the encoder boards and pins so they face upward. As is pointed out in the Romi documentation they motors can be removed and flipped over (a nice feature).

Step 4: The Wemos D1 Mini Motor Driver


The Wemos Motor Driver has TB6612 H-Bridge, and a STM32F030 microcontroller, that can be reprogrammed with the correct tools.

The Wemos Wiki has a most of the information we need: https://wiki.wemos.cc/products:d1_mini_shields:mot...

We need to solder the header pins that come with the motor driver to it, I used the long male, with female pins on the other end. This way I can plug it into the dual base shield, and still plug either other shields or the dupont wires into it. There is also a 90 degree set of pins included, these should be soldered to the area marked (VM)(GND) A1 A2 B1 B2 S

Now we need to test the driver, we will need to grab the library for it.

https://github.com/wemos/WEMOS_Motor_Shield_Arduin...

Plug the shield into your D1 Mini, keeping in mind (and matching) the pin names. Now we need to hook the 4.8v from the Romi Battery to the VM and GND on the motor board, and hook at least one of the motors to the motor control pins (A1, A2 or B1, B2). The library contains an example sketch, you'll want to upload the example. Hopefully the motor will start and the wheel will move. This sketch tests both motors, and has one set of wheels moving full speed while the other slowly ramps - so if you don't see anything give it a few minutes, or hook the 2nd motor up and see, or you may have a motor drive board with bad firmware on it.

* If the motor driver does have good firmware, the motor/wheels will move, so it's a good idea to put the robot on a cup, or something to get the wheels off the ground/table, you just don't want it running away *

IF you never see a motor move using the example, it is very likely that the driver has bad firmware. Fortunately this is easy to fix.

SPECIAL NOTE: IF you do see the motor/wheel move you probably don't need new firmware and can skip to the next step - HOWEVER - it is known that the firmware provided is buggy and does cause the I2C bus to freeze. You may still want to upload the new fixed firmware.

UPGRADE THE FIRMWARE: For this next step you may or may not need a FTDI USB to Serial adapter. As stated above it is known that the Wemos Motor Drivers have bad firmware or firmware that locks up and doesn't work correct. The good news is the firmware is open sourced, and pretty easy to flash with just a couple of basic tools.

The instructions can be found here: https://hackaday.io/project/18439-motor-shield-rep...

There is a section called "Reprogramming without soldering" - We are going to use most of the steps found in that section, however that hackaday page also contains a download to already compiled and ready to use firmware. We will use this because it's just easier we don't have to recompile anything or make changes

https://cdn.hackaday.io/files/18439788894176/motor...

(Another note: It appears this new working firmware only supports the default I2C adress 0x30) Download the above firmware. We need to install a couple of pieces of software so we can write this firmware to the STM32 microcontroller.

Install "arm-none-eabi-gcc", I am a Linux user and I found it in the package manager (so easy quick install)

For Windows - I found this (NOTE: I have not tried this on a Windows Machine)

https://developer.arm.com/open-source/gnu-toolchai...

Select the package for your OS, and follow the install instructions.

We also need to install, "stm32flash" utility. Again, I found this in the package manager for my distro.

I also found this site which appears to has packages for other OS (Windows)

https://sourceforge.net/projects/stm32flash/files/

I didn't really see install instructions - so use your own judgement here.

After the software is installed, you will want to put a jumper (I used a male/male DuPont wire) across RTS and 3V (top of the motor driver board). This puts the board into firmware upgrade mode.

From your USB Serial dongle, you'll want to connect the 3v to 3v, GND (Ground) to GND, the TX to the D2 pin on the shield, and the RX to the D1. Connected the dongle to your computer, and you should be ready to communicate with the shield.

For linux users the command would be:

stm32flash /dev/ttyUSB0

and you'll see something like the command line picture above.

It should be simiular for Windows users, replacing /dev/ttyUSB0 with your com port COM3 (for example, it should be the com port that your USB to Serial device is attached to)

(It should be noted: Linux users that have other USB to serial devices plugged in will have a different port name as well)

Some shield come "locked", again, not a problem, the unlock command is:

stm32flash /dev/ttyUSB0 -k

You should see a message that says something like "Read-UnProtecting flash".

* replace /dev/ttyUSB0 with your com port

Next run:

stm32flash /dev/ttyUSB0 -u

and you should see a message that says something like "Write-UnProtecting Flash"

* replace /dev/ttyUSB0 with your com port

And finally, we can flash the new firmware:

stm32flash /dev/ttyUSB0 -v -w motor_shield.bin

This might take a few minutes - and you should see "Wrote and verified address 0x08000c2c (100.00%) Done.

Some other things to note: the stm32flash should be run on the command line, from the directory you downloaded the motor_shield.bin to (Normally the Download folder)

* replace /dev/ttyUSB0 with your com port

Remove all the wires, including the RTS to 3v jumper, replace the shield on to the D1 Mini, hook the motors back up and run the example sketch again. This time, things should work.

IF not, you may need to flash it again. (The first time I did this one of my wires came loose and caused the flash to fail, even thou it appear to complete correctly. - just something to be aware of).

Very special thanks to Radomir Dopieralski for his working firmware and tutorial on simple flashing for the motor driver.

https://hackaday.io/project/18439-motor-shield-rep...

Step 5: Add the D1 Mini and Motor Controller to the Romi

As I said earlier the Pololu Romi chassis has many mounting options, but none seemed to work for the D1 Mini and dual base shield. They were close enough however that I was able to mount the dual base shield by leaving it a little loose and moving it as I put a 2nd screw in - then I was able to tighten it all up. I used a couple of M3 stand offs and M3 screws. These were just a little too big, taking a small knife I was able to make a couple of the mounting holes a little bigger.

The pictures really say more than I can at this point. (I am sorry about my hand made picture, this didn't quite turn out as well as I thought it would.).

The Romi has two battery "compartments" - One is a 4.8v (6v) and the other is 2.4 (3v) depending on the type of batteries you use. I used the 6v side for the motors, and connected the positive to the VM on the motor driver.

The grounds are all common, and connected together. Originally I was going to use the 3v side of the battery connection for powering the micro-controller. Turned out the 3v battery just didn't last very long.

Of course you can wire the battery compartments together and get more voltage, and then use a voltage regulator to help solve that problem. (At the time of this writing I have not done that).

I am using a emergency cell phone charger now to power the D1 mini. It's still not the best option, but it does work, and lasts a long time.

We already have the wheel encoders installed, and should have tested the motor driver at this point. The rest of the build is pretty easy. I named my motors, looking at the front of the robot, the motor on the right is M1, the one on the left I am calling M2. (Motor 1, Motor 2) - this should not be confused with the labels on the encoders (M1 and M2) - Also the Motor Driver has labeled A1, A2 and B1 and B2 which should not be confused with the labels on the encoder (A and B).

I am powering the encoders by 5v off the D1 mini. unfortunately the D1 mini on has one ground pin, so I used a small bread board to bring that ground out for more.

So here is my hookup guide:

M2 Encoder M1 to B2 on Motor Driver
M2 Encoder M2 to B1 on Motor Driver
M2 Encoder A to D5 on the mini
M2 Encoder B to D3 on the mini
(M2 is the left encoder)

M1 Encoder M1 to A2 on the Motor Driver
M1 Encoder M2 to A1 on the Motor Driver
M1 Encoder A to D7 on the mini
M1 Encoder B to D6 on the mini
(M1 is the right encoder)

It should be noted that at this point, the encoders are not being used for anything useful with the "Remote Control" sketch.

Step 6: The Radio Shack Ultrasonic Sensor

According to the PDF found at:

https://github.com/RadioShackCorp/2760342-Range-Se...

These are 5v sensors that have a 30 degree angle of detection. And a range of about 1in to 13 ft.

I picked this sensor because it appears to work at 3v as well, and only uses one pin for both trigger and echo.

This is important because we used a lot of pins for the motors and encoders. A example sketch can be found at the Radio Shack github repository.

https://github.com/RadioShackCorp/2760342-Range-Se...

I would recommend hooking this up and running the test sketch, and verify that it is within the specs listed.The SIG pin on the ultrasonic needs to be hooked to D0 on the D1 mini.

And line 66 of the example sketch should be changed to

 Ultrasonic ultrasonic(16);

16 is the GPIO number for D0.

Unfortunately with Radio Shack closing, these are getting harder to find. There are a few on eBay that I found, but the prices seem kind of high when compared to The HC-SR04 ultrasonic. Most of the HC-SR04 ultrasonics don't work at 3v, but other ultrasonic sensors may work - and would need some code changes.

IF you are curious on how ultrasonic sensors work this is a fantastic tutorial on the subject.

http://arduino-info.wikispaces.com/Ultrasonic+Dist...

Mounting the Ultrasonic:

I found a couple of small spacers, and some long thin screws, the Romi chassis has plenty of mounting holes on the front, and they lined up pretty well. I have mine in just about the center of the front attached to the holding ring around the bottom of the chassis. VCC on the ultrasonic is connected to 5v, and GND is connected to my ground block on my breadboard. And SIG is connected to D0 on the D1 mini controller.

The code block:

ping.ino (from my D1 Mini Robot code)

void ping() {

long duration;// the Pulse time received;
pinMode(ultrasonicPin, OUTPUT);

digitalWrite(ultrasonicPin, LOW);

delayMicroseconds(2);

digitalWrite(ultrasonicPin, HIGH);

delayMicroseconds(5);

digitalWrite(ultrasonicPin,LOW);

pinMode(ultrasonicPin,INPUT);

duration = pulseIn(ultrasonicPin,HIGH);

RangeInInches = duration/74/2;

// Serial.println("The distance to obstacles in front is: ");

// Serial.print(RangeInInches); //0~157 inches

/*if (RangeInInches <=39) {

stop();

cmd = 0;

}*/

}

I modified the example code slightly for our use, but it's pretty much the same code with the major change being that this will return the distance in INCHes without making a second call to the ultrasonic class. (And of course it's no longer a class, it's just a function/subroutine).

I commented out the serial prints, as they are not needed for the robot (RangeInInches is sent via MQTT to the remote display and the remote control). And at the time of this writing I am working on adding some "self" protection code, so the robot will stop even if told to go and hit something. (It wasn't quite working) This code is subject to change.

IF you want to use a different ultrasonic this is where most of your code changes would happen (ping.ino)

Step 7: The Code and Required Libraries

The Code can be found at my repository on github:

https://github.com/kd8bxp/D1-Mini-WiFi-Robot

You will see a few directories/folders - I tried to keep them name for what they are and what hardware they belong too.

d1_mini_robot - this is the main code for the robot. Because the code is big, I decided that it might be easier to split it into smaller easier to read .ino files. When compiled to upload all of these small files are put together and upload as one large sketch. The d1_mini_robot.ino file contains all of the global variables, the includes for the libraries, and calls to setup the libraries. The loop.ino is the same as void loop() { }, and setup.ino is the same as the void setup() { }. Everything else is either called or used by one of these files.

(It should be noted that I was attempting to have one code that had or has different modes of use, so far I only have the remote control code working to a point that I like) So things like motorTimer.ino, mode1.ino, mode2.ino and some others are not being used as of right now.

AT this time, you must update the code with your WIFI SSID and password which is in the d1_mini_robot.ino file near line 57.

const char* ssid = "Motel6";

const char* password = "";

otherwise the code is ready to be used.

remote_control - This is the code that needs to be uploaded to the D1 mini that has the toggle switches and oled. (see next section). Like the code above, I split this up into separate .ino files to try and keep it easy to make changes, and upload the code. The remote_control.ino has all of the variables, libraries, and library setup. As you can see there are a lot less .ino files, the code is much simpler. More on the remote in the next section.

remote_display - This code should be uploaded to the ESP8266 D-Duino (ESP8266 with onboard OLED). The remote display works very much like the remote_control, only without the control part - the code is even more simple. To keep consistent, I still split the code out into separate .ino files. And remote_display.ino contains the variables, and libraries, and library setups. The rest of the code is used to just display packages (messages) from the robot. This code is a very striped down version of the remote_control code, with some minor (or major) changes for the larger display, and some changes for how that display works.

A modular design of the .ino files, should also make it easy to port and move the specific parts of the code to other projects in the future. Or create new things for the robot to do.

If you haven't already install the Arduino IDE. Following the instructions for your OS.

https://www.arduino.cc/en/Main/Software


Install the ESP8266 Core into the Arduino IDE. The best and easiest way to install the ESP8266 Core is to use the board manager, instructions can be found here:

https://github.com/esp8266/Arduino#installing-with...

The core will contain some libraries used by the sketches, other libraries are below.

Required Libraries: (some of these libraries can be found in the library manager, others have to be downloaded and installed).

WEMOS_Motor.h https://github.com/wemos/WEMOS_Motor_Shield_Arduin...

PubSubClient.h https://github.com/knolleary/pubsubclient

ArduinoJson.h (I believe this is in the library manager) https://github.com/bblanchon/ArduinoJson

WiFiManager.h https://github.com/tzapu/WiFiManager

SSD1306.h https://github.com/squix78/esp8266-oled-ssd1306

There are several different ways to install new libraries, check to see if the library is in the manager first - this is the easiest way to install new ones. IF not, my method is to download and unzip the library - rename the folder (removing -master from the end of the name) and moving that folder to the libraries folder in the Arduino folder.

Where is the Arduino folder you ask? It depends on which OS you have. Windows it is normally in the Documents folder, and if you don't have a libraries folder you will need to create one.

Linux users typically the Arduino folder is under your home folder, again if you don't have a libraries folder you need to create one.

With the new IDE (1.6 or better) typically all you need to do is load the library manager and it will find the new libraries within the directory. This is not always true and sometimes a restart of the IDE is still needed.

* Notes: As of Oct 21, 2017 The current Arduino IDE is 1.8.5 (I am using 1.8.4), Other project files may or may not have been added to the github repository.

Step 8: The Remote

A previous instructable of mine was for a remote display using MQTT

https://www.instructables.com/id/ESP32ESP8266-WIFI...

The original idea of the display was to get status update from a robot project.

The remote takes that idea one step further. The hardware used here is very simple, and stacks on top of each other for the most part. A 5 way toggle switch is added for direction control of the robot.

The Hardware:

D1 Mini, D1 Mini .66 in OLED display, D1 Mini Dual base shield, D1 Mini Battery shield, and the 5 way toggle switch.

You will need to solder pins to all the boards, keeping in mind how you'd like these to stack, and keep in mind the pin labels need to match when you plug them into each other. (see my pictures above)

The battery is a small quad copter battery, the connector on it isn't really the right one for the battery shield however it does work, just watch your positives and negative.

<p>On the toggle switch board, you will see labels such as GND, RIGHT, DOWN, LEFT, CENTER,UP and VCC.<br>VCC will be connected to the 3v of the battery shield, GND to the GND of the battery shield.
RIGHT to D6
DOWN to D5
LEFT to D0
CENTER to D4
UP to D3</p>

The remote_control code uses the WIFIManager Library, so there is no need to change anything in the code. The WifiManager will setup an access point and captive portal that will allow you to set your WIFI information.

A brief explanation of what the code does and how it works.

When you first turn on the remote_control, it attempts to connect to your wifi network, after it connects, it will then connect to a MQTT broker, and subscribe to the "robothome" topic - The robot uses this topic to publish it's unique ID (part of it's MAC address), and it's IP address - it publishes this as a json string. The robot will continue to publish to this topic as long as it is on.

Once the remote gets a MQTT message from the "robothome" topic, it decodes the json string, and unsubscribes from the "robothome" topic, it then subscribes to the unique ID topic sent from the robot. The robot uses this "uniqueID" topic to publish sensor information (IE: Encoder Direction, Count, and Ultrasonic distance).

The remote_control also stores the IP address of the robot for use with UDP.

(The above could take a few seconds, during this time the display is blank. Once information is displayed you are ready to control the robot).

The robot listens for a UDP package, the remote sends a UDP package.

The remote_control sketch, now starts to poll for switch changes, if there is no switch being pushed it sets a value of -999 (or don't send a UDP package). Otherwise each direction has a value given to it. UP is 1, CENTER is 2, LEFT is 3, DOWN is 4, RIGHT is 5. The polling of the switch is done in the toggleSwitch.ino sketch.

If a switch has been triggered we will send a json string over UDP with speed, switch and mode information.

* One limitation of my code right now is speed is always set to 100%, and the robot code only has one mode right now - so lets call this function a future enhancement *

The updSender.ino sketch is where the json string is created, and sent. (And I just now realized I fat fingered the name of this sketch, and the function call...wow, editing :-) )

A note on UDP - the original idea was to always have the remote sending a UDP packet to the robot - The robot quickly became flooded with UDP packets and couldn't handle it (WDT reset were happening quickly, and the robot would go out of control). This can still happen if you hold a switch - the sketch will continue to send the UDP packet - it's best to quickly hit the switch once, try not to hold it. * I am exploring other ways to prevent flooding, but so far this is what I've come up with *

When a UDP packet is not received, the robot will set the command to stop, and the motors will stop.

* Also, if the robot looses it connection to the MQTT broker, it will trigger a motor stop until it can reconnect - the side effect of this is the UDP packets are still waiting to be picked up (even thou, I've attempted to flush them they appear to still be waiting) Unfortunately at this time, there is no feedback to tell the remote that it has lost it's connection to the broker.

IF the remote looses it's connection to the MQTT broker, it will also send a stop command to the robot, thou the nature of how UDP works it could be a hit or miss sent command.

* There is no feedback with UDP, once the packet gets sent, it either makes it to it's target, or it gets lost trying.

The robot will send a json string to the MQTT broker, this string contains, Motor Direction (M1dir, M2dir), Steps (or encoder counter) (m1steps, m2steps) and distance (in inches). The json string also contains the robot ID - even thou we are listening to the uniqueID (robot ID) topic - I thought it might be a good idea to include this information. It's not being used for anything right now.

The displayPkg.ino sketch, takes the decoded json information, formats it for display.

Unlike my previous MQTT displays, I did do some formatting of the information.

The display is small, so the information is limited, but still useful. It's formatted so that M1 is displayed then M2 is displayed. For direction: S means Stopped, F means moving forward, and R means moving in reverse.

Step 9: An Optional Second Display...

The hardware is already done, there is really nothing you need to do but put a battery in it, and upload the remote_display code.

This display uses a bigger OLED, so more information can be displayed. It's based off the remote_control code, in fact it is a very scaled back version of that code. With the major changes being for the larger display.

It works pretty much the same as the remote_control. It listens to the "robothome" topic, gets the uniqueID and IP address, and then subscribes to that topic, and displays the information.

I also included displaying the robots IP address, and ID. At this time, there really is no reason to do that. I just had the extra room and thought it might be good to know that information.

Step 10: MQTT, UDP and JSON

Briefly what is MQTT:

In my previous instructable, I go a bit more into what MQTT is, but briefly.

MQTT is a publish/subscribe, extremely simple and lightweight messaging protocol, it is designed for constrained devices and low-bandwidth. It is ideal for M2M or IoT connected devices.

* A special note here: I am currently using a public MQTT broker - with no type of encryption. This means anyone can listen to your published streams. For something more private, a linux machine or raspberry pi can be setup with your own broker. (This is something I am planning on doing with this project, but at this time I just haven't done it yet).

http://mqtt.org/faq

What is UDP:

UDP (User Datagram Protocol) is an alternative communications protocol to Transmission Control Protocol (TCP) used primarily for establishing low-latency and loss tolerating connections between applications on the Internet. ... Both protocols send short packets of data, called datagrams.

http://searchnetworking.techtarget.com/definition/...

The biggest difference between TCP and UDP is one is a connection and can send information in both directions (TCP). While UDP is much simpler connectionless protocol. UDP is considered to be unreliable, however it can achieve a higher throughput (within reasons). UDP packets can be lost, so many times UDP packets are sent more than once to ensure delivery. (I am trying to avoid sending the packet more than once however for this project).

What is JSON:

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999.

http://www.json.org/

A JSON string looks something like this:

{"Speed":100,"Direction":"NORTH","M1":1200,"M2":1394}

It's a pair of names or a name and value pair - so the name "Speed" is associated with the value 100.

Using the ArduinoJSON library we are able to decode the json string, then look for various "names" inside the decoded information. These could be strings or integers. You can also nest JSON strings. It's incredible powerful. And makes sending information across a network easy to do.

What makes these protocols so attractive is how easy they are to use, and how well they just get the job done.

Step 11: Some Known Issues and Test Videos

Known Issues (Oct 20, 2017) -

1. Wifi Manager doesn't work on the robot (low memory issue I believe) - Would love a work around for this.

2. The current D1_Mini_robot sketch uses 50 to 51% of variable memory space, and currently adding any new code is causing issues. WDT resets at best, and freezes at worst. These issues maybe related to either the pubsubclient library, or the Arduinojson library - both have reported issues on the esp8266.

3. Code for self preservation is still in the works. I had some issues with adding it - I think I've overcome the largest of these issues but have not attempted it in the robot code yet.

I'm not sure how to overcome some of these issues.

Step 12: More/Extra Pictures

Just some more pictures of the robot.

Step 13: Other Options for the Romi Chassis

The Romi Power Distribution Board https://www.pololu.com/product/3541

and the Romi Power Distribution with Motor Driver https://www.pololu.com/product/3543

I don't own nor have I used either of these boards, but they appear to have a good number of grounds and battery power options. The D1 Mini only has one ground, using the motor shield and with the dual base we get two grounds, and we need more. I used a small bread board to solve this problem. But the power distribution board may be a better option in the long run.

The Power Distribution Board with Motor Driver looks like it has all the same power distribution options, and adds a motor driver as well as connections for the encoders. I've not used this board, The cost seems a little high to me. But it is an option. The code and wiring for the D1 mini would change a lot, that is something to be aware of.

Both add a power switch, which is a nice thing to have.

Way beyond the scope of this instructable:

Pololu also overs a custom 32U4 control board for the Romi, which does have a number of features we don't have or need right now. The ATmega32U4 is the same chip used on the Arduino Leonardo. The board comes with header for display, a Raspberry Pi Header, an accelerometer, push buttons, and motor driver.

https://www.pololu.com/product/3544 If you use this board you are really out on your own (ok, not really, there is lots of help on the Pololu formus. But it is way outside of the scope of what I am doing here)

** NOTE: I don't own any of these boards, and can't answer any questions about them. I've listed them as options for those who under stand or want to learn a bit more about doing the wiring, programming, etc. **

** IT should also be noted the D1 Mini is a 3 volt controller has the power hooked up wrong, or bridging the two sets of batteries could cause lots of problems, or destroy your D1 mini. Know what you are doing if you decide to use any of these boards.

Step 14: Updates....

I've made some progress on updates, for both the code and hardware.

I know have a Raspberry PI Zero W setup as an Access Point for the robot - instructable can be found here:

https://www.instructables.com/id/Using-a-Raspberry...

There are several new branchs (Which at some point I may pull into the main branch of the code repository)

https://github.com/kd8bxp/D1-Mini-WiFi-Robot

Alternative_Code Branch - contains some alterntive code for using the robot.

ping Branch - contains a working sketch that adds protection to mode0 so the robot shouldn't run into things while being remote controlled.

autonomous branch - contains working code for mode 1. Has remote display, and remote control can be used to change modes with some patients.

and raspberrypi branch has examples of files I used to setup the PI.

Wireless Contest

Participated in the
Wireless Contest

Make It Move Contest 2017

Participated in the
Make It Move Contest 2017