Robotics Kit 2

Introduction
This is the second in a series of a WiFi Controlled Robot projects. In this kit you'll be putting together a controller to drive your previous kit remotely.
Objectives
Then this is a great place to start! If you're already familiar with setting up the Arduino and the IDE, you can skip to the next section.
Terms
When we talk about Arduino, the Arduino IDE, and coding, there are a lot of words being thrown around. This section will clear all of those up and get you ready to start building!
Arduino
The Arduino is a electronics prototyping platform. That means it's a flexible platform for building, testing, and, of course, prototyping electronics. That could be simple LEDs that light up at night, or advanced robots. When we talk about the Arduino we are talking about the physical board itself. The one that comes in this kit is red, but they come in many different shapes and colors. The Arduino brand and original board were created by arduino.cc and you can read more about the details of its history here.
Arduino IDE
The Arduino IDE, or Integrated Development Environment, is not hardware, but a piece of software. If you wanted to write an essay, you might use Microsoft Word or Google Docs. If you wanted to edit pictures, you'd probably use Photoshop or Paint.net. If you want to program code for the Arduino, you'd use the Arduino IDE. Its a computer program (tool) that let's you develop and test out code. Once written, the code can be upload to the physical Arduino where it will stay until you upload new code.
Download
Since it is a program, you'll need to install it.
For Windows computers use this link Windows Installer
For Mac computers use this link Mac Installer
After following each link, press the Just Download button to begin downloading the Arduino IDE. The Mac version has a few more steps and we have a video just for that.

Installation
Open the executeable file you downloaded. You'll see a screen asking you to agree to their license. You can press I Agree.

Next up are the installation options. The Install USB Drivers lets the Arduino board communicate with the IDE. We definitely want this. The Associate .ino files makes any Arduino file on your computer open up to the Arduino IDE. Very helpful, so we'll keep that too. Press Next >.

Now you are being asked where you'd like the Arduino IDE program installed. I don't mind it in the standard Program Files so I just press Install. You can change where it will be installed, just remember what you chose. I recommend not changing it.

Now the IDE is installing.

Once completed proceed to the next section.

Arduino IDE 101
Open up the Arduino IDE for the first time. So, let's figure out what's what.

There is a mostly empty space in the middle that has this text:
1
2
3
4
5
6
7
8
9
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
This is a simple Arduino Sketch. A Sketch is code you write that will later be uploaded to the Arduino board.
There are few steps to go from code written in a sketch to code that runs on the Arduino board. Those are Verify > Compile > Upload.
All of these you can get to by going under Sketch on the top bar of the program. Or using the Checkmark and Arrow icons right below that. The Checkmark verifies your code will compile, and the arrow button uploads the code to the Arduino.


Verify - looks at your code and makes sure it can actually run. It checks that there are no errors or things out of place. If your code will work, it goes to the Compile stage.
Compile - The code you've written is great for human. It is readable and hopefully understandable. But this isn't great for a machine ie the Arduino. The Compile stage takes your written code and translates into something that the Arduino can understand and run, called machine code. It saves that compiled file and tried to Upload it to the board.
Upload - This takes the compiled files and tries to send it to a plugged in Arduino. The IDE doesn't know where you've plugged in your Arduino or what kind it is. You have to tell it. I'll show you how to set that up in the next section.
Arduino Board Setup
For this section, make sure your Arduino Board that came with your kit is plugged in. Use the included micro USB cable to plug your Arduino into any free USB port on you computer.
Navigate to the Tools section at the top of the Arduino IDE.
You'll be greeted with a scary drop down. To setup your Arduino to accept uploads, do the following: Go to Board: and make sure Arduino/Genuino Uno is selected.

Next is the Port. For Mac users refer to the video for these instructions. With your Arduino plugged in, you'll see some options. Mine says COM 15. This is the channel that the IDE will use to communicate with your Arduino. If you have a lot of COM # devices and don't know which is your Arduino, unplug your Arduino and take note of that numbers are there. Then plug it back in. Whichever is the new one in the list is your Arduino. Select that port.

With the board and port selected and ready to go, let's upload our first sketch.
Sketches
We are going to upload a simple sketch to make an LED on the board blink. Head to File > Examples > Basics > Blink . You should see this sketch.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
Blink
Turns an LED on for one second, then off for one second, repeatedly.
Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
the correct LED pin independent of which board is used.
If you want to know what pin the on-board LED is connected to on your Arduino
model, check the Technical Specs of your board at:
https://www.arduino.cc/en/Main/Products
modified 8 May 2014
by Scott Fitzgerald
modified 2 Sep 2016
by Arturo Guadalupi
modified 8 Sep 2016
by Colby Newman
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Blink
*/
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Don't worry about the coding for now. Let's upload this sketch. You can press the Arrow icon, go to Sketch then Upload, or you can use the shortcut Ctrl+U in order to upload the code. Your sketch will auto-verify, compile, then upload to your Arduino board.

You will see the message Done uploading and your board should now have a blinking light.
Uploading Sketches and Code From Thimble
We provide example code for all our projects. To use those you'll need to copy them from our website. Then, go into the Arduino IDE, File > New. It's best to then delete all the code already there in the sketch before you paste our code in, as that will avoid any errors from copying over the old code.
Serial Plotter
You'll be asked to use the Serial Plotter on some projects. This reads any information coming from the Arduino and displays it on a graph. It can only be accessed after you've uploaded your code. It is in the Tools menu. Once opened, make sure the
Baud rate
is set to 9600.


Troubleshooting
The most common issues are solved by double checking your Board and Port settings.
What are Libraries?
Libraries are a collection of code that has already been written. We use them when we want to add functionality without have to write everything from scratch.
Some the projects in this set need libraries so this section will show you how to install those.
Libraries to be downloaded
This kit only uses the libraries you've already installed with other kits. Have fun!
List of Parts
This is a list of all the parts you should have received in your Robotics Kit 2 box.
Parts









Additional parts
You should also have received a sheet of stickers and a postcard with instructions.
Start

This is what the completed controller looks like. It uses WiFi to relay the joystick readings over to Robotics Kit 1. It also has two 1x1 mounting points. We will be using them for shoulder buttons.
Modules
Gather the following parts to complete this project.
Parts









Mounting the Arduino
The Arduino and black base shield must be separate for this step. Grab the Bottom Controller Plate, Arduino, three M3 10mm screws, and three M3 hex nuts. The Bottom Controller Plate should be facing up so you can see the L and R engravings. Place the Arduino on top of the Bottom Controller Plate so the mounting holes line up. Place a screw through one of the 3 mounting holes. Flip the Bottom Controller Plate and Arduino over and hand tighten a hex nut. Repeat for the remaining mounting holes. The top right hole makes the screw go in diagonal. This is normal.


















Reattach the Base Shield
With the Arduino in place, reinsert the base shield into the Arduino. Line up the pins on the Shield with the headers in the Arduino and press down.






Attaching the Buttons
Grab the two Vertical Spacing Plates, two button modules, four M2 10mm screw, and four M2 hex nuts. Place a button on top of a Vertical Spacing Plate so that the mounting holes in the plate line up with the hole in the module. It does not matter what orientation the plate and board are in. Place an M2 screw through the module then through the plate. Hand tighten an M2 hex nut to the screw. Repeat for the other mounting hole. Repeat these steps for the remaining Vertical Spacing Plate and module.














Mounting the Standoffs
Grab the two 20mm standoffs and two M3 hex nuts. Place one standoff through one of the holes found in the hand grips on the Bottom Controller Plate.The standoff should be coming out of the side of plate with the engravings. Flip the Bottom Controller Plate over and attach a M3 hex nut to the threads of the standoff. Repeat for the remaining mounting hole and standoff.













Attaching the Vertical Plates
Grab the two Vertical Spacing Plates with buttons in them as well as two M3 10mm screws, and two M3 hex nuts. We will be inserting the Vertical Spacing Plates into the slots at the top of the Bottom Controller Plate. This time the orientation matters. We want the socket on the bottom with the button module facing out or towards the top. Place a hex nut in the t-slot near socket inside a Vertical Spacing Plate. The will be snug. Place the Vertical Spacing Plate into the Bottom Controller Plate. From the bottom of the Bottom Controller Plate insert a screw. It should line up with the hex nut in the t-slot. Tighten the screw but not too tight. Repeat this for the remaining side.















Mount the Joysticks
Setting aside what we just made. Grab the two joystick modules, the Top Controller Plate, six M2 10mm screws, and six M2 hex nuts. Place a joystick module in two one of the two cutoffs for it. Do this from the bottom through the plate. Add one M2 screw from the top down. Flip over the plate and hand tighten the nut. Repeat this for the remaining two screw holes. Then repeat for the remaining joystick module and other cutout.










