Sommario:

SmartBin: 8 passaggi
SmartBin: 8 passaggi

Video: SmartBin: 8 passaggi

Video: SmartBin: 8 passaggi
Video: How to Track Steps on XIAOMI Smart Band 8 2024, Dicembre
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 nas informações recuperadas.

Para montar este projeto, è necessario:

  • NodeMCU
  • Sensore Ultrasonico di Distanza
  • Caixa de papelão
  • Protoboard
  • Cabos
  • Dispositivo Android

Passaggio 1: collegamento del sensore O

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

// definisce i numeri dei pin #define pino_trigger 2 //D4

#define pino_echo 0 //D3

Per efetuare a leitura dos dados do sensor, per seguire o tutorial elaborato pelo FilipeFlop, disponível aqui.

float cmMsec, inMsec;

microsec lungo = ultrasonic.timing();

cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM);

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

// Mostra informazioni senza monitor seriale

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

Serial.print(cmMsec);

Serial.print(" - Distancia em polegadas: ");

Serial.println(inMsec);

Dati stringa = Stringa (cmMsec);

Serial.println(dati);

Fase 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 saber o valor para a lixeira vazia. No meu caso, foi de 26, 3cm. Esse é o valor que considerarmos para uma lixeira vazia.

Per simulação, visto che non si può più avere un sensore ultrassônico, si ha un algoritmo per salvare casualmente una distanza lida e 4 lixeiras diferentes.

//Simulando 4 lixeiras

lungo lixeiraID;

ciclo vuoto() {

IDlixeira = random(1, 5);

}

Passaggio 3: caricare Para a Nuvem

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 ao volume de cada lixeira.

Pará conectar a aplicação com o ThingSpeak, é necessario salvare o número da API do canal criado. Siga os passis descritos no site oficial.

De volta à aplicação, vamos utilizza una biblioteca ESP8266WiFi.h per efetuar conexão com o ThingSpeak, e transferir os dados.

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

void connectWifi(){

Serial.print("Connessione a "+ *ssid);

WiFi.begin(ssid, pass);

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

ritardo (500);

Serial.print(".");

}

Serial.println("");

Serial.print("Connessione alla rete");

Serial.println(ssid);

Serial.print("IP: ");

Serial.println(WiFi.localIP());

}

Durante o setup, tentamos efetuar a conexão com a rede.

void setup() {

Serial.begin(9600);

Serial.println("Leggi i dati del sensore…");

//Collegamento al Wi-Fi

connectWifi();

}

E, para enviar os dados para o ThingSpeak, basta abrir uma conexão HTTP padrão, passando o número da API e os parâmetros.

void sendDataTS(float cmMsec, long id){

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

Serial.println("Inviare dati per ThingSpeak ");

String postStr = apiKey;

postStr += "&campo";

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("Connessione: chiudi\n");

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

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

client.print("Lunghezza contenuto: ");

client.print(postStr.length());

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

client.print(postStr);

ritardo(1000);

}

cliente.stop();

}

O primeiro parâmetro corrisponde alla distanza 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 serve também para identificator para qual campo será feito o upload do valor lido.

Passaggio 4: Recuperando Dados Do ThingSpeak

O ThingSpeak permite efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Come 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 informato previamente. Altre cose importanti per il progetto:

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

È un URL che serve per eseguire l'applicazione Android, per recuperare i dati di ThingSpeak.

Passaggio 5: creazione di un'applicazione Android

No Android Studio, piangi un nuovo progetto Android. Per correggere il funzionamento dell'applicazione, è necessario configurare come permessi abaixo no AndroidManifest.

Per utilizzare Google Maps, se necessario pegar uma chave junto ao Google. Siga os passi descritti no link Otter chave de API.

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

La chiave API per le API basate su Google Maps è definita come risorsa stringa.

(Vedi il file "res/values/google_maps_api.xml").

Tieni presente che la chiave API è collegata alla chiave di crittografia utilizzata per firmare l'APK. È necessaria una chiave API diversa per ogni chiave di crittografia, inclusa la chiave di rilascio utilizzata per firmare l'APK per la pubblicazione. Puoi definire le chiavi per le destinazioni di debug e rilascio in src/debug/ e src/release/.

<meta-dati

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

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

Una configurazione completa è disponibile in qualsiasi momento AndroidManifest anexado ao project.

n

Passaggio 6: Recuperando O Feed No Android

Na atividade principal no Android, MainActivity, crie 4 variáveis para identificator cada um dos canais do ThingSpeak a serem lidos:

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";

Para efetuar a leitura dos dados, iremos utilizar uma class do Android específica, chamada JSONObject. Mais uma vez, vamos criar um objeto para cada URL:

JSONObject responseLixeiraA; JSONObject responseLixeiraB; JSONObject responseLixeiraC; JSONObject responseLixeiraD;

Para abrir a conexão com as 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, e retornar o objeto JSON montado.

public JSONObject makeHttpRequest (String url, metodo String, parametri mappa) {

Tentativo {

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

}

if ("GET".uguale(metodo)) { url = url + "?" + parametri codificati; urlObj = nuovo URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(metodo);

} altro {

urlObj = nuovo URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(metodo); urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty("Content-Length", String.valueOf(encodedParams.getBytes().length)); urlConnection.getOutputStream().write(encodedParams.getBytes()); } //Connettiti al server urlConnection.connect(); //Leggi la risposta è = urlConnection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); linea di stringa;

// Analizza la risposta

while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } è chiuso(); json = sb.toString(); //Converti la risposta in JSON Object 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", "Errore durante l'analisi dei dati " + e.toString()); } catch (Exception e) { Log.e("Exception", "Errore durante l'analisi dei dati " + e.toString()); }

// restituisce l'oggetto JSON

restituire jObj;

}

}

De volta a atividade principal, vamos efetuar a chamada às urls de forma assíncrona, escrevendo este código dentro do método 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);

restituire null;}

Quando si esegue il metodo di esecuzione inBackground, o si controlla l'esecuzione di Android passa per il metodo su PostExecute. Neste método, vamos criar os objetos Lixeira, e popular com os dados recuperados do ThingSpeak:

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

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

Visualizza mainView =(View)findViewById(R.id.activity_main); if (success == 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

Calcolatrice SmartBinService = new SmartBinService(); calcolatrice.montaListaLixeiras(feedList);

//Recupera componenti

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

//Dati attuali

Data currentTime = Calendar.getInstance().getTime(); SimpleDateFormat simpleDate = new SimpleDateFormat("gg/MM/aaaa"); String datacorrente = simpleDate.format(currentTime); createDate.setText(KEY_DATE + currentDate + " "); listaDeLixeiras.setAdapter(adattatore);

} catch (JSONException e) {

e.printStackTrace(); }

} altro {

Toast.makeText(MainActivity.this, "Si è verificato un errore durante il caricamento dei dati", Toast. LENGTH_LONG).show();

}

} }); }

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

Step 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.

/** Chiamato quando l'utente tocca il pulsante Mapa */ public void openMaps(View view) { Intent intent = new Intent(this, LixeiraMapsActivity.class);

//Passa a lista de lixeiras

Bundle bundle = new Bundle(); bundle.putParcelableArrayList("lixeiras", feedList); intent.putExtras(pacchetto);

startActivity(intento);

}

No mapa, temos três atividades a executar:

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

Per eseguire i passaggi, è possibile utilizzare un'API Google Directions. Para desenhar as rotas, foram seguidos os passis do tutorial Disegnare le indicazioni stradali del percorso di guida tra due posizioni utilizzando Google Directions in Google Map Android API V2

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

//Località

corrente LatLng privata;

latLng privato lixeiraA; latLng privato lixeiraB; latLng privato lixeiraC; privato LatLng lixeiraD;.

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

private void checkLocationandAddToMap() { // Verifica se l'utente ha concesso l'autorizzazione 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) { //Richiesta l'autorizzazione alla posizione ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Restituzione; }

//Recupero dell'ultima posizione conosciuta usando il Fus

Posizione posizione = LocationServices. FusedLocationApi.getLastLocation(googleApiClient);

//MarkerOptions viene utilizzato per creare un nuovo Marker. Puoi specificare posizione, titolo, ecc. con MarkerOptions

this.current = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions().position(current).title("Posizione attuale");

//Aggiungendo il marker creato sulla mappa, spostando la telecamera in posizione

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

// Sposta istantaneamente la telecamera nella posizione con uno zoom di 15.

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

// Ingrandisci, animando la telecamera.

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

}

Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:

private void addBinALocation() { // Verifica se l'utente ha concesso l'autorizzazione 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) { //Richiesta l'autorizzazione alla posizione ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Restituzione; }

//Praça da Estação

doppia latitudine = -19,9159578; doppia longitudine = -43.9387856; this.lixeiraA = new LatLng(latitudine, longitudine);

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

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

Come posições de latitude e longitude de cada lixeira foram recuperadas através do próprio Google Maps, e deixadas fixas no código. Idealmente, estes valores ficariam salvas em um banco de dados (per esempio Firebase). Será a primeira evolução deste projeto!

O último passo agora é traçar as rotas entre os pontos. Per questo, um conceito muito importante, 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){

// Origine del percorso

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

// Destinazione del percorso

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

//Waypoint lungo il percorso

//waypoint=optimize:true|-19.9227365, -43.9473546|-19.9168006, -43.9361124 Waypoint stringa = "waypoint=optimize:true"; for (LatLng point: waypointsList){ waypoint += "|" + punto.latitudine + ", " + punto.longitudine; }

// Sensore abilitato

Sensore stringa = "sensore=falso";

// Costruire i parametri per il servizio web

Parametri stringa = str_origin+"&"+str_dest+"&"+sensor + "&" + waypoint;

// Formato di output

Uscita stringa = "json";

// Costruire l'URL del servizio web

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

URL di ritorno;

}

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(); }

//Disegna percorsi

// Ottenere l'URL per l'API di Google Directions

Elenco punti = new ArrayList(); points.add(lixeiraB); points.add(lixeiraC); points.add(lixeiraD);

String url = getDirectionsUrl(current, lixeiraA, points);

DownloadTask downloadTask = new DownloadTask(); // Inizia a scaricare i dati json dall'API di Google Directions downloadTask.execute(url); }

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

Fase 8: Conclusione

Estendi il tuo progetto trabalando i concetti di IoT, mostrando tutte le varie opzioni di connessione dispositivi che attraversano il nuovo, ed effettivamente tutte le decisioni sem interferência umana diretta. Inoltre, segue il video del progetto completo, per l'illustrazione, e le fonti di attività non sono disponibili su Android.

Consigliato: