Introduction: Wi-Fi Browser Controlled Robotic Arm (with Arduino and ESP8266)
Robotic arms kits are getting cheaper and cheaper. You can find different models online and try different methods to control them.
This project is part of a series of tutorials in which I explore different methods for controlling a robotic arm.
In my previous experiment, I used a Nintendo Wii Nunchuk to control a 6-joint robotic arm. You can find it here:
https://www.instructables.com/id/Nunchuk-Controlled-Robotic-Arm-with-Arduino/
This time I wanted to control it remotelly using an cheap ESP8266 WiFi module. For that, I designed a html interface from which I can send commands to my robot, store them and repeat later. I've already used a similar approach on other tutorials:
https://www.instructables.com/id/Wi-Servo-Wi-fi-Browser-Controlled-Servomotors-with/
https://www.instructables.com/id/Joy-Robot-Rob%C3%B4-Da-Alegria-Open-Source-3D-Printed-A/
There are several ways you can use this tutorial. If you don't have a robotic arm kit (and doesn't want to buy or build one) you can still use it to learn something about Arduino programming, and how to interface an Arduino with an ESP8266 module on your own projects. You can also use it to practice your electronics and mechanic skills.
If you like it, please share with your friends or leave suggestions! :D
Step 1: Tools and Materials
The following tools and materials were used in this project:
Tools and materials:
- Solder iron and wire. I had to solder some terminals to Nunchuk's wires in order to connect it to the Arduino;
- Shrinking tube. Some pieces of shrinking tube were used for a better isolation of the conductors;
- Screwdriver. The structure is mounted using some bolts and nuts;
- 6-axis mechanical desktop robotic arm (link). This awesome kit already comes with several components as described bellow. It's reliable and easy to assemble;
- 12V power supply (2A or more);
- ESP8266-01 (link / link). It's used as a 'WiFi modem'. It receives signals from the control interface to be performed by the Arduino;
- Male-female jumper wires (5 wires);
- Arduino Mega (link / link / link). Notice that the robotic arm kit I've used also has a board and controller bundle that already comes with this Arduino board. If you you're not using on of those kits, you might use other Arduino boards as well;
Sain Smart 6-axis mechanical desktop arm already comes with the following components:
- Arduino Mega 2560 R3 (link)
- Control board shield (link)
- NRF24L01+ Wireless Transceiver Module (link)
- MPU6050 3-axis gyroscope and a 3-axis accelerometer (link)
- 71 x M3X8 screw
- 47 x M3 nut
- 2 x U bracket
- 5 x servo bracket
- 4 x 9kg servo (link)
- 2 x 20kg servo (link)
- 6 x metal servo tray
- 3 x U bracket
- 21 x right-angled bracket
- 3 x flange bearing
- 1 x gripper
You might find other robotic arm kits online (link), or even design your own. There are some awesome projects you can 3D print, for instance.
In the next step I'll show you how to assemble the arm kit before wiring up the circuits. If you doesn't have a similar kit, feel free to jump some steps. You can use another robotic arm kit, assemble it and jump directly to the electronics and programming steps.
Step 2: Assembling the Robotic Arm
In this step I'll show you how to assemble the arm kit (mechanical parts) I've used (link). If you doesn't have a similar kit, feel free to jump some steps. You can use another robotic arm kit, assemble it and jump directly to the electronics and programming steps.
- The first part to be assembled is the base of the robot. It's made of two U shaped brackets, joined back to back using four M3 bolts and nuts, as shown in the pictures;
- The first servomotor is mounted perpendicular to the base, using a servo bracket. This profile is attached to the base using four M3 bolts and nuts, as it's shown in the pictures. Servo #1 is place on it's top, and attached using four M3 bolts and nuts. A circular metal horn is attached to the servo axis. The kit comes with several plastic horns. They won't be used for assembling the robot.
- Another servo bracket is mounted perpendicular to the previous one. It's connected to servo #1 horn using four M3 bolts. Servo #2 is installed with four M3 bolts and nuts, and also uses a circular metal horn. An U bracket is then attached to the horn using four bolts. Notice that a M3 bolt is used oposite the servo axis. It gives stability to the structure. A bearing fits on this bolt, and it's locked in position using another M3 nut. This way the U bracket is tightly attached to servo #2 center axis.
- Another U bracket is mounted using four M3 bolts and nuts. On the other end, servo #3 is installed, using a circular metal horn and four bolts. A servo bracket is connected to the servo motor, and a L shaped profile is linked to the servo bracket using some bolts and nuts. Notice that another bearing is used oposite to the servo axis, as described before.
- Another U bracket is connected to the L shaped profile using a set of four M3 bolts and nuts. Similarly to the previous step, servo #4 is mounter to the U bracket using four bolts. Another servo bracket is connected to the servo.
- The fifth servo is connected perpendicular to servo #4 using another servo bracket, installed using four M3 bolts and nut.
- The gripper is then connected to servo #5 axis. On it's top, servo #6 is connected using some bolts, nuts and a metal horn. The gripper has some gears, which will turn the rotation of the servo into a linear movement of the gripper.
Step 3: Wiring Up the Circuits
Once the structure is assembled, you'll be ready to wire up the circuits. I used the controll board shield that came along with my robotic arm kit. It makes the connection of the components easier, since it already comes with specific connectors for the servomotors, power supply, etc.
Unfortunatelly this controll board doesn't have a specific connector for the ESP8266. So I had to use some jumper wires to connect that Wi-Fi module to my Arduino Mega.
Connect the components as follows:
ESP8266:
- ESP8266 RX => Arduino Mega Pin 14 (on the shield)
- ESP8266 TX => Arduino Mega Pin 15 (on the shield)
- ESP8266 Vcc => Ardino Mega Pin 3V3 (on the shield)
- ESP8266 Gnd => Arduino Mega Pin Gnd (on the shield)
- ESP8266 CH_PD => Arduino Mega Pin 3V3 (on the shield, in the connector reserved for the 24L01 module)
You'll notice that the servo control shield has two pins labeled as 5V. Although, one of then is actually a 3.3V pin. Test it with a voltage meter.
Servos:
- Control shield terminal 11 => Servo #1
- Control shield terminal 12 => Servo #2
- Control shield terminal 13 => Servo #3
- Control shield terminal 8 => Servo #4
- Control shield terminal 9 => Servo #5
- Control shield terminal 10 => Servo #6
If you're not using the control shield, you should use the following pin configuration:
- Arduino Pin 11 => Servo #1 (Sgn)
- Arduino Pin 12 => Servo #2 (Sgn)
- Arduino Pin 13 => Servo #3 (Sgn)
- Arduino Pin 8 => Servo #4 (Sgn)
- Arduino Pin 9 => Servo #5 (Sgn)
- Arduino Pin 10 => Servo #6 (Sgn)
- Arduino Gnd => Servos Gnd
- 6V Power supply => Servos Vcc
You'll also need to connect an external 12V power supply. I suggest one with more than 2A output. The servos consume a lot of power, and if the power supply is not powerfull enough, the servos will vibrate and get really hot. They will also lose their strenght.
Don't connect the power source until you've uploaded the Arduino code (shown in later steps). There's a power button on the shield. Keep it on the off position.
Plug an USB cable on the Arduino and proceed to the next step.
Warning! You'll notice I've connected my ESP8266 RX/TX pins directly to the Arduino TX/RX pins. It worked for me, but I don't recommend doing the same. ESP8266 works with 3.3V, and the Arduino pins run on 5V. Some say it might burn your ESP8266 module (although I've tested it several times, and had no issue). You might use a voltage divider or a voltage level shifter if you want to convert 5V to 3.3V.
Step 4: Setup Arduino IDE
Now that the hardware is ready, it's time to work on the Arduino code.
1. Download and install Arduino IDE latest version
You can find the latest version for Windows, Linux or MAC OSX on Arduino's website: https://www.arduino.cc/en/main/software
Download it for free, install it on your computer and launch it.
No additional library was used for the communication between the Arduino and the with ESP8266 module. Please check the baudrate of you ESP8266 and set it properly in the code.
Step 5: Arduino Code
Download Arduino code (browser-controlled-arm-v3.ino) and replace the XXXXX by your wifi router SSID and YYYYY by router password. Connect the Arduino board to your computer USB port and upload the code.
Once the circuit is powered, the arm will move to the starting position, and the ESP8266 will try to connect the Wi-Fi network.
Warning: when the code starts running, the robotic arm will move really fast to it's initial position. Be careful not to get hurt or damage nearby equipment during startup!
You'll possibly have to replace the starting angle of each servomotor depending on how your servos where mounted.
Code explained:
Before the setup, the code imports the libraries used on the sketch. Only servo.h library was used. No library was used for interfacing with the WiFi module.
Pins to be used are defined, and global variables are declared. angle# integer variables store the initial position for each servo. If you want your robot to start at a different position, change the values on those variables.
angle#sp are the set points for each servo. During the execution of the code, the controller will move the motors at a given speed until they reach the setpoints.
servo_speed variable define the speed of the movements for all the servos. If you want a specific servo to move faster, increase its value.
//Include libraries #include <Servo.h> //define variables #define DEBUG true //display ESP8266 messages on Serial Monitor #define SERV1 8 //servo 1 on digital port 8 #define SERV2 9 //servo 2 on digital port 9 #define SERV3 10 //servo 3 on digital port 10 #define SERV4 11 //servo 4 on digital port 11 #define SERV5 12 //servo 5 on digital port 12 #define SERV6 13 //servo 6 on digital port 13 Servo s1; //servo 1 Servo s2; //servo 2 Servo s3; //servo 3 Servo s4; //servo 4 Servo s5; //servo 5 Servo s6; //servo 6 //define starting angle for each servo //choose a safe position to start from //it will try to move instantaniously to that position when powered up! //those angles will depend on the angle of each servo during the assemble int angle1 = 90; //servo 1 current angle int angle2 = 30; //servo 2 current angle int angle3 = 0; //servo 3 current angle int angle4 = 90; //servo 4 current angle int angle5 = 90; //servo 5 current angle int angle6 = 45; //servo 6 current angle int servo_speed = 6; //speed of the servos int angle1sp = 90; //servo 1 set point int angle2sp = 30; //servo 2 set point int angle3sp = 0; //servo 3 set point int angle4sp = 90; //servo 4 set point int angle5sp = 90; //servo 5 set point int angle6sp = 45; //servo 6 set point boolean display_angles = true; //boolean used to update the angle of each servo on Serial Monitor
During the setup, each servo is attached to an especific pin, and its position is started.
Two serial ports of the Arduino Mega are used: one for the Serial Monitor communication and other for the communication with the ESP8266-01 module. Both serial communications are started during the setup.
The communication with the ESP8266 module uses standard AT commands.
First the Arduino sends a command for the rest of the module (using AT+RST). It will restart the module. ESP8266 module might work in station or as a access point. It's set to station mode (using AT+CWMODE=1), and receives a command for the connection to the WiFi router (AT+CWJAP=SSID,PASSWORD). A while loop waits until the connection is successful.
AT+CIFSR command I used to display the IP address attributed to the ESP8266. It will later be used on the control interface. A webserver is then started at port 80. This way the ESP8266 will be able to receive messages addressed to that IP address and port.
//SETUP void setup() { //attach each servo to a pin and start its position s1.attach(SERV1); s1.write(angle1); s2.attach(SERV2); s2.write(angle2); s3.attach(SERV3); s3.write(angle3); s4.attach(SERV4); s4.write(angle4); s5.attach(SERV5); s5.write(angle5); s6.attach(SERV6); s6.write(angle6); //start serial communication Serial.begin(9600); Serial.println("Connecting..."); Serial3.begin(9600); //Wi-Fi connection sendData("AT+RST\r\n", 2000, DEBUG); //reset module sendData("AT+CWMODE=1\r\n", 1000, DEBUG); //set station mode sendData("AT+CWJAP=\"XXXXX\",\"YYYYY\"\r\n", 2000, DEBUG); //connect wifi network while(!Serial3.find("OK")) { //wait for connection } sendData("AT+CIFSR\r\n", 1000, DEBUG); //show IP address sendData("AT+CIPMUX=1\r\n", 1000, DEBUG); //allow multiple connections sendData("AT+CIPSERVER=1,80\r\n", 1000, DEBUG); // start web server on port 80 }
The main loop is repeated over and over. During each scan, the Arduino will check if there's an incoming message. If it does, it will read the full string and break it into six smaller strings. Each one will represent the setpoint for each servo.
void loop() { if (Serial3.available()) //check if there is data available on ESP8266 { if (Serial3.find("+IPD,")) //if there is a new command { String msg; Serial3.find("?"); //run cursor until command is found msg = Serial3.readStringUntil(' '); //read the message String command = msg.substring(0, 3); //command is informed in the first 3 characters. "srs" = command to move the six servos String valueStr1 = msg.substring(4, 7); //next 3 characters inform the desired angle String valueStr2 = msg.substring(8,11); //next 3 characters inform the desired angle String valueStr3 = msg.substring(12,15); //next 3 characters inform the desired angle String valueStr4 = msg.substring(16,19); //next 3 characters inform the desired angle String valueStr5 = msg.substring(20,23); //next 3 characters inform the desired angle String valueStr6 = msg.substring(24,27); //next 3 characters inform the desired angle int angle1sp = valueStr1.toInt(); //convert to integer int angle2sp = valueStr2.toInt(); //convert to integer int angle3sp = valueStr3.toInt(); //convert to integer int angle4sp = valueStr4.toInt(); //convert to integer int angle5sp = valueStr5.toInt(); //convert to integer int angle6sp = valueStr6.toInt(); //convert to integer
The code will increase/decrease the angle of each servo in small steps until it matches received setpoint. In the end of each cycle a delay is used to limit the speed of the motors.
if (angle1 > angle1sp) { angle1 -= 1; s1.write(angle1); } if (angle1 < angle1sp) { angle1 += 1; s1.write(angle1); } . . . delay(100/servo_speed);
Attachments
Step 6: HTML Interface
A simple control interface was designed using html and Javascript. Download it, unzip it and launch it in your web browser. I've tested it in Firefox and Google Chrome browsers.
In order to send commands to the Arduino, user shall enter the IP address assigned to the ESP8266. As it was described before, you can get it using the Serial monitor. Fortunatelly, the IP tends to be repeated itself in the following connections.
On this controll interface, the user can select a given angle for each joint using some sliding bars. Current angle for each servo is shown under each bar.
An Add position to command stack button aloows the user to store current position of the arm on a Command stack in a text box. This way, a sequence of position can be stored, with a configurable delay between each movement.
Each command is define as sr1:angle1 sr2:angle2 sr3:angle3 sr4:angle4 sr5:angle5 sr6:angle6 delay:time. Angles are represented in degrees and time in miliseconds. User can also edit the commands manually on the text box.
Run command stack plays the sequence of commands stored on the command stack. Clear command stack erases the list of commands. User may also save the command list (in a text file) and load it later. This way, one may store sequences of commands and repeat them.
Html code explained:
Html files are divided in head and body sections. The head only displays some metadata and indicate which javascript files will run on that file.
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="author" content="Igor Fonseca Albuquerque"> <title>Control interface</title> <script src="jquery.js"></script> <script src="myscript1.js"></script> </head>
The body is where all the inputs (text forms, buttons, and sliding bars) are defined. A text box was declared for the user to enter the IP address to each the commands will be sent. It's started with a given IP address (192.168.0.9), but you have to update it with the IP address obtained from the Serial Monitor.
<div style="margin: 0; width:500px; height:80px;"> <form name="myform2" action="" method="GET"> ESP8266 IP Address: <input type="text" name="inputbox" value="192.168.0.9"> </form> </div>
Six sliding bar were added in a six column table, one for each servo. Sliding bars are defined using a range type input, with angles between 0 an 180 degrees. Value parameter gives the starting angle for each servo, which is show at a text field bellow each bar.
The user can change the angles by dragging the slider with the mouse. When mouse button is released moveSrs() function is called. It will be descibed later.
<th> <p style="margin: 0; position: relative; top: 0px; left: 0px; width:100px; height:20px;"> Servo 1 </p> <input type="range" id="s1Range" min="0" max="180" value="90" onmouseup="moveSrs(s1Range.value, s2Range.value, s3Range.value, s4Range.value, s5Range.value, s6Range.value)" onchange="updateTextInput1(this.value)" style="margin: 0; position: relative; top: 10px; left: 0px; width:200px; height:40px;" /> <input type="text" id="s1textInput" value="90" style="margin: 0; position: relative; top: 10px; left: -10px; border: none;"> </th>
A button was defined for adding current angles to the command stack. addCommand() function is called when it's clicked. A textbox on its right is used for the user to enter a time delay (in milliseconds) to be used between two commands.
<input type="button" id="button1" value="Add position to command stack" onClick="addCommand(s1textInput.value, s2textInput.value, s3textInput.value, s4textInput.value, s5textInput.value, s6textInput.value, delayValue.value)" style="position: relative; top:60px; height:40px;"> <input type="text" id="delayValue" value="1000" style="position: relative; top:60px; height:35px; width:50px;">
A second table was used to organize other features. A textarea was defined to store the commands stack. Bellow it there are two buttons, which are used to call runCommands() and clearCommads() functions.
<table style="margin: 0; position: relative; top: 80px; left: 0px; width:100%; height:80px;"> <tr><td>Command stack:</td></tr> <tr> <td> <textarea id="inputTextToSave" cols="80" rows="14"></textarea> </td> </tr> <tr> <td> <button onclick="runCommands(inputTextToSave.value)" style="height:40px;">Run command stack</button> <button onclick="clearCommand()" style="height:40px;">Clear command stack</button> <p> </td> </tr><br>
By the end of the table there are some buttons for saving and opening text files.
Javascript code explained:
The html interface calls two Javascript files: jquery.js and myscript.js. In myscript.js I designed my own functions to interact with the robot.
As it was described before, whenever on of the sliders is moved (and released),moveSrs() function is called. It has as inputs the angle of each servo. It processes those values (add some zeros, so that it always have three digits) and send a message to the IP address of the ESP8266 module.
function moveSrs(angle1, angle2, angle3, angle4, angle5, angle6) { TextVar = myform2.inputbox.value; ArduinoVar = "http://" + TextVar + ":80"; //add zeros if (angle1 < 100) { angle1 = "0" + angle1; } if (angle1 < 10) { angle1 = "0" + angle1; } . . . //send command $.wait(5000).then($.get( ArduinoVar, { "srs": angle1 + " " + angle2 + " " + angle3 + " " + angle4 + " " + angle5 + " " + angle6 }, function(data){alert("data:" + data);})) ; {Connection: close}; }
There's one updateTextInput#() function for each servo. It's used only for updating the text under the sliding bar with servos' current angles.
//update text under scroll bars function updateTextInput1(val) { document.getElementById('s1textInput').value=val; }
addCommand() function simply add a new line to the stack textbox with appropriate angles and delays. clearCommand(), in other hand, clears that textbox.
//add command to the stack function addCommand(val1, val2, val3, val4, val5, val6, val7) { document.getElementById('inputTextToSave').value = document.getElementById('inputTextToSave').value + "sr1:" + val1 + " sr2:" + val2 + " sr3:" + val3 + " sr4:" + val4 + " sr5:" + val5 + " sr6:" + val6 + " delay:" + val7 + String.fromCharCode(13, 10); } //clear command stack function clearCommand() { document.getElementById('inputTextToSave').value = ""; }
runCommands() is where the command stack is processed. It reads on line at a time and split it to get the angle of each servo in that command line. I'll notice a setTimout function was used. A time variable 'k' is incremented at each command line by given time (delay value). Using setTimout function, a new command is only sent after a given time was passed, and the ESP8266 won't receive a lot of messagens at the same time. Otherwise, it would have its buffer exceeded and might crash.
//run command stack function runCommands(val) { var k = 0; step = 0; var commands = val.split("\n"),i; for (i = 0; i < commands.length - 1; i++) { setTimeout(function(data){ var angle1 = commands[step].split(" ")[0]; angle1 = angle1.split(":")[1]; var angle2 = commands[step].split(" ")[1]; angle2 = angle2.split(":")[1]; var angle3 = commands[step].split(" ")[2]; angle3 = angle3.split(":")[1]; var angle4 = commands[step].split(" ")[3]; angle4 = angle4.split(":")[1]; var angle5 = commands[step].split(" ")[4]; angle5 = angle5.split(":")[1]; var angle6 = commands[step].split(" ")[5]; angle6 = angle6.split(":")[1]; moveSrs(angle1, angle2, angle3, angle4, angle5, angle6); step+=1; },k); var tempo = commands[step].split(" ")[6]; tempo = tempo.split(":")[1]; k += parseInt(tempo); } }
Attachments
Step 7: Have Fun!
Plug the USB cable on your computer, open the serial monitor and power up the robot.
It will automatically connect your WiFi network and show it's IP address. Save that number. You may now remove the USB cable (and even reset the Arduino). It will probably use the same IP address if you try to connect it again to the same network.
Open the interface on your web browser, and enter the IP address you've seen before. The computer have to be connected to the same WiFi network.
Select the angle for each joint and add to a stack of commands. A delay might be used between any two commands. Notice that the delay have to be large enough to ensure the previous command has ended (the robot has reached last set point) before a new command is sent.
You can save the stack of commands on a .txt file and use it later.
Save some moves, play them and have fun!
If you liked this tutorial, please click the 'like' button and share it with your friends! :D
Step 8: Final Considerations
If you still don't follow my tutorials, take a look at those other projects in which I explain a little bit about internet of things, robotics and 3D printing. I hope you enjoy them too!
https://www.instructables.com/id/IoT-Wallet-smart-...
https://www.instructables.com/id/IoT-Air-Freshner-...
https://www.instructables.com/id/Minimalist-IoT-Cl...
https://www.instructables.com/id/IoT-Air-Freshner-...
https://www.instructables.com/id/Nunchuk-Controll...
Liked any of my projects? Please consider supporting my future projects with a small Bitcoin donation! :D
BTC Deposit Address: 1FiWFYSjRaL7sLdr5wr6h86QkMA6pQxkXJ