Attaching the Top Controller Plate
Grab the Top Controller Plate, four M3 10mm screws, and two hex nuts. Place it on top of the standoffs and Vertical Spacing Plates. Place two screws into the standoffs and tighten. Slide a hex nut into a Vertical Spacing Plate's t-slot. Then add a screw and tighten. Repeat with the remaining Vertical Spacing Plate.












Wiring Up the Joysticks
Grab two cables. Place one end into the left joystick socket and the other side into A0. Take the remaining cable and place it into the right joystick socket and the other side into A2. The joysticks must be spaced out like this because they use two analog channels per joystick. Putting them into A0 and A1 would cause overlap and some directions wouldn't work.





Add the WiFi Module
Grab the WiFi module, a cable, and a piece of tape to secure it. We are using the tape instead of screws because with the positioning of the WiFi module using screws would dig into your hand when holding the controller. Tape the WiFi module to the Bottom Controller Plate under the right joystick. Using the cable, place one end into the WiFi module socket and the other into D8.








A Battery For Later
We'll be using a 9-volt battery to power the controller wirelessly. Plug the cable into the battery then attach a piece of tape to the battery. Tape it down like the WiFi module but under the left joystick.





Next Section
With the controller assembled let's move on to the next section where we calibrate the joysticks.
Start
Why We Need to Calibrate the Joysticks
Each joystick uses two analog channels. One for the x-axis and one for the y-axis. The values on each channel change according to the joystick's position is a similar way to the potentiometer. As you twist the potentiometer you are changing it's resistance and therefore changing the voltage reading that goes to the Arduino.
The joystick also has a button feature. Normally another feature like this would need another channel but using some clever engineering we don't. The potentiometer goes from 0 to 1023. Each joystick channel only goes from about 200-800. When the button is pressed it overwrites the value on the x-axis to 1023. Knowing this, whenever we see 1023 on the x-axis channel of the joystick, we know that can only come from the button being pressed. We sacrifice some resolution in the positioning for the button feature.
We need to calibrate the joysticks because each one is going to have a different maximum and minimum value in that 200-800 range.
Upload
Upload the following code. The left joystick is in A0 and the right joystick is in A2.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
________ _ __ __
/_ __/ /_ (_)___ ___ / /_ / /__
/ / / __ \/ / __ `__ \/ __ \/ / _ \
/ / / / / / / / / / / / /_/ / / __/
/_/ /_/ /_/_/_/ /_/ /_/_.___/_/\___/
____ __ __ _ __ __ _ __ ___
/ __ \____ / /_ ____ / /_(_)_________ / //_/(_) /_ |__ \
/ /_/ / __ \/ __ \/ __ \/ __/ / ___/ ___/ / ,< / / __/ __/ /
/ _, _/ /_/ / /_/ / /_/ / /_/ / /__(__ ) / /| |/ / /_ / __/
/_/ |_|\____/_.___/\____/\__/_/\___/____/ /_/ |_/_/\__/ /____/
*/
//Change this to "right" when ready
String joystick = "left";
//Holds raw measurements
int xVal;
int yVal;
//Holds xAxis measurements
int xMax;
int xMin;
//Holds yAxis measurements
int yMax;
int yMin;
//Trigger for x or y measuring
bool measuringX = true;
void setup()
{
//Start Serial communcation to computer
Serial.begin(9600);
}
void loop()
{
//If we are calibrating the left joystick
if (joystick == "left") {
//Use A0 and A1 for readings
yVal = analogRead(A0);
xVal = analogRead(A1);
//If we are calibrating the right joystick
} else {
//Use A2 and A3 for readings
yVal = analogRead(A2);
xVal = analogRead(A3);
}
//If you are pressing the button for the first time
if (yVal > 1020 && measuringX) {
//Display current status
Serial.println("___________________");
Serial.println("Changeing to Y AXIS");
Serial.println("___________________");
Serial.println("Please stop pressing the Joystick");
//Resets yVal. If this was not done it would be 1023
yVal = 500;
// Give user time to respond
delay(2000);
//Set this to change axis
measuringX = false;
//If you are pressing the button for the second time
} else if (yVal > 1020) {
//Print out all results
printResults();
//Purposefully get stuck in endless loop to stop measuring
while (1);
}
//Checks to see which axis you want to measure
if (measuringX) {
//If the xVal is bigger than xMax
if (xVal > xMax || xMax == 0) {
//Make it the new Max
xMax = xVal;
}
// If the xVal is smaller than xMin
if (xVal < xMin || xMin == 0) {
//Make it the new Min
xMin = xVal;
}
//Print out current results
Serial.print("The MAX X and MIN X are:");
Serial.print(xMax);
Serial.print(",");
Serial.println(xMin);
Serial.println(" ");
delay(200);
} else {
//If the yVal is bigger than yMax
if (yVal > yMax || yMax == 0) {
//Make it the new Max
yMax = yVal;
}
// If the yVal is smaller than yMin
if (yVal < yMin || yMin == 0) {
//Make it the new Min
yMin = yVal;
}
//Print out current results
Serial.print("The MAX Y and MIN Y are:");
Serial.print(yMax);
Serial.print(",");
Serial.println(yMin);
Serial.println(" ");
delay(200);
}
}
void printResults() {
Serial.println("**********************************");
Serial.println("Calibration Results for " + joystick + " Joystick");
Serial.println("**********************************");
Serial.print("The MAX X and MIN X are:");
Serial.print(xMax);
Serial.print(",");
Serial.println(xMin);
Serial.println(" ");
Serial.print("The MAX Y and MIN Y are:");
Serial.print(yMax);
Serial.print(",");
Serial.println(yMin);
Serial.println(" ");
Serial.print("**********************************");
}
How to Calibrate the Joysticks
Open up the Serial Monitor. For each axis we will be rotating the joystick 2-3 times. This makes sure we hit the maximum and minimum values. Click the joystick and wait about 4 seconds then repeat. Click again and the Serial Monitor will print out the calibration results. Write this down somewhere. A post-it, text document, or screenshot. We are going to need these numbers. You're not done yet! change the joystick variable from
left
to
right
and repeat the whole process.


















Next Section
With both joysticks calibrated and values written down let's jump to the next section.
Start
Setting Up the Robot
You can use any iteration of the final RS1 project. If it has the LEDs or buzzer on it the robot will drive but those extra features won't work ... yet.
Upload
Upload the following code. Put your calibration values in below before uploading the code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
________ _ __ __
/_ __/ /_ (_)___ ___ / /_ / /__
/ / / __ \/ / __ `__ \/ __ \/ / _ \
/ / / / / / / / / / / / /_/ / / __/
/_/ /_/ /_/_/_/ /_/ /_/_.___/_/\___/
____ __ __ _ __ __ _ __ ___
/ __ \____ / /_ ____ / /_(_)_________ / //_/(_) /_ |__ \
/ /_/ / __ \/ __ \/ __ \/ __/ / ___/ ___/ / ,< / / __/ __/ /
/ _, _/ /_/ / /_/ / /_/ / /_/ / /__(__ ) / /| |/ / /_ / __/
/_/ |_|\____/_.___/\____/\__/_/\___/____/ /_/ |_/_/\__/ /____/
*/
//All the libraries used
#include <WiFiEsp.h>
#include <WiFiEspUdp.h>
#include "SoftwareSerial.h"
#include "Grove_I2C_Motor_Driver.h"
// default I2C address is 0x0f
#define I2C_ADDRESS 0x0f
//Motor names
#define LEFTMOTOR MOTOR2
#define RIGHTMOTOR MOTOR1
//Joystick Limits
int leftUp = 253;
int leftDown = 769;
int rightUp = 775;
int rightDown = 247;
//Create Serial communication Object
SoftwareSerial Serial1(8, 9); // RX, TX
WiFiEspUDP Udp;
IPAddress apIP = IPAddress(192, 168, 111, 111);
IPAddress stationIP = IPAddress(192, 168, 111, 112);
IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
//Wifi settings
char ssid[] = "My WiFi Robot"; // the name of your access point
char pass[] = "password"; // the password for your access point
int status = WL_IDLE_STATUS; // the Wifi radio's status
//Ports to be used
unsigned int listeningPort = 10002; // local port to listen on
unsigned int sendingPort = 10003; // local port to sent on
//Message Variables
#define arrayLength 6
char data[arrayLength + 1];
String dataAsString;
// Vaiables
int leftData = 0;
int rightData = 0;
//Motor Variables
int leftSpeed = 0;
int rightSpeed = 0;
void setup()
{
// Start Serial Communication with computer and WiFi module
Serial.begin(9600);
// initialize serial for ESP module
Serial1.begin(9600);
// initialize ESP module
WiFi.init(&Serial1);
WiFi.configAP(apIP);
// start motor driver
Motor.begin(I2C_ADDRESS);
// correct pwm cycles
Motor.frequence(F_490Hz);
// Print out debugging messages
Serial.print("Attempting to start AP ");
Serial.println(ssid);
// start access point
status = WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK);
// Set up UDP listener on port
Udp.begin(listeningPort);
// Print out which port
Serial.print(F("Listening on port "));
Serial.println(listeningPort);
}
void loop()
{
//Check for incoming packets
int packetSize = Udp.parsePacket();
// If there are packets
if (packetSize) {
//memset(data, 0, sizeof data);
//Print out update
//Serial.println("Packets Received");
// read the packet into packetBufffer
int len = Udp.read(data, 6);
if (len > 0) {
data[len] = 0;
}
//Send received data to function
dataTranslate(data);
//Map values to speeds
leftSpeed = map(leftData, leftDown, leftUp, -100, 100);
rightSpeed = map(rightData, rightDown, rightUp, -100, 100);
}
//Check to see if joystick is in deadzone
if (leftSpeed < 10 && leftSpeed > -10) {
//Stop motor
Motor.stop(LEFTMOTOR);
} else {
//Set motor to mapped speed
Motor.speed(LEFTMOTOR, leftSpeed);
}
//Check to see if joystick is in deadzone
if (rightSpeed < 10 && rightSpeed > -10) {
//Stop motor
Motor.stop(RIGHTMOTOR);
} else {
//Set motor to mapped speed
Motor.speed(RIGHTMOTOR, rightSpeed);
}
//Print out all values
Serial.println(String(leftSpeed) + "," + String(rightSpeed));
}
//Function that takes raw string and chops it into values
void dataTranslate(char recData[]) {
// Set passed array into a temp variable
dataAsString = recData;
// Write a section of the array to a value based on location
leftData = dataAsString.substring(0, 3).toInt();
rightData = dataAsString.substring(3, 6).toInt();
}
Observe
The network name of
My Wifi Robot
should appear as a network on your computer or phone. There is no need to connect to it this time. If you see the network you can move on to the next step.
Start
Controller Framework
We'll be using the UDP messaging system from the Weather Station Series to send the joystick positions to the robot. The robot will then translate those into a direction and power for the motors. For a more in depth explanation head over to this section.
Adding the WiFi Module
Take a free WiFi module and cable. Roll up a piece of tape to create double sided tape. Place one side of the tape on the bottom plate of the controller. Take the WiFi module and place it on top of the tape. Take a cable and connect one end to the WiFi module socket and the other to D8.
Upload
Upload the following code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
________ _ __ __
/_ __/ /_ (_)___ ___ / /_ / /__
/ / / __ \/ / __ `__ \/ __ \/ / _ \
/ / / / / / / / / / / / /_/ / / __/
/_/ /_/ /_/_/_/ /_/ /_/_.___/_/\___/
____ __ __ _ __ __ _ __ ___
/ __ \____ / /_ ____ / /_(_)_________ / //_/(_) /_ |__ \
/ /_/ / __ \/ __ \/ __ \/ __/ / ___/ ___/ / ,< / / __/ __/ /
/ _, _/ /_/ / /_/ / /_/ / /_/ / /__(__ ) / /| |/ / /_ / __/
/_/ |_|\____/_.___/\____/\__/_/\___/____/ /_/ |_/_/\__/ /____/
*/
//All the libraries used
#include <WiFiEsp.h>
#include <WiFiEspUdp.h>
#include "SoftwareSerial.h"
//Create Serial communication Object
SoftwareSerial Serial1(8, 9); // RX, TX
WiFiEspUDP Udp;
IPAddress apIP = IPAddress(192, 168, 111, 111);
IPAddress stationIP = IPAddress(192, 168, 111, 112);
IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
//Wifi settings
char ssid[] = "My WiFi Robot"; // the name of your access point
char pass[] = "password"; // the password for your access point
int status = WL_IDLE_STATUS; // the Wifi radio's status
//Ports to be used
unsigned int listeningPort = 10003; // local port to listen on
unsigned int sendingPort = 10002; // local port to sent on
//Message Variables
#define arrayLength 6
char data[arrayLength + 1];
String dataAsString;
// Vaiables
int leftData;
int rightData;
void setup()
{
// Start Serial Communication with computer and WiFi module
Serial.begin(9600);
// initialize serial for ESP module
Serial1.begin(9600);
// initialize ESP module
WiFi.init(&Serial1);
WiFi.config(stationIP);
// Connect to robot
status = WiFi.begin(ssid, pass);
// Set up UDP listener on port
Udp.begin(listeningPort);
// Print out which port
Serial.print(F("Listening on port "));
Serial.println(listeningPort);
}
void loop() {
//Read the Joystick values
leftData = analogRead(A0);
rightData = analogRead(A2);
//Concatanate all the vlaues into one string
dataAsString = String(leftData) + String(rightData);
//Convert String to char array
dataAsString.toCharArray(data, arrayLength + 1);
//Print out all values
Serial.println(data);
//Begin UDP sending
Udp.beginPacket(apIP, sendingPort);
//Send the data
Udp.write(data);
//Send ending packets
Udp.endPacket();
//Battery saving delay
delay(10);
}
Observe
Make sure RS1 is powered and open up the Serial Monitor. You should see the Controller attempting to connect to the network created by RS1. After connected it will start sending the joystick position. Move the left joystick to control the left wheel and the right joystick to control the right wheel.
Modify
Change the robot's motor speed to go faster or slower and take a look at the following section for upgrades!
Start
Nonholonomic vs Holonomic
When it comes to movement there are two main differences. One is a system of movement where we can go in whatever direction we want. This would be an example of a Holonomic system. The other system is one where we cannot move however we want. This is called a Nonholonomic system. This is the type of system in which a car fits. To parallel park we cannot just slide into the spot. We must take many steps to achieve the result that a slide would get us. As we can see in the video above, the forklift is fitted with special wheels that allow it move in a Holonomic system. It can move forward, backwards, side to side, as well as turning.
Quick terms
Some words we need to know are defined in the part.
Vector - A Vector is a direction and magnitude. Going 50 miles per house is just a magnitude but going 50 miles per hour heading west is a vector. The magnitude can be any unit of speed. Such as miles per hour or meters per second. A direction can be a compass heading or degrees.
Nonholonomic Example
Let's look at how a car moves. The tires use friction to move the car. The tires can only produced motion in the way they are pointed. You use the pedals to apply a magnitude of speed and the steering wheel to apply a direction. These two values come together to create a vector. You can see the vector as a red arrow in the picture below.

Tank or Differential Drive
Tank drive keeps the wheel locked into one position. All the direction part of the vector comes from a difference in magnitude of the two sides. This is best illustrated in the picture below. One side is going forward and the other backward. This creates a stationary turn. Check out vectors below.

Holonomic Examples
Here are two examples of Holonomic driving systems.
Omni-wheels

Omni-wheels are wheels that In the picture below check out the individual vectors on the left and the sum total on the right.have rollers along the circumference. They rotate like normal tires but due to the rollers, you can move side to side. They are usually found at 90 or 120 degree differences to each other. Unlike a car that would have all the tires facing the same direction. By combining the vectors of multiple wheels you can achieve a Holomonic drive system. In the picture below check out the individual vectors on the left and the sum total on the right.

Mecanum Wheels

Mecanum wheels are mounted similar to normal tires and have rollers like omni-wheels. However, their rollers are positioned at 45 degree angle to how like rotate. This allows them to create the same vectors as omni-wheels but in a simpler layout. In the picture below check out the individual vectors on the left and the sum total on the right.

Start
In this section we will use the two buttons on the Controller to control individual LEDs on the robot. You'll see the frame work needs to add other inputs and outputs.
Connecting the Buttons
Take a cable. Unwrap it and place one end into the left button on the Controller. The other end of the cable should go into D6. Take another cable. Unwrap it and place one end into the right button on the controller. The other end should go into D5.







Upload
Upload the following code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
________ _ __ __
/_ __/ /_ (_)___ ___ / /_ / /__
/ / / __ \/ / __ `__ \/ __ \/ / _ \
/ / / / / / / / / / / / /_/ / / __/
/_/ /_/ /_/_/_/ /_/ /_/_.___/_/\___/
____ __ __ _ __ __ _ __ ___
/ __ \____ / /_ ____ / /_(_)_________ / //_/(_) /_ |__ \
/ /_/ / __ \/ __ \/ __ \/ __/ / ___/ ___/ / ,< / / __/ __/ /
/ _, _/ /_/ / /_/ / /_/ / /_/ / /__(__ ) / /| |/ / /_ / __/
/_/ |_|\____/_.___/\____/\__/_/\___/____/ /_/ |_/_/\__/ /____/
*/
//All the libraries used
#include <WiFiEsp.h>
#include <WiFiEspUdp.h>
#include "SoftwareSerial.h"
//Button sockets
#define leftSocket 5
#define rightSocket 6
//Create Serial communication Object
SoftwareSerial Serial1(8, 9); // RX, TX
WiFiEspUDP Udp;
IPAddress apIP = IPAddress(192, 168, 111, 111);
IPAddress stationIP = IPAddress(192, 168, 111, 112);
IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
//Wifi settings
char ssid[] = "My Wifi Robot"; // the name of your access point
char pass[] = "password"; // the password for your access point
int status = WL_IDLE_STATUS; // the Wifi radio's status
//Ports to be used
unsigned int listeningPort = 10003; // local port to listen on
unsigned int sendingPort = 10002; // local port to sent on
//Message Variables
#define arrayLength 8
char data[arrayLength + 1];
String dataAsString;
// Vaiables
int leftData;
int rightData;
int leftButton;
int rightButton;
void setup()
{
// Start Serial Communication with computer and WiFi module
Serial.begin(9600);
// initialize serial for ESP module
Serial1.begin(9600);
// initialize ESP module
WiFi.init(&Serial1);
WiFi.config(stationIP);
// Connect to robot
status = WiFi.begin(ssid, pass);
// Set up UDP listener on port
Udp.begin(listeningPort);
// Print out which port
Serial.print(F("Listening on port "));
Serial.println(listeningPort);
}
void loop() {
//Read the Joystick values
leftData = analogRead(A0);
rightData = analogRead(A2);
//Read button values
leftButton = digitalRead(leftSocket);
rightButton = digitalRead(rightSocket);
//Concatanate all the vlaues into one string
dataAsString = String(leftData) + String(rightData) + String(leftButton)+ String(rightButton);
//Convert String to char array
dataAsString.toCharArray(data, arrayLength + 1);
//Print out all values
Serial.println(data);
//Begin UDP sending
Udp.beginPacket(apIP, sendingPort);
//Send the data
Udp.write(data);
//Send ending packets
Udp.endPacket();
//Battery saving delay
delay(10);
}
Observe
Taking a quick look at the code you can see that we added two more placed to the
data[]
array. One for each button. We are adding those values to the string that we send the robot.
Adding the LEDs
We'll need two Chainable LEDs as well as two more cables. Plug one cable into D6 on the Robot and the other side into the IN socket on one of the Chainable LEDs. Take another cable and plug that into the OUT side of the same LED. The other side of cable should go into the IN side of the remaining and unconnected LED. You can now take some tape and tape them down to the Robot chassis.





