Robot control with esp8266 receiver

Posted on Posted in Arduino

Despite successful attempts toggling pins with web server library, telnet protocol was way more reliable and faster. DHT temperature module is still included in code but optional, as well as the display. Status updates can still be received live over serial monitor.

Parts needed:

Wemos D1 Mini: www.ebay.de/WeMos-D1-mini  6€

Roboter kit: http://www.ebay.de/itm/Arduino-Roboter 11€

Motor-Dual-Bridge: www.ebay.de/itm/DE-Ship-L298N-Driver-Stepper-Motor-H-Dual-Bridge 3€

sum: 20€

Optional:

DHT11: www.ebay.de/DHT11  3.30€

LCD with i2c interface: www.ebay.de/itm/LCD-1602-Blau-  5.50€

 

Board circuit:

Arduino source code:

#include <ESP8266WiFi.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"

LiquidCrystal_I2C lcd(0x3F, 16, 2);

//how many clients should be able to telnet to this ESP8266
#define MAX_SRV_CLIENTS 3
#define DHTTYPE DHT11   // DHT 11

// TO BE CHANGED
// *************************************************
const char* ssid     = "***************"; // SSID existing WIFIs
const char* password = "***************"; // Password existing WIFIs
const int DHTPin = 16; //PIN D0 for DHT11 Input DATA
// *************************************************

IPAddress gateway(192,168,178,1); // IP-Adress Wifi-Gateway
IPAddress subnet(255,255,255,0);  // Subnet
IPAddress ip(192,168,178,52); // Static IP Adress for WeMos

WiFiServer server(23); // --> default port for communication usign TELNET protocol | Server Instance
WiFiClient serverClients[MAX_SRV_CLIENTS]; // --> Client Instanse

DHT dht(DHTPin, DHTTYPE);
//dht.begin(); 
//UNCOMMENT IF YOU HAVE DHT

String Name;
String temperature = "Temperature: ";
String humidity = "Humidity: ";

void setup() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.init();
  lcd.backlight();// Turn on the backlight.

   D3_off(); D4_off(); D5_off(); D6_off();

  WiFi.config(ip, gateway, subnet);
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  // -->Try to connect to particular host for 100 times, If still not connected then automatically resets.
  Serial.print("Connecting to "); Serial.println(ssid); lcd.print("Connecting...");
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 100) delay(500);
  if(i == 100){
    Serial.print("Could not connect to "); Serial.println(ssid);
    while(1);
  }
  //start UART and the server
  Serial.begin(115200);
  server.begin();
  server.setNoDelay(true); // --> Won't be storing data into buffer and wait for the ack. rather send the next data and in case nack is received, it will resend the whole data
  Serial.print("Ready! Use 'telnet ");Serial.print(WiFi.localIP()); Serial.println(" 23' to connect");
  lcd.clear();
  lcd.print("Ready to connect!");
}

void loop() {
     lcd.print(getString());
}

char* getString()
{
  uint8_t i;
  //check if there are any new clients
  if (server.hasClient()){
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      //find free/disconnected spot
      if (!serverClients[i] || !serverClients[i].connected()){
        if(serverClients[i]) serverClients[i].stop();
        serverClients[i] = server.available();
        Serial.print("New client: "); Serial.println(i);
        lcd.clear(); lcd.print("Connected");
        continue;
      }
    }
    //no free/disconnected spot so reject
    WiFiClient serverClient = server.available();
    serverClient.stop();
  }
  //check clients for data
  for(i = 0; i < MAX_SRV_CLIENTS; i++){
    if (serverClients[i] && serverClients[i].connected()){
      static char str[21]; // For strings of max length=20
      if(serverClients[i].available()){
          delay(64); // wait for all characters to arrive
          memset(str,0,sizeof(str)); // clear str
          byte count=0;
        //get data from the telnet client and push it to the UART
        while(serverClients[i].available()){
           char c=serverClients[i].read();
           if (c>=32 && count<sizeof(str)-1)
             {
                lcd.clear();
                str[count]=c;
                count++;
             }
        }  
        str[count]='\0'; // make it a zero terminated string
        if (strcmp(str, "t") == 0)
          temperatureOutput();
        else if (strcmp(str, "f") == 0) //forward on
         {D4_on();
          D6_on();}
        else if (strcmp(str, "F") == 0) //forward off
        {D4_off();
         D6_off();}
        else if (strcmp(str, "b") == 0) //backwards on
         {D3_on();
         D5_on();}
        else if (strcmp(str, "B") == 0) //backwards off
         {D3_off();
          D5_off();}
        else if (strcmp(str, "l") == 0) //left on
          D6_on();
        else if (strcmp(str, "L") == 0) //Left off
          D6_off();
        else if (strcmp(str, "r") == 0) //right on
          D5_on();
        else if (strcmp(str, "R") == 0) //right off
          D5_off();
        else
           return str;        
    }
  }
  //check UART for data
  if(Serial.available()){
    size_t len = Serial.available();
    uint8_t sbuf[len];
    Serial.readBytes(sbuf, len);
    //push UART data to all connected telnet clients
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      if (serverClients[i] && serverClients[i].connected()){
        serverClients[i].write(sbuf, len);
        delay(1);
      }
    }
  }
 }
}
void temperatureOutput()
{
  float h = dht.readHumidity();
            float t = dht.readTemperature();
            if (isnan(h) || isnan(t)) 
               lcd.print("Failed to read from DHT sensor!");
            else
               lcd.print("Temperature:");
               lcd.print(t);
               lcd.setCursor(0,1);
               lcd.print("Humidity:");
               lcd.print(h);
}
void D4_on() {
      pinMode(D4, OUTPUT);
      digitalWrite(D4, HIGH);
      delay(100);
      Serial.println("D4 turned on over TELNET");
    }
void D4_off() {
      pinMode(D4, OUTPUT);
      digitalWrite(D4, LOW);
      delay(100);
      Serial.println("D4 turned off over TELNET");
    }
void D3_on() {
      pinMode(D3, OUTPUT);
      digitalWrite(D3, HIGH);
      delay(100);
      Serial.println("D3 turned on over TELNET");
    }
void D3_off() {
      pinMode(D3, OUTPUT);
      digitalWrite(D3, LOW);
      delay(100);
      Serial.println("D3 turned off over TELNET");
    }
void D5_on() {
      pinMode(D5, OUTPUT);
      digitalWrite(D5, HIGH);
      delay(100);
      Serial.println("D5 turned on over TELNET");
    }
void D5_off() {
      pinMode(D5, OUTPUT);
      digitalWrite(D5, LOW);
      delay(100);
      Serial.println("D5 turned off over TELNET");
    }
void D6_on() {
      pinMode(D6, OUTPUT);
      digitalWrite(D6, HIGH);
      delay(100);
      Serial.println("D6 turned on over TELNET");
    }
void D6_off() {
      pinMode(D6, OUTPUT);
      digitalWrite(D6, LOW);
      delay(100);
      Serial.println("D6 turned off over TELNET");
    }

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/loginpanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="visible">

        <Button
            android:id="@+id/connect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Connect..." />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/chatpanel"
        android:layout_width="match_parent"
        android:layout_height="509dp"
        android:orientation="vertical"
        android:visibility="gone">

        <Button
            android:id="@+id/forward"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="For" />

        <Button
            android:id="@+id/backward"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Back" />

        <Button
            android:id="@+id/left"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Left" />

        <Button
            android:id="@+id/right"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Right" />

        <Button
            android:id="@+id/temperature"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="temperature" />

        <Button
            android:id="@+id/disconnect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Disconnect" />

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/chatmsg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </ScrollView>

    </LinearLayout>

</LinearLayout>

MainActivity.java

package com.example.jonas.robotcontrol;


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {


    static final int SocketServerPORT = 23;

    LinearLayout loginPanel, chatPanel;

    Button buttonConnect;
    TextView chatMsg;

    static final String ServerAdress= "192.168.178.52";

    Button buttonDisconnect;
    Button buttonForward;
    Button buttonBackwards;
    Button buttonLeft;
    Button buttonRight;
    Button buttonTemperature;

    String msgLog = "";

    ChatClientThread chatClientThread = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        loginPanel = (LinearLayout)findViewById(R.id.loginpanel);
        chatPanel = (LinearLayout)findViewById(R.id.chatpanel);

        buttonConnect = (Button) findViewById(R.id.connect);
        buttonDisconnect = (Button) findViewById(R.id.disconnect);
        buttonForward = (Button) findViewById(R.id.forward);
        buttonBackwards = (Button) findViewById(R.id.backward);
        buttonLeft = (Button) findViewById(R.id.left);
        buttonRight = (Button) findViewById(R.id.right);
        chatMsg = (TextView) findViewById(R.id.chatmsg);
        buttonTemperature = (Button) findViewById(R.id.temperature);

        buttonConnect.setOnClickListener(buttonConnectOnClickListener);
        buttonDisconnect.setOnClickListener(buttonDisconnectOnClickListener);
        buttonForward.setOnTouchListener(buttonForwardOnTouchListener);
        buttonBackwards.setOnTouchListener(buttonBackwardsOnTouchListener);
        buttonLeft.setOnTouchListener(buttonLeftOnTouchListener);
        buttonRight.setOnTouchListener(buttonRightOnTouchListener);
        buttonTemperature.setOnClickListener(buttonTemperatureOnClickListener);
    }

  View.OnTouchListener buttonForwardOnTouchListener = new View.OnTouchListener() {
        @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction() == MotionEvent.ACTION_DOWN) {
                    chatClientThread.sendMsg("f\n");
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    chatClientThread.sendMsg("F\n");
                }
                return true;
            }
        };

    View.OnTouchListener buttonBackwardsOnTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event.getAction() == MotionEvent.ACTION_DOWN) {
                chatClientThread.sendMsg("b\n");
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                chatClientThread.sendMsg("B\n");
            }
            return true;
        }
    };

    View.OnTouchListener buttonLeftOnTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event.getAction() == MotionEvent.ACTION_DOWN) {
                chatClientThread.sendMsg("l\n");
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                chatClientThread.sendMsg("L\n");
            }
            return true;
        }
    };

    View.OnTouchListener buttonRightOnTouchListener = new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event.getAction() == MotionEvent.ACTION_DOWN) {
                chatClientThread.sendMsg("r\n");
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                chatClientThread.sendMsg("R\n");
            }
            return true;
        }
    };

    OnClickListener buttonDisconnectOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if(chatClientThread==null){
                return;
            }
            chatClientThread.disconnect();
        }

    };
    OnClickListener buttonTemperatureOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if(chatClientThread==null){
                return;
            }
            chatClientThread.sendMsg("t\n");
        }

    };
    OnClickListener buttonConnectOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            msgLog = "";
            chatMsg.setText(msgLog);
            loginPanel.setVisibility(View.GONE);
            chatPanel.setVisibility(View.VISIBLE);

            chatClientThread = new ChatClientThread(ServerAdress, SocketServerPORT);
            chatClientThread.start();

        }
    };

    private class ChatClientThread extends Thread {

        String dstAddress;
        int dstPort;

        String msgToSend = "";
        boolean goOut = false;

        ChatClientThread(String address, int port) {
            dstAddress = address;
            dstPort = port;
        }

        @Override
        public void run() {
            Socket socket = null;
            DataOutputStream dataOutputStream = null;
            DataInputStream dataInputStream = null;

            try {
                socket = new Socket(dstAddress, dstPort);
                dataOutputStream = new DataOutputStream(
                        socket.getOutputStream());
                dataInputStream = new DataInputStream(socket.getInputStream());
                dataOutputStream.flush();
                while (!goOut) {
                    if (dataInputStream.available() > 0) {
                        msgLog += dataInputStream.readUTF();
                        MainActivity.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                chatMsg.setText(msgLog);
                            }
                        });
                    }
                    if(!msgToSend.equals("")){
                        dataOutputStream.writeUTF(msgToSend);
                        dataOutputStream.flush();
                        msgToSend = "";
                    }
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
                final String eString = e.toString();
                MainActivity.this.runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
                final String eString = e.toString();
                MainActivity.this.runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
                    }
                });
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                if (dataOutputStream != null) {
                    try {
                        dataOutputStream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                if (dataInputStream != null) {
                    try {
                        dataInputStream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                MainActivity.this.runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        loginPanel.setVisibility(View.VISIBLE);
                        chatPanel.setVisibility(View.GONE);
                    }
                });
            }
        }

        private void sendMsg(String msg){
            msgToSend = msg;
        }

        private void disconnect(){
            goOut = true;
        }
    }

}

Leave a Reply

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