Inhaltsverzeichnis:

SmartBin - Gunook
SmartBin - Gunook

Video: SmartBin - Gunook

Video: SmartBin - Gunook
Video: Guardforce's Smart Waste Bin 2024, November
Anonim
SmartBin
SmartBin

Este é um projeto para um sistema inteligente de coletas, no qual os caminhões de lixo recebem dados das lixeiras, identificando a quantidade de lixo presente em cada uma delas, e uma rota de coleta traçada, com base naser informações.

Para montar este projeto, é necessário:

  • KnotenMCU
  • Sensor Ultrassônico de Distancia
  • Caixa de papelão
  • Protoboard
  • Cabos
  • Dispositiv Android

Schritt 1: Conectando O-Sensor

Primeiramente, vamos efetuar a conexão entre o sensor ultrassônico e o NODEMCU. Para tanto, vamos conectar als Portas trigger und echo do sensor nas portas D4 und D3 do NodeMCU:

// definiert Pinnummern #define pino_trigger 2 //D4

#define pino_echo 0 //D3

Para efetuar a leitura dos dados do sensor, foi seguido oder Tutorial elaborado pelo FilipeFlop, disponível aqui.

float cmMsec, inMsec;

lange Mikrosekunden = ultraschall.timing();

cmMsec = ultraschall.konvertieren (Mikrosekunden, Ultraschall::CM);

inMsec = ultraschall.convert(microsec, Ultrasonic::IN);

// Exibe informacoes kein serieller Monitor

Serial.print ("Distanz em cm:");

Serial.print (cmMsec);

Serial.print (" - Entfernung von den Polegadas: ");

Serial.println (inMsec);

String-Daten = String (cmMsec);

Serial.println (Daten);

Schritt 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no „teto“da lixeira. Para o exemplo, usei um cabo e fita isolante. Em seguida, temos que medir a distância inicial, para sabre o valor para a lixeira vazia. No meu caso, Foi de 26, 3cm. Esse é o valor que Considerarmos para uma lixeira vazia.

Para simulação, visto que não possuo mais de um sensor ultrassônico, foi feito um algoritmo para salvar randomicamente a distancia lida em 4 lixeiras diferentes.

//Simulando 4 lixeiras

langes lixeiraID;

Leere Schleife () {

lixeiraID = zufällig (1, 5);

}

Schritt 3: Laden Sie Para a Nuvem. hoch

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por Familiaridade com o mesmo. Primeiramente, é necessário criar um novo canal, recebendo 4 parâmetros, referentes ua volume de cada lixeira.

Pará conectar aplicação com o ThingSpeak, écessário salvar oder número da API do canal criado. Siga os passos descritos keine offizielle Website.

Zur Anwendung, kann eine Biblioteca ESP8266WiFi.h für die Verbindung mit ThingSpeak und Übertragungen von Daten verwenden.

Primeiramente, uma função para efetuar conexão com a rede (defina previamente duas variáveis, ssid e pass, contendo o identificador e a senha de sua rede).

void connectWifi(){

Serial.print("Verbindung zu "+ *ssid);

WiFi.begin(ssid, pass);

while (WiFi.status() != WL_CONNECTED) {

Verzögerung (500);

Serial.print(".");

}

Serial.println("");

Serial.print ("Conectado na rede");

Serial.println (ssid);

Serial.print("IP:");

Serial.println (WiFi.localIP());

}

Dauer oder Setup, tentamos efetuar a conexão com a rede.

Leere Einrichtung () {

Serial.begin (9600);

Serial.println ("Lendo dados do sensor …");

//Conectando ua Wi-Fi

connectWifi();

}

E, für alle, die für ThingSpeak geeignet sind, um eine Verbindung zu HTTP-Padrão, um die Nummern von API und Parametern zu übergeben.

void sendDataTS(float cmMsec, lange ID){

if (client.connect(server, 80)) {

Serial.println ("Enviando dados para o ThingSpeak");

Zeichenfolge postStr = apiKey;

postStr += "&feld";

postStr += ID;

postStr += "=";

postStr += String(cmMsec);

postStr += "\r\n\r\n";

Serial.println (postStr);

client.print( POST /update

client.print("Host: api.thingspeak.com\n");

client.print("Verbindung: schließen\n");

client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");

client.print("Content-Type: application/x-www-form-urlencoded\n");

client.print("Inhaltslänge: ");

client.print (postStr.length());

client.print("\n\n");

client.print(postStr);

Verzögerung (1000);

}

client.stop();

}

O primeiro parâmetro corresponde à distância em centímetros encontrada pelo sensor ultrassônico. O segundo parâmetro é o ID da lixeira que foi lida (que foi gerado randomicamente, um número de 1 a 4).

O ID da lixeira dient também para identificar para qual campo será feito oder upload do valor lido.

Schritt 4: Recuperando Dados Do ThingSpeak

O ThingSpeak efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Als diferentes opções para leitura do feed do seu canal estão descritas aqui:

www.mathworks.com/help/thingspeak/get-a-ch…

Neste projeto, optou-se por ler diretamente os dados de cada campo. O padrão de URL para este cenário é:

api.thingspeak.com/channels/CHANNEL_ID/fields/FIELD_NUMBER/last.json?api_key=API_KEY&status=true

Cada campo está descrito no link informado previamente. Wichtige Informationen für das Projekt Sao:

  • CHANNEL_ID: número do seu canal
  • FIELD_NUMBER: o número do campo
  • API_KEY: a chave de API do seu canal

Esta é a URL que será lida aplicativa Android, für die Wiederherstellung von ThingSpeak.

Schritt 5: Criando a Aplicação Android

Kein Android Studio, schrei um novo projeto Android. Para oder correto funcionamento da aplicação, é notário configurar als Permissões abaixo no AndroidManifest.

Para utilizar o Google Maps, será notário pegar uma chave junto ua Google. Siga os passos descritos no link Obter chave de API.

Uma vez com a chave, você deve também configurá-la na aplicação.

Der API-Schlüssel für Google Maps-basierte APIs ist als String-Ressource definiert.

(Siehe Datei "res/values/google_maps_api.xml").

Beachten Sie, dass der API-Schlüssel mit dem Verschlüsselungsschlüssel verknüpft ist, der zum Signieren des APK verwendet wird. Sie benötigen für jeden Verschlüsselungsschlüssel einen anderen API-Schlüssel, einschließlich des Freigabeschlüssels, mit dem das APK für die Veröffentlichung signiert wird. Sie können die Schlüssel für die Debug- und Release-Ziele in src/debug/ und src/release/ definieren.

<Meta-Daten

android:name="com.google.android.geo. API_KEY"

android:value="@string/google_maps_key" />

Eine vollständige Konfiguration, die ein AndroidManifest-Projekt erstellt hat.

n

Schritt 6: Recuperando O Feed kein Android

Na atividade Principal kein Android, MainActivity, schreien Sie 4 verschiedene Variationen, um zu identifizieren, wie Sie ThingSpeak in einem Serem Lidos tun können:

private String url_a = "https://api.thingspeak.com/channels/429823/fields/1/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; private String url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; private String url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; private String url_d = "https://api.thingspeak.com/channels/429823/fields/4/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true";

Um eine leitura dos dados, iremos utilizar uma classe für Android speziell, chamada JSONObject. Mais uma vez, vamos criar um objeto para cada URL:

JSONObject-AntwortLixeiraA; JSONObject-AntwortLixeiraB; JSONObject-AntwortLixeiraC; JSONObject-AntwortLixeiraD;

Para abrir a conexão com als URLs, vamos usar criar uma classe auxiliar, chamada HttpJsonParser. Esta classe será responsável por abrir uma conexão com um URL, efetuar leitura dos dados encontrados, und retornar oder objeto JSON montado.

public JSONObject makeHttpRequest(String-URL, String-Methode, Map-Parameter) {

Versuchen {

Uri. Builder-Builder = neuer Uri. Builder(); URL urlObj; String encodedParams = ""; if (params!= null) { for (Map. Entry-Eintrag: params.entrySet()) { builder.appendQueryParameter(entry.getKey(), entry.getValue()); } } if (builder.build().getEncodedQuery() != null) { encodedParams = builder.build().getEncodedQuery();

}

if ("GET".equals(method)) { url = url + "?" + codierte Parameter; urlObj = neue URL (URL); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(Methode);

} anders {

urlObj = neue URL (URL); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(Methode); urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty("Content-Length", String.valueOf(encodedParams.getBytes().length)); urlConnection.getOutputStream().write(encodedParams.getBytes()); } //Mit dem Server verbinden urlConnection.connect(); //Die Antwort lesen ist = urlConnection.getInputStream(); BufferedReader-Reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String-Linie;

//Antwort analysieren

while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } ist in der Nähe(); json = sb.toString(); //Antwort in JSON-Objekt konvertieren jObj = new JSONObject(json);

} catch (UnsupportedEncodingException e) {

e.printStackTrace(); } catch (ProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { Log.e("JSON Parser", "Fehler beim Parsing von Daten" + e.toString()); } catch (Exception e) { Log.e("Exception", "Fehler beim Analysieren von Daten" + e.toString()); }

// JSON-Objekt zurückgeben

Rückgabe jObj;

}

}

De volta a atividade Principal, Vamos efetuar a chamada às URLs de forma assíncrona, escrevendo este código dentro doInBackground.

@Override protected String doInBackground(String… params) { HttpJsonParser jsonParser = new

responseLixeiraA = jsonParser.makeHttpRequest(url_a, "GET", null);

responseLixeiraB = jsonParser.makeHttpRequest(url_b, "GET", null); responseLixeiraC = jsonParser.makeHttpRequest(url_c, "GET", null); responseLixeiraD = jsonParser.makeHttpRequest(url_d, "GET", null);

null zurückgeben;}

Quando oder Methode doInBackground zur Encerrado, oder Kontrolle der Ausführung von Android Passa für oder Methode onPostExecute. Neste Método, Vamos criar oder objetos Lixeira, und beliebte com os dados rekuperados do ThingSpeak:

protected void onPostExecute(String result) { pDialog.dismiss(); runOnUiThread(new Runnable() { public void run() {

//ListView listView =(ListView)findViewById(R.id.feedList);

View mainView =(View)findViewById(R.id.activity_main); if (Erfolg == 1) { try { //Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira(); Lixeira feedDetails2 = new Lixeira(); Lixeira feedDetails3 = new Lixeira(); Lixeira feedDetails4 = new Lixeira();

feedDetails1.setId('A');

feedDetails1.setPesoLixo(Double.parseDouble(responseLixeiraA.getString(KEY_FIELD1))); feedDetails1.setVolumeLixo(Double.parseDouble(responseLixeiraA.getString(KEY_FIELD1)));

feedDetails2.setId('B');

feedDetails2.setPesoLixo(Double.parseDouble(responseLixeiraB.getString(KEY_FIELD2))); feedDetails2.setVolumeLixo(Double.parseDouble(responseLixeiraB.getString(KEY_FIELD2)));

feedDetails3.setId('C');

feedDetails3.setPesoLixo(Double.parseDouble(responseLixeiraC.getString(KEY_FIELD3))); feedDetails3.setVolumeLixo(Double.parseDouble(responseLixeiraC.getString(KEY_FIELD3)));

feedDetails4.setId('D');

feedDetails4.setPesoLixo(Double.parseDouble(responseLixeiraD.getString(KEY_FIELD4))); feedDetails4.setVolumeLixo(Double.parseDouble(responseLixeiraD.getString(KEY_FIELD4)));

feedList.add(feedDetails1);

feedList.add(feedDetails2); feedList.add(feedDetails3); feedList.add(feedDetails4);

//Calcula dados das lixeiras

SmartBinService-Rechner = neuer SmartBinService(); rechner.montaListaLixeiras(feedList);

//Recupera-Komponenten

TextView createDate = (TextView) mainView.findViewById(R.id.date); ListView listaDeLixeiras = (ListView) findViewById(R.id.lista); adapter.addAll(feedList);

//Daten aktuell

Datum currentTime = Calendar.getInstance().getTime(); SimpleDateFormat simpleDate = new SimpleDateFormat("TT/MM/JJJJ"); String currentDate = simpleDate.format(currentTime); createDate.setText(KEY_DATE + currentDate + " "); listaDeLixeiras.setAdapter(Adapter);

} catch (JSONException e) {

e.printStackTrace(); }

} anders {

Toast.makeText(MainActivity.this, "Beim Laden der Daten ist ein Fehler aufgetreten", Toast. LENGTH_LONG).show();

}

} }); }

Agora, na tela inicial do aplicativo, serão listados os dados de cada lixeira.

Schritt 7: Mostrando No Mapa

Mostrando No Mapa
Mostrando No Mapa

Ainda na atividade Principal, vamos adicionar uma ação a ser relacionada ao botão Mapa, na tela inicial.

/** Wird aufgerufen, wenn der Benutzer auf die Mapa-Schaltfläche tippt */ public void openMaps(View view) { Intent Intent = new Intent(this, LixeiraMapsActivity.class);

//Passa a lista de lixeiras

Bundle-Bundle = neues Bundle(); Bundle.putParcelableArrayList("lixeiras", feedList); Absicht.putExtras (Bündel);

startActivity(Absicht);

}

No mapa, temos três atividades a executar:

  1. marcar a posição atual do caminha de lixo
  2. marcar os pontos Correspondentes a cada lixeira no mapa
  3. traçar a rota entre os pontos

Para executar os passos acima, vamos usar a API Google Directions. Para desenhar as rotas, foram seguidos os passos do tutorial Zeichnen von Wegbeschreibungen zwischen zwei Standorten mit Google Directions in Google Map Android API V2

Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:

//Standorte

privater LatLng-Strom;

private LatLng lixeiraA; privates LatLng lixeiraB; privates LatLng lixeiraC; private LatLng lixeiraD;.

Para adicionar a posição atual no mapa, foi criado o método:

private void checkLocationandAddToMap() { //Überprüfen, ob der Benutzer die Berechtigung erteilt hat if (ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_FINE_LOCATION) != PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_COARSE_LOCATION) != PackageManager. PERMISSION_GRANTED) { //Anfordern der Standortberechtigung ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Rückkehr; }

//Abrufen des letzten bekannten Standorts mit dem Fus

Standortstandort = LocationServices. FusedLocationApi.getLastLocation(googleApiClient);

//MarkerOptions werden verwendet, um einen neuen Marker zu erstellen. Sie können Position, Titel usw. mit MarkerOptions angeben

this.current = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions().position(current).title("Posição atual");

// Hinzufügen der erstellten Markierung auf der Karte, Verschieben der Kamera an die Position

markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_GREEN)); System.out.println("++++++++++++ Passei aqui! ++++++++++++"); mMap.addMarker(markerOptions);

// Bewegen Sie die Kamera mit einem Zoom von 15 sofort zum Standort.

mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(aktuell, 15));

// Vergrößern, animieren der Kamera.

mMap.animateCamera(CameraUpdateFactory.zoomTo(14), 2000, null);

}

Em seguida, para cada lixeira, foram criados métodos likes ua abaixo:

private void addBinALocation() { //Überprüfen, ob der Benutzer die Berechtigung erteilt hat if (ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_FINE_LOCATION) != PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_COARSE_LOCATION) != PackageManager. PERMISSION_GRANTED) { //Anfordern der Standortberechtigung ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Rückkehr; }

//Praça da Estação

doppelter Breitengrad = -19,9159578; doppelter Längengrad = -43,9387856; this.lixeiraA = new LatLng(Breitengrad, Längengrad);

MarkerOptions markerOptions = new MarkerOptions().position(lixeiraA).title("Lixeira A");

markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_RED)); mMap.addMarker(markerOptions); }

Als Posições de latitude und longitude de cada lixeira foram recuperadas através do próprio Google Maps, e deixadas fixas no código. Idealmente, estes valores ficariam salvos em um banco de dados (für Firebase-Beispiele). Será a primeira evolução deste projeto!

O último passo agora é traçar als rotas entre os pontos. Para tal, um wichtige Dinge zu beachten, e que será utilizado neste projeto, são os Waypoints!

Foi criado um método para traçar a rota entre dois dados pontos:

private String getDirectionsUrl(LatLng origin, LatLng dest, List waypointsList){

// Ursprung der Route

String str_origin = "origin="+origin.latitude+", "+origin.longitude;

// Ziel der Route

String str_dest = "destination="+dest.latitude+", "+dest.longitude;

//Wegpunkte entlang der Route

//waypoints=optimize:true|-19.9227365, -43.9473546|-19.9168006, -43.9361124 String waypoints = "waypoints=optimize:true"; for (LatLng point: waypointsList){ Wegpunkte += "|" + Punkt. Breitengrad + ", " + Punkt. Längengrad; }

// Sensor aktiviert

Stringsensor = "sensor=false";

// Erstellen der Parameter für den Webservice

Zeichenfolgenparameter = str_origin+"&"+str_dest+"&"+sensor + "&" + Wegpunkte;

// Ausgabeformat

Stringausgabe = "json";

// Aufbau der URL zum Webservice

String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; System.out.println("++++++++++++++ "+url);

Rückgabe-URL;

}

E, por fim, juntando tudo no método Principal da classe, onMapReady:

@Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap;

checkLocationandAddToMap();

if (lixeirasList.get(0).getVolumeLixo() > Lixeira. MIN_VOLUME_GARBAGE

|| lixeirasList.get(0).getPesoLixo()-10 > Lixeira. MIN_SIZE_GARBAGE){ addBinALocation(); } if (lixeirasList.get(1).getVolumeLixo() > Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get(1).getPesoLixo() > Lixeira. MIN_SIZE_GARBAGE){ addBinBLocation(); } if (lixeirasList.get(2).getVolumeLixo() > Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get(2).getPesoLixo() > Lixeira. MIN_SIZE_GARBAGE){ addBinCLocation(); } if (lixeirasList.get(3).getVolumeLixo() > Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get(3).getPesoLixo() > Lixeira. MIN_SIZE_GARBAGE){ addBinDLocation(); }

//Routen zeichnen

// URL zur Google Directions-API abrufen

Listenpunkte = new ArrayList(); Punkte.add(lixeiraB); Punkte.add(lixeiraC); Punkte.add(lixeiraD);

String-URL = getDirectionsUrl(aktuell, lixeiraA, Punkte);

DownloadTask downloadTask = neue DownloadTask(); // Json-Daten von der Google Directions-API herunterladen downloadTask.execute(url); }

Aqui passamos apenas pelos pontos principais. O código completo do projeto será disponibilizado para consulta.

Schritt 8: Fazit

Este foi um projeto trabalhando conceitos de IoT, mostrando uma das várias opções de conectar dispositivos através da nuvem, und efetuar tomada decisões sem interferência humana direta. Em anexo, segue um video do projeto completo, para ilustração, und os fontes das atividades criadas no Android.

Empfohlen: