Control MeArm Robot With MKR1000 And Your Smartphone

This project allows you to control a MeArm Robot with your smartphone, as if you had many potentiometers in your hands.

dsc01047_vNtwBzRndc

Things used in this project

Story

The communication between the 2 cards uses the I2C protocol, since I could not find a way to use RT / TX.

Finally, the LED located on the original mkr1000 card will be used to indicate whether or not a wifi client is connected.

Code

Master Code (MKR1000)

Arduino

Webserver Code for the MKR1000
/*
  WiFi Web Server Contrôle de robot meArm, affichage LCD et led

  created 18 Mars 2018
  par Fabrice bonne
  
 */

#include <SPI.h>
#include <WiFi101.h>
#include <Wire.h>
// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   90
// size of buffer that stores the incoming string
#define TXT_BUF_SZ   50

char ssid[] = "****";        // your network SSID (name)
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer
char txt_buf[TXT_BUF_SZ] = {0};  // buffer to save text to

int led =  LED_BUILTIN;
int status = WL_IDLE_STATUS;
WiFiServer server(80);

void setup() {
  //Initialize serial and wait for port to open:
  Wire.begin(); // Rejoindre le bus I2C (Pas besoin d adresse pour le maitre)
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Access Point Web Server");

  pinMode(led, OUTPUT);      // set the LED pin mode
  digitalWrite(led, LOW);
  // print the network name (SSID);
  Serial.print("Creating access point named: ");
  Serial.println(ssid);

  // Create open network. Change this line if you want to create an WEP network:
  status = WiFi.beginAP(ssid);
  if (status != WL_AP_LISTENING) {
    Serial.println("Creating access point failed");
    // don't continue
    while (true);
  }

  // wait 10 seconds for connection:
  delay(10000);

  // start the web server on port 80
  server.begin();

  // you're connected now, so print out the status
  printWiFiStatus();
}