Upload
Upload the following code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
________ _ __ __
/_ __/ /_ (_)___ ___ / /_ / /__
/ / / __ \/ / __ `__ \/ __ \/ / _ \
/ / / / / / / / / / / / /_/ / / __/
/_/ /_/ /_/_/_/ /_/ /_/_.___/_/\___/
____ __ __ _ __ __ _ __ ___
/ __ \____ / /_ ____ / /_(_)_________ / //_/(_) /_ |__ \
/ /_/ / __ \/ __ \/ __ \/ __/ / ___/ ___/ / ,< / / __/ __/ /
/ _, _/ /_/ / /_/ / /_/ / /_/ / /__(__ ) / /| |/ / /_ / __/
/_/ |_|\____/_.___/\____/\__/_/\___/____/ /_/ |_/_/\__/ /____/
*/
//All the libraries used
#include <WiFiEsp.h>
#include <WiFiEspUdp.h>
#include "SoftwareSerial.h"
#include "Grove_I2C_Motor_Driver.h"
#include <ChainableLED.h>
//Create Chainable LED object
ChainableLED leds(6, 7, 2);
// default I2C address is 0x0f
#define I2C_ADDRESS 0x0f
//Motor names
#define LEFTMOTOR MOTOR2
#define RIGHTMOTOR MOTOR1
//Joystick Limits
int leftUp = 253;
int leftDown = 769;
int rightUp = 775;
int rightDown = 247;
//Button Variables
int leftButton = 0;
int rightButton = 0;
//Create Serial communication Object
SoftwareSerial Serial1(8, 9); // RX, TX
WiFiEspUDP Udp;
IPAddress apIP = IPAddress(192, 168, 111, 111);
IPAddress stationIP = IPAddress(192, 168, 111, 112);
IPAddress broadcastIP = IPAddress(0, 0, 0, 0);
//Wifi settings
char ssid[] = "My Wifi Robot"; // the name of your access point
char pass[] = "password"; // the password for your access point
int status = WL_IDLE_STATUS; // the Wifi radio's status
//Ports to be used
unsigned int listeningPort = 10002; // local port to listen on
unsigned int sendingPort = 10003; // local port to sent on
//Message Variables
#define arrayLength 8
char data[arrayLength + 1];
String dataAsString;
// Vaiables
int leftData = 0;
int rightData = 0;
//Motor Variables
int leftSpeed = 0;
int rightSpeed = 0;
void setup()
{
// Start Serial Communication with computer and WiFi module
Serial.begin(9600);
// initialize serial for ESP module
Serial1.begin(9600);
// initialize ESP module
WiFi.init(&Serial1);
WiFi.configAP(apIP);
// start motor driver
Motor.begin(I2C_ADDRESS);
// correct pwm cycles
Motor.frequence(F_490Hz);
// Print out debugging messages
Serial.print("Attempting to start AP ");
Serial.println(ssid);
// start access point
status = WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK);
// Set up UDP listener on port
Udp.begin(listeningPort);
// Print out which port
Serial.print(F("Listening on port "));
Serial.println(listeningPort);
//Initalize the LEDs
leds.init();
//Turn both off
leds.setColorRGB(0, 0, 0, 0);
leds.setColorRGB(1, 0, 0, 0);
}
void loop()
{
//Check for incoming packets
int packetSize = Udp.parsePacket();
// If there are packets
if (packetSize) {
//memset(data, 0, sizeof data);
//Print out update
//Serial.println("Packets Received");
// read the packet into packetBufffer
int len = Udp.read(data, arrayLength);
if (len > 0) {
data[len] = 0;
}
//Send received data to function
dataTranslate(data);
//Map values to speeds
leftSpeed = map(leftData, leftDown, leftUp, -100, 100);
rightSpeed = map(rightData, rightDown, rightUp, -100, 100);
}
//Check left button values
if (leftButton) {
//Set Left LED to green
leds.setColorRGB(0, 0, 255, 0);
} else {
//Set LED off
leds.setColorRGB(0, 0, 0, 0);
}
//Check left button values
if (rightButton) {
//Set Right LED to green
leds.setColorRGB(1, 0, 255, 0);
} else {
//Set LED off
leds.setColorRGB(1, 0, 0, 0);
}
//Check to see if joystick is in deadzone
if (leftSpeed < 10 && leftSpeed > -10) {
//Stop motor
Motor.stop(LEFTMOTOR);
} else {
//Set motor to mapped speed
Motor.speed(LEFTMOTOR, leftSpeed);
}
//Check to see if joystick is in deadzone
if (rightSpeed < 10 && rightSpeed > -10) {
//Stop motor
Motor.stop(RIGHTMOTOR);
} else {
//Set motor to mapped speed
Motor.speed(RIGHTMOTOR, rightSpeed);
}
//Print out all values
Serial.println(String(leftSpeed) + "," + String(rightSpeed) + "," + String(leftButton) + "," + String(rightButton));
}
//Function that takes raw string and chops it into values
void dataTranslate(char recData[]) {
//Set passed array into a temp variable
dataAsString = recData;
//Write a section of the array to a value based on location
leftData = dataAsString.substring(0, 3).toInt();
rightData = dataAsString.substring(3, 6).toInt();
leftButton = dataAsString.substring(6, 7).toInt();
rightButton = dataAsString.substring(7, 8).toInt();
}
Observe
We added variables to store the new information that we are sending. You can find that towards the top of the code. In the
dataTranslate
function we added two new lines that read the values of the buttons from the string sent over to the Robot.
In the main loop of the code is where we set the LEDs color based on those translated button values.
Going Further
We could have added a dial or any other sensor to the controller. For simple switches we only see one more byte in the
data[]
array. For an analog value we would need 4 bytes.
On the receiving side, it's important to keep track of which values are where in the string.