Innholdsfortegnelse:

SmartBin: 8 trinn
SmartBin: 8 trinn

Video: SmartBin: 8 trinn

Video: SmartBin: 8 trinn
Video: Kospet TANK T2 Smartwatch Review: The Complete Guide! 2024, November
Anonim
SmartBin
SmartBin

Este é um projeto para um system inteligente de coletas, no qual os caminhões de lixo recebem dados das lixeiras, identifierando 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, é needário:

  • NodeMCU
  • Sensor Ultrassônico de Distancia
  • Caixa de papelão
  • Protoboard
  • Caboer
  • Dispositivo Android

Trinn 1: Conectando O -sensor

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:

// definerer pinnetall #definer pino_trigger 2 // D4

#define pino_echo 0 // D3

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

flyte cmMsec, inMsec;

lang mikrosek = ultralyd.timing ();

cmMsec = ultralyd.konvertering (mikrosek, ultralyd:: CM);

inMsec = ultrasonic.convert (mikrosek, ultralyd:: IN);

// Exibe informerer ingen seriell skjerm

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

Serial.print (cmMsec);

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

Serial.println (inMsec);

String data = String (cmMsec);

Serial.println (data);

Trinn 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Presisaremos conectar o sensor ultrassônico no “teto” da lixeira. For eksempel kan du bruke en 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.

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

lang lixeiraID;

void loop () {

lixeiraID = tilfeldig (1, 5);

}

Trinn 3: Last opp Para a Nuvem

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, av kjent informasjon om en mesmo. Primeiramente, é necessário criar um novo canal, recebendo 4 parâmetros, referentes ao volume de cada lixeira.

Pará conectar a aplicação com ThingSpeak, en nødvendighet salvar eller número da API for canal criado. Siga os passos descritos no site oficial.

De volta à aplicação, vamos utilizar a biblioteca ESP8266WiFi.h para 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 identifierador e a senha de sua rede).

void connectWifi () {

Serial.print ("Koble til"+ *ssid);

WiFi. Begynner (ssid, pass);

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

forsinkelse (500);

Serial.print (".");

}

Serial.println ("");

Serial.print ("Conectado na rede");

Serial.println (ssid);

Serial.print ("IP:");

Serial.println (WiFi.localIP ());

}

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

ugyldig oppsett () {

Serial.begin (9600);

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

// Conectando ao Wi-Fi

connectWifi ();

}

E, for 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 ("Enviando dados para o ThingSpeak");

String postStr = apiKey;

postStr += "& field";

postStr += id;

postStr += "=";

postStr += String (cmMsec);

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

Serial.println (postStr);

client.print ("POST /oppdater HTTP /1.1 / n");

client.print ("Vert: api.thingspeak.com / n");

client.print ("Tilkobling: lukk / n");

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

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

client.print ("Content-Length:");

client.print (postStr.length ());

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

client.print (postStr);

forsinkelse (1000);

}

client.stop ();

}

O primeiro parâmetro correspondonde à 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 serve também fora identifierar para qual campo será feito o upload to valor lido.

Trinn 4: Recuperando Dados Do ThingSpeak

O ThingSpeak tillater efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. As 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. Os mais importantes para o projeto são:

  • CHANNEL_ID: nåmero do seu canal
  • FIELD_NUMBER: o nåmero do campo
  • API_KEY: en chave de API do seu -kanal

Det er en URL som kan brukes av Android, for gjenoppretting av ting fra ThingSpeak.

Trinn 5: Criando og Aplicação Android

Ingen Android Studio, crie um novo projeto Android. Para o correto funcionamento da aplicação, é nødvendigvis konfigurer as permissionsões abaixo no AndroidManifest.

For å bruke Google Maps, er det nødvendig å laste ned Google. Vi kan ikke beskrive noen lenker.

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

API-nøkkelen for Google Maps-baserte APIer er definert som en strengressurs.

(Se filen "res/values/google_maps_api.xml").

Vær oppmerksom på at API -nøkkelen er koblet til krypteringsnøkkelen som ble brukt til å signere APK. Du trenger en annen API -nøkkel for hver krypteringsnøkkel, inkludert utgivelsesnøkkelen som brukes til å signere APK -en for publisering. Du kan definere nøklene for feilsøkings- og utgivelsesmålene i src/debug/og src/release/.

<metadata

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

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

En konfigurasjon som er fullstendig for AndroidManifest, og som også kan brukes.

n

Trinn 6: Recuperando O Feed Ingen Android

På hoveddel ingen Android, MainActivity, crie 4 varianter for identifikasjon av ting du kan gjøre ting Speak 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 classe do Android específica, chamada JSONObject. Mais uma vez, vamos criar um objeto for 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 or objeto JSON montado.

public JSONObject makeHttpRequest (String url, String method, Map params) {

prøv {

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

}

if ("GET".equals (method)) {url = url + "?" + encodedParams; urlObj = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metode);

} annet {

urlObj = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metode); urlConnection.setRequestProperty ("Innholdstype", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). skrive (encodedParams.getBytes ()); } // Koble til serveren urlConnection.connect (); // Les svaret er = urlConnection.getInputStream (); BufferedReader reader = new BufferedReader (new InputStreamReader (is)); StringBuilder sb = new StringBuilder (); String linje;

// Analyser svaret

while ((line = reader.readLine ())! = null) {sb.append (line + "\ n"); } er nært(); json = sb.toString (); // Konverter svaret til JSON Object jObj = nytt JSONObject (json);

} catch (UnsupportedEncodingException e) {

e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Error parsing data" + e.toString ()); } catch (Unntak e) {Log.e ("Unntak", "Feil ved analyse av data" + e.toString ()); }

// returner JSON Object

retur 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 beskyttet String doInBackground (String … params) {HttpJsonParser jsonParser = new HttpJsonParser ();

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

returner null;}

Quando o método doInBackgroundé encerrado, or control de execução to Android passa para o método onPostExecute. Neste método, vamos criar os objetos Lixeira, e popular com us dados recuperados do ThingSpeak:

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

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

View mainView = (Vis) findViewById (R.id.activity_main); if (success == 1) {try {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira (); Lixeira feedDetails2 = ny Lixeira (); Lixeira feedDetails3 = ny Lixeira (); Lixeira feedDetails4 = ny 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 kalkulator = ny SmartBinService (); kalkulator.montaListaLixeiras (feedList);

// Recupera componentes

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

// Data atual

Date currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = ny SimpleDateFormat ("dd/MM/åååå"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adapter);

} fangst (JSONException e) {

e.printStackTrace (); }

} annet {

Toast.makeText (MainActivity.this, "Noen feil oppstod under lasting av data", Toast. LENGTH_LONG).show ();

}

} }); }

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

Trinn 7: Mostrando No Mapa

Mostrando No Mapa
Mostrando No Mapa

Ainda na atividade rektor, kan også fortelle om en ação a ser relacionada ao botão Mapa, and tela inicial.

/ ** Ringes når brukeren trykker på Mapa -knappen*/ public void openMaps (View view) {Intent intention = new Intent (this, LixeiraMapsActivity.class);

// Passa a list de lixeiras

Bundle bundle = new Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); intention.putExtras (bunt);

startActivity (intention);

}

Ingen mapa, temos três atividades en 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

For utførelse av passos acima, bruker vi et API Google Directions. Para desenhar as rotas, foram seguidos os passos do do tutorial Tegne kjøreveibeskrivelser mellom to steder ved hjelp av Google Veibeskrivelse i Google Map Android API V2

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

// Steder

privat LatLng gjeldende;

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

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

private void checkLocationandAddToMap () {// Sjekker om brukeren har gitt tillatelsen hvis (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Be om plasseringstillatelsen ActivityCompat.requestPermissions (denne, nye strengen {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); komme tilbake; }

// Henter den siste kjente plasseringen ved hjelp av Fus

Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);

// MarkerOptions brukes til å lage en ny Marker. Du kan angi plassering, tittel osv. Med MarkerOptions

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

// Legger til den opprettede markøren på kartet, flytter kameraet til posisjon

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

// Flytt kameraet umiddelbart til stedet med en zoom på 15.

mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (nåværende, 15));

// Zoom inn, animere kameraet.

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

}

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

private void addBinALocation () {// Kontrollerer om brukeren har gitt tillatelse til hvis (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (this, android.per.mission.est. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Be om beliggenhetstillatelsen ActivityCompat.requestPermissions (denne, nye strengen {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); komme tilbake; }

// Praça da Estação

dobbel breddegrad = -19,9159578; dobbel lengdegrad = -43,9387856; this.lixeiraA = ny LatLng (breddegrad, lengdegrad);

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

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

Som 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 salvos em um banco de dados (for eksempel Firebase). Será a primeira evolução deste projeto!

O último passo agora é traçar as rotas entre os pontos. Para tal, om conceito muito importante, e que será utilizado next projeto, eller våre veipunkter!

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

private String getDirectionsUrl (LatLng -opprinnelse, LatLng -dest, List waypointsList) {

// Rutens opprinnelse

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

// Destinasjon for rute

String str_dest = "destinasjon ="+dest.breddegrad+","+dest.lengdegrad;

// Veipunkter langs ruten

//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; for (LatLng -punkt: waypointsList) {waypoints += "|" + point.latitude + "," + point.longitude; }

// Sensor aktivert

String sensor = "sensor = false";

// Bygg parametrene til webtjenesten

Stringparametere = str_origin+"&"+str_dest+"&"+sensor+"&"+veipunkter;

// Utgående format

String output = "json";

// Bygger nettadressen til webtjenesten

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

retur url;

}

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

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

checkLocationandAddToMap ();

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

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

// Tegn ruter

// Få URL til Google Directions API

Listepunkter = ny ArrayList (); poeng. legge til (lixeiraB); poeng. legge til (lixeiraC); poeng. legge til (lixeiraD);

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

DownloadTask downloadTask = ny DownloadTask (); // Start nedlasting av json -data fra Google Directions API downloadTask.execute (url); }

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

Trinn 8: Konklusjon

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

Anbefalt: