Things used in this project

Hardware components

Software apps and online services

Story

Arduino and servos have pretty much gone together from the inception of the legendary Arduino hardware project. If you look on the web, you see many examples, questions and uses of Arduinos boards and servos together. In this article, I will introduce a set of code to allow the Arduino MKR1000 and some Javascript/Ajax to function as a simple but interactive servo control panel. Studying this code will help you interface with an Arduino with Wifi abilities to put together control or data collection tools that are both interactive and easy to use.

What you will Learn from this Article and its Code

Basic Arduino web server coding

Simple Javascript/Ajax user interfaces

http get requests from Javascript/JQuery

json data strings

Application Workings at a High-Level

The “application” as we will call it here, is in two parts. The first component is on the Arduino MKR1k itself. The microcontroller code is a web responder running on port 80. This web responder listens for requests from a web browser, parses the request sent, executes it and then returns the results of the request back to the browser. On the browser side (Javascript/Ajax) requests are sent via HTTP get requests as the user interacts with the panels controls.

Code Highlights of the Web Responder

The web server for this project is very simple. The code starts out setting up the Wifi connection. Once connected, it opens up a listening socket on port 80. After the setup is complete we get into the main loop of the code. In the loop code we check for new client connections and parses the request data sent. For this application, we really are only interested in the first line any request sent, so once that is read and processed and the rest of the request data is read, but ignored.

We are only needing the actual GET request part – “GET /servoOpen?7 HTTP/1.1”

This line will contain all the information we need to process the command sent in the request. After the first line ending (‘\r\n’) is found, the request info is parsed out. The parameters are pulled out from the file path info. This is anything past the ‘?’, and up to the ‘ ‘ (space) before the ‘HTTP/1.1’ at the end on the line. Once the code gets the parameters (if any), the command sent in is matched by a series if/if elses using the ‘request_is’ function. If there is a match, the function is called sending any parameters sent in. If there is no match found, the line is ignore (no function is called)

After each matching command is executed, the ‘json_ret’ global variable is set to the data that will be sent back to the calling program (the browser in this case). This data is formatted in a JSON format for easy processing by Javascript or other calling languages. The json data is sent back by a call to the ‘sendReturnResp’ function listed in the code and the connection is closed and then waits for another connection.

Code Highlights from the Control Panel

The browser code may look complex at first, but it’s really not. The GUI and it’s processing is done with a combination of css style sheets, HTML5 for the gui elements, jquery/javascript for the html and form manipulation, and then javascript for the data processing and command sending to the server. Noteworthy code from the browser code itself is the ‘connServo’ function. In it you can see good examples for jquery/javascript interaction as well as get requests and json processing.

Loading the Code onto the Controller

To use the Application, you must first download it from the link below (MkrServo Code). After doing so, unzip the file and navigate to the directory that contains the file ‘MkrServo.ino’. Load this into the Arduino IDE and hook the MKR1k board up to your computer for programming. See Arduino IDE setup for info on getting the IDE. You may also need to load the board definition for the MKR1000, see here for more info on that. After you have the IDE ready and the board connected, select your board and com-port and load the code.

You may see the following pop up:

If so just click ‘OK’.

Once the web server code is loaded into the IDE, find the following lines:

Here you will set the SSID (your Wifi router name) and the password use to log on to it. This would be the same you use for your phone, tablet or PC. After that change is made, save the file and send it to your MKR1k by clicking the ‘upload’ button on the IDE.

The Servo Control Panel Interface

This is the screen for the control panel itself. It consists five boxes of different colors or shades (CSS styles). *For this article we will only use and focus on the Device IP fields and buttons (darker blue area) and the Grey box with the actual servo controls and connection buttons.

* — To keep the code limited to the basics, the other buttons are only there for future use and ideas.

To start controlling a servo connected to a MKR1k that is configured with the servo web responder, you must first give the IP address of the controller. To find this, you will need to open up a serial monitor or terminal with the controller connected via USB. You could optionally look at your WiFi router’s admin pages to find the IP as well.

Navigate to the folder with the file ‘Mkr1000servolocal.html’ is it and double click it to run. Once it loads into the browser, copy this IP (Just the ip – i.e. 192.168.34.2) to the ‘Device IP:’ field of the control panel. Connect a servo the the arduino and select the pin from the drop-down you have it connected to and click the ‘Connect’ button. If the control panel code was able to connect to the MKR1k web server, the ‘Connect’ will change to ‘Disconnect’. You can now use the sliders, or buttons to move the servo (The grey box). If it did not connect, open up the javascript console in the browser (Shift + Ctrl + I on Chrome), if there are any errors, correct them and try again. If you get a good connection to the controller, and do not want to type the IP each time, you can do the following… The IP can be saved by clicking the ‘Save IP’ button. Then the next time the control panel used it will load the saved IP automatically. You can remove the save IP with the ‘Delete IP’ button.

NOTE: You will need an HTML5 based browser such as Chrome to use the Servo Control panel.

Going Forward…

I hope you have learned some about Javascript and talking to an Arduino via Wifi from a browser. There are lots more you can do with the browser code as well as the web responder on the MKR1000. You could add the record and playback functions or other functionality. You are only limited by your imagination. Please continue to learn and have fun!

Schematics

Code

/* Mkr1000-Servo control web responder Goal in life: Control servos via http get requests. Written By - Scott Beasley 2016.*/#include<SPI.h>#include<WiFi101.h>#include<Servo.h>#include<string.h>#include<ctype.h>voidServoOpen(Stringpin);voidServoClose(Stringcommand);voidServoSet(Stringcommand);voidServoRead(Stringcommand);voidServoCtrlReset(void);voidsendReturnResp(WiFiClientclient,Stringret_data);boolrequest_is(Stringrequest,Stringreqdata);// Define your Wifi info here#define SSID "YOUR ROUTER SSID"#define PASSWD "YOUR ROUTER PASSWORD"#define BOARDNAME "mkr1000_01"// Define to get extra info from the Serial port#define DEBUG// GlobalsWiFiServerserver(80);// Allow for at least 8 servos.structuserservos{Servoservo;intpin;}userservos[8];intservosinuse=;Stringjson_ret="";voidsetup(void){servosinuse=;intstatus=WL_IDLE_STATUS;inti=;Serial.begin(9600);while(!Serial){if(i++>=1024)break;}// check for the presence of the shield:if(WiFi.status()==WL_NO_SHIELD){Serial.println("WiFi shield not present");// don't continue:while(true);}// Mark all servo slots as free on start.for(inti=;i<9;i++){userservos[i].pin=-1;}// Connect to the WiFi networkSerial.print("\nConnecting to: ");Serial.println(SSID);while(status!=WL_CONNECTED){// Connect to WPA/WPA2 network. Change this line if using open or WEP network:status=WiFi.begin(SSID,PASSWD);// wait 10 seconds for connection:delay(10000);}Serial.println("\nWiFi connected");// Start the tcp listenerserver.begin();// Print the IP addressIPAddressip=WiFi.localIP();Serial.print("Use this URL to connect: ");Serial.print("http://");Serial.print(ip);Serial.println("/");}voidloop(){boolendofline=false;json_ret="";WiFiClientclient=server.available();if(client){#ifdef DEBUGSerial.println("Client connected");#endifStringcurrentLine="";while(client.connected()){if(client.available()){charc=client.read();if(c=='\n'){endofline=true;}elseif(c!='\r'){currentLine+=c;}if(endofline){endofline=false;Stringparms="";#ifdef DEBUGSerial.println("<"+currentLine+">");#endif// Copy the parms sent in the request.intndx1=currentLine.indexOf('?');intndx2=currentLine.indexOf(' ',ndx1);#ifdef DEBUGSerial.println("<"+String(ndx1)+">");Serial.println("<"+String(ndx2)+">");#endifif(ndx1>=){parms=currentLine.substring(ndx1+1,ndx2);}#ifdef DEBUGif(parms.length()>)Serial.println("<"+parms+">");#endifif(request_is(currentLine,"/servoOpen")){ServoOpen(parms);}elseif(request_is(currentLine,"/servoClose")){ServoClose(parms);}elseif(request_is(currentLine,"/servoSet")){ServoSet(parms);}elseif(request_is(currentLine,"/servoRead")){ServoRead(parms);}elseif(request_is(currentLine,"/servoCtrlReset")){ServoCtrlReset();json_ret="{\n\t\"return_code\": 0\n}";}else{break;}#ifdef DEBUGSerial.println("<="+json_ret+"=>");#endifsendReturnResp(client,json_ret);currentLine="";break;}}}// Close the connection when doneclient.stop();#ifdef DEBUGSerial.println("Client disconnected normally");#endif}}boolrequest_is(Stringrequest,Stringreqdata){return(request.indexOf(reqdata)!=-1?1:);}voidsendReturnResp(WiFiClientclient,Stringret_data){Stringreturn_hdr="HTTP/1.1 200 OK\r\n""Content-Type: application/json\r\n""Access-Control-Allow-Origin: *\r\n""Connection: close\r\n""Content-Length: "+String(ret_data.length())+"\r\n\r\n"+ret_data+"\r\n";client.print(return_hdr);}voidServoOpen(Stringpin){inti,return_code=;//convert ascii to integerintpinNumber=pin.charAt()-'0';//Sanity check to see if the pin numbers are within limitsif(pinNumber<||pinNumber>9)return_code=-1;servosinuse++;if(servosinuse>8){return_code=-3;// All servos inuse.}for(i=;i<9;i++){if(userservos[i].pin==-1){// Zap any old attachment.userservos[i].servo.detach();userservos[i].pin=pinNumber;userservos[i].servo.attach(pinNumber);break;}}// Return the servo array element index used.json_ret="{\n\t\"data_value\": \""+String(i)+"\",\n\t\"return_code\": "+return_code+"\n}";}voidServoClose(Stringcommand){intreturn_code=;//convert ascii to integerintindexNumber=command.charAt()-'0';//Sanity check to see if the element numbers are within limitsif(indexNumber<||indexNumber>9)return_code=-1;userservos[indexNumber].pin=-1;servosinuse--;userservos[indexNumber].servo.detach();json_ret="{\n\t\"return_code\": "+String(return_code)+"\n}";}voidServoSet(Stringcommand){intret=-1;//convert ascii to integerintindexNumber=command.charAt()-'0';//Sanity check to see if the pin numbers are within limitsif(indexNumber<||indexNumber>8){ret=-1;}else{Stringvalue=command.substring(2);ret=;userservos[indexNumber].servo.write(value.toInt());}json_ret="{\n\t\"return_code\": "+String(ret)+"\n}";}voidServoRead(Stringcommand){intreturn_code=;intraw_val=;//convert ascii to integerintindexNumber=command.charAt()-'0';//Sanity check to see if the pin numbers are within limitsif(indexNumber<||indexNumber>8)return_code=-1;raw_val=userservos[indexNumber].servo.read();json_ret="{\n\t\"data_value\": \""+String(raw_val)+"\",\n\t\"return_code\": "+String(return_code)+"\n}";}voidServoCtrlReset(void){servosinuse=;// Mark all servo slots as free and close any open.for(inti=;i<9;i++){if(userservos[i].pin!=-1){userservos[i].servo.write(90);// Try and stop if moving.userservos[i].servo.detach();}userservos[i].pin=-1;}}