void loop() {
  // compare the previous status to the current status
  if (status != WiFi.status()) {
    // it has changed update the variable
    status = WiFi.status();

    if (status == WL_AP_CONNECTED) {
      byte remoteMac[6];

      // a device has connected to the AP
      Serial.print("Device connected to AP, MAC address: ");
      WiFi.APClientMacAddress(remoteMac);
      Serial.print(remoteMac[5], HEX);
      Serial.print(":");
      Serial.print(remoteMac[4], HEX);
      Serial.print(":");
      Serial.print(remoteMac[3], HEX);
      Serial.print(":");
      Serial.print(remoteMac[2], HEX);
      Serial.print(":");
      Serial.print(remoteMac[1], HEX);
      Serial.print(":");
      Serial.println(remoteMac[0], HEX);
      digitalWrite(led, HIGH);
    } else {
      // a device has disconnected from the AP, and we are back in listening mode
      Serial.println("Device disconnected from AP");
      digitalWrite(led, LOW);
    }
  }
  
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
      boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // limit the size of the stored received HTTP request
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();

                        // print the received text to the Serial Monitor window
                        // if received with the incoming HTTP GET string
                        if (GetText(txt_buf, TXT_BUF_SZ)) {
                          Serial.println("\r\nReceived Text:");
                          Serial.println(txt_buf);
                          Wire.beginTransmission(4);
                          Wire.write(txt_buf);
                          Wire.endTransmission();
                        }
                    }
                    else {  // web page request
                        // send rest of HTTP header
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send web page
                        client.println("<!DOCTYPE html>");
                        client.println("<head>");
                        client.println("<title>Control meArm</title>");
                        client.println("<meta name='viewport' content='width=device-width, initial-scale=1.0'>");
                        client.println("<script type='text/javascript'>");
                        
                        //--fonctions javascript
                        //fonction texte
                        client.println("function SendText(){");
                        client.println("nocache = \"&nocache=\" + Math.random() * 1000000;");
                        client.println("var request = new XMLHttpRequest();");
                        client.println("strText = \"&txt=\" + document.getElementById('txt_form').form_text.value + \"&end=end\";");
                        client.println("request.open(\"GET\", \"ajax_inputs\" + strText + nocache, true);");
                        client.println("request.send(null);");
                        client.println("}");

                        //fonction verticale
                        client.println("function Verticale(){");
                        client.println("nocache = \"&nocache=\" + Math.random() * 1000000;");
                        client.println("var request = new XMLHttpRequest();");
                        client.println("strText = \"&txt=\" + \"Vertical=\" + document.getElementById('pos_v').posiv_range.value + \"&end=end\";");
                        client.println("positiv = document.getElementById('pos_v').posiv_range.value;");
                        client.println("document.getElementById('reportv').value=positiv;");
                        client.println("request.open(\"GET\", \"ajax_inputs\" + strText + nocache, true);");
                        client.println("request.send(null);");
                        client.println("}");
                       
                        //fonction horizontale
                        client.println("function Horizontale(){");
                        client.println("nocache = \"&nocache=\" + Math.random() * 1000000;");
                        client.println("var request = new XMLHttpRequest();");
                        client.println("strText = \"&txt=\" + \"Horizontal=\" + document.getElementById('pos_h').posih_range.value + \"&end=end\";");
                        client.println("positih = document.getElementById('pos_h').posih_range.value;");
                        client.println("document.getElementById('reporth').value=positih;");
                        client.println("request.open(\"GET\", \"ajax_inputs\" + strText + nocache, true);");
                        client.println("request.send(null);");
                        client.println("}");
                        
                        //fonction angulaire
                        client.println("function Angulaire(){");
                        client.println("nocache = \"&nocache=\" + Math.random() * 1000000;");
                        client.println("var request = new XMLHttpRequest();");
                        client.println("strText = \"&txt=\" + \"Angle=\" + document.getElementById('pos_a').posia_range.value + \"&end=end\";");
                        client.println("positia = document.getElementById('pos_a').posia_range.value;");
                        client.println("document.getElementById('reporta').value=positia;");
                        client.println("request.open(\"GET\", \"ajax_inputs\" + strText + nocache, true);");
                        client.println("request.send(null);");
                        client.println("}");
                        
                        //fonction pince
                        client.println("function Pince(){");
                        client.println("nocache = \"&nocache=\" + Math.random() * 1000000;");
                        client.println("var request = new XMLHttpRequest();");
                        client.println("strText = \"&txt=\" + \"Ouverture=\" + document.getElementById('pos_p').posip_range.value + \"&end=end\";");
                        client.println("positip = document.getElementById('pos_p').posip_range.value;");
                        client.println("document.getElementById('reportp').value=positip;");
                        client.println("request.open(\"GET\", \"ajax_inputs\" + strText + nocache, true);");
                        client.println("request.send(null);");
                        client.println("}");
                        client.println("</script>");
                        client.println("</head>");
                        client.println("<div>");

                        //--Input texte et Input Range
                        //Envoi de texte
                        client.println("<form id='txt_form' name='frmText'>");
                        client.println("<center><textarea name='form_text' rows='2' cols='16'></textarea></center>");
                        client.println("</form>");
                        client.println("<center><input type=submit value='Send Text' onclick=SendText() /></center></div>");
                        client.println("<div>");
                        client.println("<center>Bouger le robot</center><BR><BR>");
                        
                        //Verticalement
                        client.println("<form id='pos_v' name='posText'>");
                        client.println("<center>Verticalement</center><BR>");
                        client.println("<center>Bas<input type=range name='posiv_range' min='20' max='90' value='45' step='1' onchange=Verticale() />Haut</center>");
                        client.println("</form>");
                        client.println("<center><input type=text id='reportv' size='3'/></center><BR>");
                        
                        //Horizontalement
                        client.println("<form id='pos_h' name='posText'>");
                        client.println("<center>Horizontalement</center><BR>");
                        client.println("<center>Proche<input type=range name='posih_range' min='0' max='80' value='45' step='1' onchange=Horizontale() />Loin</center>");
                        client.println("</form>");
                        client.println("<center><input type=text id='reporth' size='3'/></center><BR>");
                        
                        //Angulaire
                        client.println("<form id='pos_a' name='posText'>");
                        client.println("<center>Tourner le robot</center><BR>");
                        client.println("<center>Gauche<input type=range name='posia_range' min='0' max='180' value='90' step='1' onchange=Angulaire() />Droite</center>");
                        client.println("</form>");
                        client.println("<center><input type=text id='reporta' size='3'/></center><BR>");
                        
                        //Pince
                        client.println("<form id='pos_p' name='posText'>");
                        client.println("<center>Pince</center><BR>");
                        client.println("<center>Ouvert<input type=range name='posip_range' min='0' max='90' value='45' step='1' onchange=Pince() />Fermee</center>");
                        client.println("</form>");
                        client.println("<center><input type=text id='reportp' size='3'/></center><BR>");
                        
                        client.println("</div>");
                        client.println("</body>");
                        client.println("</html>");
                       }
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

