Ruschino WiFi

Da raspibo.
Versione del 3 nov 2015 alle 00:24 di Dancast78 (discussione | contributi) (Creata pagina con '= Un robot terrestre, un pò di materiale recuperato, è qualche pezzo di codice = Il progetto nasce per vari motivi: * provare a costruire un robot, perchè è un'esperienza ...')
(diff) ← Versione meno recente | Versione attuale (diff) | Versione più recente → (diff)
Jump to navigation Jump to search

Un robot terrestre, un pò di materiale recuperato, è qualche pezzo di codice

Il progetto nasce per vari motivi:

  • provare a costruire un robot, perchè è un'esperienza nuova e sempre interessante
  • riciclare un pò di hardware a cui vale la pena dare una nuova vita
  • studiare nuove tecnologie sia hardware che software
  • aggiungere un nuovo gioco alla nostra ormai ricca collezione di progetti che mostriamo durante gli eventi e i robottini sono sempre quelli che hanno più successo

Partiamo dall'hardware

Lo scoglio più grande è sicuramente hardware quando si pensa ad un robot e l'occasione di poter utilizzare motori con il riduttore e già facilmente assemblabili era troppo ghiotta per poterla lasciare.

Quasi un anno prima grazie ad Olotoria siamo riusciti a recuperare hardware da un vecchio distributore automatico, mi hanno subito colpito i motori con motoriduttore incorporato e ho voluto cercare di utilizzarli per un progetto.

Motori

Sono motori in corrente continua con un riduttore integrato, che hanno molta coppia, non sono particolarmente semplici da alimentare perchè funzionano a 24 volts.

Hanno una scatola ingranaggi abbastanza grande, ma con il vantaggio che passandoci dentro due barre filettate formano già un telaio.

Ponte H

Per pilotare i motori è necessario un ponte H che sopporti i 24 volts di alimentazione, per questo ho disegnato un board con kicad che utilizza l'integrato L293D ed un paio di transistor per limitare l'utilizzo di pin per il circuuito di comando.

Schede di controllo

La board è anche disegnata per essere montata al posto di un'altra schedina già presente sulla carcassa dei motor, in questo modo si sfruttano anche le viti già predisposte.

Per ridurre le dimensioni della board la dissipazione del ponte ad H potrebbe non essere ottimale, vediamo se saranno necessari accorgimenti particolari in seguito.

Per il comando del robot al momento ci sono anche un arduino nano che s'incastra sulla scheda che ho disegnato ed un modulo ESP8266 connesso alla seriale dell'Arduino.

Altro hardware

Per completare l'assemblaggio di base ho aggiunto qualche supporto stampato in 3D e una ballcaster come terzo punto di appoggio, una scatola per contenere le batterie ed i due convertitori dc/dc, due fusibili, l'interruttore generale.

Software

Il software è ancora in fase di completamento, ma si basa su due elementi intelligenti: ESP8266 che viene utilizzato come access point, e server web.

Arduino che interpreta semplici comandi inviati da ESP8266 e pilota il ponte H.

ESP8266 Web server

Questo è il codice del file web_serv.lua

 local str=wifi.ap.getmac();
 local ssidTemp=string.format("%s%s%s",string.sub(str,10,11),string.sub(str,13,14),string.sub(str,16,17));
 cfg={};
 cfg.ssid="192.168.4.1_Ruschino-"..ssidTemp;
 wifi.ap.config(cfg);
 cfg.ip="192.168.4.1";
 cfg.netmask="255.255.255.0";
 cfg.gateway="192.168.4.1";
 wifi.ap.setip(cfg);
 wifi.setmode(wifi.SOFTAP)
 str=nil;
 ssidTemp=nil;
 collectgarbage();
 print("R=0&l=0&D=0&d=0&E=0&e=0")
 local httpRequest={}
 httpRequest["/"]="index.htm";
 httpRequest["/index.htm"]="index.htm";
 httpRequest["/style.css"]="style.css";
 local getContentType={};
 getContentType["/"]="text/html";
 getContentType["/index.htm"]="text/html";
 getContentType["/style.css"]="text/css";
 local filePos=0;
 if srv then srv:close() srv=nil end
 srv=net.createServer(net.TCP)
 srv:listen(80,function(conn)
    conn:on("receive", function(conn,request)
        --print("[New Request]");
        local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
        if(method == nil)then
         _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
        end
        local formDATA = {}
        if (vars ~= nil)then
            --for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
            --    print("["..k.."="..v.."]");
            --    formDATA[k] = v
            --end   
            print(vars)
        end
        if getContentType[path] then
            requestFile=httpRequest[path];
        --    print("[Sending file "..requestFile.."]");            
            filePos=0;
            conn:send("HTTP/1.1 200 OK\r\nContent-Type: "..getContentType[path].."\r\n\r\n");            
        else
        --    print("[File "..path.." not found]");
            conn:send("HTTP/1.1 404 Not Found\r\n\r\n")
            conn:close();
            collectgarbage();
        end
    end)
    conn:on("sent",function(conn)
        if requestFile then
            if file.open(requestFile,r) then
                file.seek("set",filePos);
                local partial_data=file.read(512);
                file.close();
                if partial_data then
                    filePos=filePos+#partial_data;
                    --print("["..filePos.." bytes sent]");
                    conn:send(partial_data);
                    if (string.len(partial_data)==512) then
                        return;
                    end
                   
                end
            --else
            --    print("[Error opening file"..requestFile.."]");
            end
        end
        --print("[Connection closed]");
        conn:close();
        collectgarbage();
    end)
 end)

Codice del file index.htm

 <html>
 <head>
 <meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0"/>
 <style>
 body {padding: 0; margin: 0;}
 #heade{ border: 3px solid #ff0000; height: 100px; position: fixed; top: 0px; right:  100px; left:  100px}
 #l{ border: 3px solid #ff0000; margin: auto 200px auto 0px; width: 100px; height: 100px; position: fixed; top: 200px; left:  0px}
 #r{ border: 3px solid #0000ff; margin: 0px auto auto 255px; width: 100px; height: 100px; position: fixed; top: 200px; right: 0px}
 .c{ border: -1px solid #000000; width: 100%; position: fixed}
 </style>
 <script>  
 var L=200;
 var R=200;
 var ML=0;
 var MR=0;
 var DL=0;
 var DR=0;
 var EL=0;
 var ER=0;
 addEventListener('touchmove', function(e) {
 e.preventDefault();
 var touch = e.touches[0]; 
 var posY = touch.pageY - 50; 
 var posX = touch.pageX - 50; 
 if (posY>=0 && posY<=400) {
     X=posX;
     Y=posY;
         if(e.touches.length == 1 && posX < 100) {
             document.getElementById("l").style.top = posY+'px';
             L=Math.round(posY);
         }   
         if(e.touches.length == 1 && posX > 250) {
             document.getElementById("r").style.top = posY+'px';
             R=Math.round(posY);
         }
         if(e.touches.length == 2) { // If two fingers are touching
             document.getElementById("l").style.top = posY+'px';
             L=Math.round(posY);
             document.getElementById("r").style.top = posY+'px';
             R=Math.round(posY);
         }
 }        
 }, false);
 addEventListener('touchend', function(e) {
 e.preventDefault();
 var touch = e.touches[0]; 
 var xhttp = new XMLHttpRequest();
 xhttp.onreadystatechange = function() {
 }
 if (L>180 && L<220) {ML=0;EL=0;} //P. centrale 10px toll.
 if (R>180 && R<220) {MR=0;ER=0;}
 if (L>220) {EL=1;DL=1;}
 if (R>220) {ER=1;DR=1;}
 if (L<180) {EL=1;DL=0;}
 if (R<180) {ER=1;DR=0;}
 if (L<180) {ML=Math.round(255-(L*1.30))}
 if (R<180) {MR=Math.round(255-(R*1.30))}
 if (L>220) {ML=Math.round(255-((400-L)*1.30))}
 if (R>220) {MR=Math.round(255-((400-R)*1.30))}
 //document.getElementById("header").innerHTML= ML+'-'+MR+'_'+L+'-'+R;
 xhttp.open("GET", "test?R="+MR+"&l="+ML+"&D="+DR+"&d="+DL+"&E="+ER+"&e="+EL, true);
 xhttp.send();
 }, false);  
 </script>
 </head>
 <body>
 <div id=header></div>
 <div id=l></div>
 <div id=r></div>
 <hr class=c style="top: 190px">
 <hr class=c style="top: 300px">
 </body>
 </html>

Ed infine init.lua

 tmr.alarm(0, 3000, 0, function() dofile('web_serv.lua') end )
 uart.setup(0,115200,8,0,1,0)

Codice arduino

 String comando;
 int en12=9;
 int en34=10;
 int dir12=4;
 int dir34=5;
 int board=1;
 int out_bridge_n=0;
 int incomingByte = 0;
 int s_speed_sx=0;
 int s_speed_dx=0;
 boolean direction_sx=0;
 boolean direction_dx=0;
 boolean enable_sx=0; //non utilizzato
 boolean enable_dx=0; //non utilizzato
 int command_name;
 int position;
 char cmd;
 // Calculate based on max input size expected for one command
 #define INPUT_SIZE 30
 void motor_drive(int out_bridge, boolean dir, int speed) {
  if (out_bridge == 34) {
    digitalWrite(dir34, dir);
    analogWrite(en34, speed);  
  } 
  else if (out_bridge == 12) {
    digitalWrite(dir12, dir);
    analogWrite(en12, speed);
  }  
 }  
 void setup() {
  Serial.begin(115200); 
  pinMode(en12, OUTPUT);
  pinMode(dir12, OUTPUT);
  pinMode(en34, OUTPUT);
  pinMode(dir34, OUTPUT); 
  Serial.println("Start");
 }
 void loop() {
  if (Serial.available() > 0) {
    char input[INPUT_SIZE + 1];
    byte size = Serial.readBytes(input, INPUT_SIZE);
    input[size] = 0;
    char* command = strtok(input, "&");
    while (command != 0)
    {
      char* command_value = strchr(command, '=');
      if (command_value != 0)
      {
        *command_value = 0;
        command_name = command[0];
        ++command_value;
        position = atoi(command_value);
      }
      command = strtok(0, "&");
      switch(command_name) {
      case 'l':
        s_speed_sx=position;
        break;
      case 'R':
        s_speed_dx=position;
        break;  
      case 'D':
        direction_dx=position;
        break;
      case 'd':
        direction_sx=position;
        break;  
      case 'E':
        enable_dx=position;
        break;
      case 'e':
        enable_sx=position;
        break;  
      }  
    }
   motor_drive(34,direction_sx,s_speed_sx);
   motor_drive(12,direction_dx,s_speed_dx); 
  }
 }