// extract text from the incoming HTTP GET data string
// returns true only if text was received
// the string must start with "&txt=" and end with "&end"
// if the string is too long for the HTTP_req buffer and
// "&end" is cut off, then the function returns false
boolean GetText(char *txt, int len)
{
  boolean got_text = false;    // text received flag
  char *str_begin;             // pointer to start of text
  char *str_end;               // pointer to end of text
  int str_len = 0;
  int txt_index = 0;
  
  // get pointer to the beginning of the text
  str_begin = strstr(HTTP_req, "&txt=");
  if (str_begin != NULL) {
    str_begin = strstr(str_begin, "=");  // skip to the =
    str_begin += 1;                      // skip over the =
    str_end = strstr(str_begin, "&end");
    if (str_end != NULL) {
      str_end[0] = 0;  // terminate the string
      str_len = strlen(str_begin);

      // copy the string to the txt buffer and replace %20 with space ' '
      for (int i = 0; i < str_len; i++) {
        if (str_begin[i] != '%') {
          if (str_begin[i] == 0) {
            // end of string
            break;
          }
          else {
            txt[txt_index++] = str_begin[i];
            if (txt_index >= (len - 1)) {
              // keep the output string within bounds
              break;
            }
          }
        }
        else {
          // replace %20 with a space
          if ((str_begin[i + 1] == '2') && (str_begin[i + 2] == '0')) {
            txt[txt_index++] = ' ';
            i += 2;
            if (txt_index >= (len - 1)) {
              // keep the output string within bounds
              break;
            }
          }
        }
      }
      // terminate the string
      txt[txt_index] = 0;
      got_text = true;
    }
  }

  return got_text;
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);
    
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

    return 0;
}



void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);

}

Slave Code (Arduino UNO)

Arduino

The code for the slave card, Arduino UNO. It is used to read the I2C transmission, and convert the orders into movements and LCD display
/*
  WiFi Web Server Contrôle de moteur, affichage LCD et led (Slave)

  created 18 Mars 2018
  par Fabrice bonne
  
 */

#include <Servo.h>
#include <LiquidCrystal.h>
#include <Wire.h> // Librairie pour la communication I2C


LiquidCrystal lcd(7,6,5,4,3,2);          //lcd en bornes 2 à 7
Servo MVertical;
Servo MHorizontal;
Servo MAngle;
Servo MPince;

void setup() {
Wire.begin(4); // Rejoindre le bus à l'adresse #4
Wire.onReceive(receiveEvent); // Preparer une fonction spécifique a la reception de donnee
Serial.begin(9600);
lcd.begin(16, 2);                 //démarrage du module LCD
lcd.clear();
lcd.setCursor(0,0);

MVertical.attach(10);
MHorizontal.attach(8);
MAngle.attach(9);
MPince.attach(11);

MVertical.write(45);
MHorizontal.write(45);
MAngle.write(90);
MPince.write(45);

lcd.clear();
lcd.setCursor(0,0);
lcd.print("EN ATTENTE");
lcd.setCursor(0,1);
lcd.print("D'ENVOI");
}

void loop()
{
  delay(500);
}

// Fonction qui s execute si quelque chose est present sur l interface
void receiveEvent(int howMany)
{
String data = "";
String aff1 = "";
String aff2 = "";
String recherche = "";
int dl;
bool Mot = false;

while (Wire.available()) {     //lecture des ordres envoyés
    data += (char)Wire.read();
}
    Serial.println(data);
    recherche = "Vertical=";  //Recherche des ordres moteurs
    if (data.indexOf(recherche)!=-1){
      aff1 = "Vertical=";
      aff2 = data.substring(9,12);
      Serial.print("Nouvelle valeur V=");
      Serial.println(aff2);
      MVertical.write(aff2.toInt());
      Mot = true ;
    }
    recherche = "Horizontal=";
    if (data.indexOf(recherche)!=-1){
      aff1 = "Horizontal=";
      aff2 = data.substring(11,14);
      Serial.print("Nouvelle valeur H=");
      Serial.println(aff2);
      MHorizontal.write(aff2.toInt());
      Mot = true ;
    }
    recherche = "Angle=";
    if (data.indexOf(recherche)!=-1){
      aff1 = "Angle=";
      aff2 = data.substring(6,9);
      Serial.print("Nouvelle valeur A=");
      Serial.println(aff2);
      MAngle.write(aff2.toInt());
      Mot = true ;
    }
    recherche = "Ouverture=";
    if (data.indexOf(recherche)!=-1){
      aff1 = "Ouverture=";
      aff2 = data.substring(10,13);
      Serial.print("Nouvelle valeur O=");
      Serial.println(aff2);
      MPince.write(aff2.toInt());
      Mot = true ;
    }
    if (Mot == false) {  //Si c'est un texte, découpage et affichage
    dl = data.length();
    Serial.print("longueur :");
    Serial.println(dl);
    if (dl > 16) {
      aff1 = data.substring(0, 16);
      aff2 = data.substring(16, dl);
      Serial.print("découpage :");
      Serial.println(aff1);
      Serial.println(aff2);
     }
    else {
      aff1 = data;
      Serial.println("découpage non requis");
      }
    }
    Serial.println();
    lcd.clear();       //Affichage des infos moteur et texte en Relay
    lcd.setCursor(0,0);
    lcd.print(aff1);
    lcd.setCursor(0,1);
    lcd.print(aff2);
}

Source : Control MeArm Robot With MKR1000 And Your Smartphone


About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top