Sadržaj:

SmartBin: 8 koraka
SmartBin: 8 koraka

Video: SmartBin: 8 koraka

Video: SmartBin: 8 koraka
Video: Автомобильный генератор BMW 12 В 180 А к генератору с помощью зарядного устройства для ноутбука 2024, Novembar
Anonim
SmartBin
SmartBin

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

  • NodeMCU
  • Senzor Ultrassônico de Distancia
  • Caixa de papelão
  • Protoboard
  • Cabos
  • Dispozitivo Android

Korak 1: Conectando O senzor

Primarno, vamos efektivno povezivanje ultrazvučnog senzora i NODEMCU -a. Para tanto, vamos konektar kao okidač porta i senzor eho do nas porta D4 i D3 do NodeMCU:

// definira brojeve pinova #define pino_trigger 2 // D4

#define pino_echo 0 // D3

Para efektiar leitura dos dados do senzor, foi seguido o tutorial elaborado pelo FilipeFlop, disponível aqui.

float cmMsec, inMsec;

dugačak mikrosek = ultrazvučni.timing ();

cmMsec = ultrasonic.convert (mikrosek, Ultrazvuk:: CM);

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

// Exibe informacoes no serijski monitor

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

Serial.print (cmMsec);

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

Serial.println (inMsec);

String data = String (cmMsec);

Serial.println (podaci);

Korak 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Precisaremos konektor ili ultrazvučni senzor bez "teto" da lixeira. Para o exemplo, utilizei 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, 3 cm. Esse é o valor que obzirrarmos para uma lixeira vazia.

Za simulaciju, ako ne morate koristiti ultrazvučni senzor, možete primijeniti algoritam za automatsko čuvanje i distanciranje 4 liksera različitosti.

// Simulando 4 lixeiras

long lixeiraID;

void loop () {{100} {101}

lixeiraID = slučajno (1, 5);

}

Korak 3: Postavite Para a Nuvem

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, ili familiidade com o mesmo. Primeiramente, é neophodário criar um novo channel, recebendo 4 parámetros, reores ao volume de cada lixeira.

Par parametar koji se primjenjuje u ThingSpeak -u, neophodan je za korištenje API -ja u kanalu. Siga os passos descritos no site oficial.

Da biste primijenili aplikaciju, možete koristiti biblioteku ESP8266WiFi.h za efektivno povezivanje s ThingSpeakom ili prijenosom.

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

void connectWifi () {

Serial.print ("Povezivanje sa"+ *ssid);

WiFi.begin (ssid, pass);

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

kašnjenje (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.

void setup () {

Serial.begin (9600);

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

// Conectando ao Wi-Fi

connectWifi ();

}

E, za dodatne informacije o ThingSpeak -u, jednostavno uklonite uzajamno povezivanje HTTP -a, pređite na numeru API -ja i provjerite parametre.

void sendDataTS (float cmMsec, long id) {

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

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

String postStr = apiKey;

postStr += "& polje";

postStr += id;

postStr += "=";

postStr += String (cmMsec);

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

Serial.println (postStr);

client.print ("POST /ažuriraj HTTP /1.1 / n");

client.print ("Domaćin: api.thingspeak.com / n");

client.print ("Veza: zatvori / n");

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

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

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

client.print (postStr.length ());

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

client.print (postStr);

kašnjenje (1000);

}

client.stop ();

}

O primjeru odgovarajućeg parametra odgovara à distância em centímetros encontrada pelo senzora 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 služi tambem para identificar para qual campo será feito o upload do valor lido.

Korak 4: Recuperando Dados Do ThingSpeak

O ThingSpeak dozvolite da efektivno učinite sve što možete učiniti sa kanalom, através de um serviço retornando um JSON. Kako se razlikuju opções para leitura do feed do seu kanala 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 adrã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 nema veze sa informacijama unaprijed. Os mais importantes para o projeto são:

  • CHANNEL_ID: número do seu kanal
  • FIELD_NUMBER: o número do campo
  • API_KEY: API za seve kanal

Ovo je URL adresa koja sadrži aplikacije za Android, za potrebe oporavka za ThingSpeak.

Korak 5: Criando i Aplikação Android

Nema Android Studija, pogledajte novi projekat za Android. Da biste primijenili funkcionalnost aplikacije koja je potrebna, morate konfigurirati dopuštenja za Android ili Manifest.

Za korištenje Google karata, ako vam je potrebna pomoć za korištenje Googlea. Siga os passos descritos no link Obter chave de API.

Uma vez com a chave, você deve também configurá-la na aplikaciji.

API ključ za API-je zasnovane na Google kartama definiran je kao niz izvor.

(Pogledajte datoteku "res/values/google_maps_api.xml").

Imajte na umu da je API ključ povezan s ključem za šifriranje koji se koristi za potpisivanje APK -a. Za svaki ključ šifriranja potreban vam je drugačiji API ključ, uključujući ključ za izdanje koji se koristi za potpisivanje APK -a za objavljivanje. Ključeve za ciljeve otklanjanja grešaka i izdanja možete definirati u src/debug/i src/release/.

<meta-podaci

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

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

Konfiguracija je potpuna i dostupna za AndroidManifest kao dodatak ao projektu.

n

Korak 6: Recuperando O Feed Nema Androida

Na aktivnom principu nema Androida, MainActivity, pogledajte 4 varijacije za identifikaciju kad je u pitanju kanaliranje 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"; privatni niz 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";

Za efektivnu i korisničku nadogradnju, iremos korištenja uma klase za Android específica, chamada JSONObject. Više informacija možete pronaći u objektu za URL 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, efektuar leitura dos dados encontrados, e retornar or object JSON montado.

javni JSONObject makeHttpRequest (URL niza, metoda niza, parametri karte) {

probaj {

Uri. Builder builder = novi 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 = novi URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metoda);

} else {

urlObj = novi URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metoda); urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). write (encodedParams.getBytes ()); } // Povezivanje sa serverom urlConnection.connect (); // Pročitajte odgovor je = urlConnection.getInputStream (); BufferedReader čitač = novi BufferedReader (novi InputStreamReader (je)); StringBuilder sb = novi StringBuilder (); String line;

// Raščlanjivanje odgovora

while ((line = reader.readLine ())! = null) {sb.append (line + "\ n"); } is.close (); json = sb.toString (); // Pretvorimo odgovor u JSON Objekt jObj = novi JSONObject (json);

} catch (UnsupportedEncodingException e) {

e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Greška pri raščlanjivanju podataka" + e.toString ()); } catch (Izuzetak e) {Log.e ("Izuzetak", "Greška pri raščlanjivanju podataka" + e.toString ()); }

// vraća JSON objekt

return jObj;

}

}

De volta atividade principal, vamos efetuar chamada as urls de forma assíncrona, escrevendo este código dentro do método doInBackground.

@Override zaštićen niz doInBackground (String… params) {HttpJsonParser jsonParser = novi 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);

return null;}

Možete preuzeti doInBackground encerrado, izvršnu kontrolu za Android prolaz za metodi naPostExecute. Neste método, vamos criar os Objetos Lixeira, and popular com os dados recuperados do ThingSpeak:

zaštićena praznina naPostExecute (rezultat niza) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {

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

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

// Izračunaj dados das lixeiras

Kalkulator SmartBinService = novi SmartBinService (); calculator.montaListaLixeiras (feedList);

// Recupera components

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

// Stvarni podaci

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

} catch (JSONException e) {

e.printStackTrace (); }

} else {

Toast.makeText (MainActivity.this, "Došlo je do neke greške pri učitavanju podataka", Toast. LENGTH_LONG).show ();

}

} }); }

Agora, na tela inicial za apliciranje, popis stranica koje su navedene kao cada lixeira.

Korak 7: Mostrando bez karte

Mostrando Mapa
Mostrando Mapa

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

/ ** Poziva se kada korisnik dodirne dugme Mapa*/ public void openMaps (prikaz) {Intent intent = new Intent (this, LixeiraMapsActivity.class);

// Prelazak na listu de lixeiras

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

startActivity (namjera);

}

Nema mape, temos três atividades je izvršilac:

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

Da biste izvršili sve potrebne korake, koristite API Google smjernice. Para desenhar as rotas, foram seguidos os passos do tutorial Crtanje uputstava za rutu vožnje između dvije lokacije pomoću Google smjerova na Google Map Android API V2

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

// Lokacije

privatna LatLng struja;

privatni LatLng lixeiraA; privatni LatLng lixeiraB; privatni LatLng lixeiraC; privatni LatLng lixeiraD;.

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

private void checkLocationandAddToMap () {// Provjeravamo je li korisnik odobrio dozvolu if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.missionChement, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Traženje dozvole za lokaciju ActivityCompat.requestPermissions (ovaj, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); return; }

// Dohvaćanje posljednje poznate lokacije pomoću Fus -a

Lokacija lokacije = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);

// MarkerOptions se koriste za kreiranje novog Marker -a. Možete odrediti lokaciju, naslov itd. Pomoću MarkerOptions

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

// Dodavanje kreiranog markera na mapu, pomicanje kamere u položaj

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

// Odmah premjestite kameru na lokaciju sa zumiranjem od 15.

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

// Uvećajte prikaz, animirajući kameru.

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

}

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

private void addBinALocation () {// Provjerava je li korisnik odobrio dozvolu if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission this, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Traženje dozvole za lokaciju ActivityCompat.requestPermissions (ovaj, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); return; }

// Praça da Estação

dvostruka širina = -19,9159578; dvostruka geografska dužina = -43.9387856; this.lixeiraA = novi LatLng (zemljopisna širina, dužina);

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

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

Kao geografska širina i dužina prikazane su cada lixeira za recuperadas através do próprio Google Maps, i deixadas fixas no código. Idealno, estes valores ficariam salvos em um banco de dados (na primjer Firebase). Será a primeira evolução deste projeto!

O último passo agora é traçar as rotas entre os pontos. Para tal, 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) {

// Polazište rute

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

// Odredište rute

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

// Međutočke duž rute

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

// Senzor omogućen

String sensor = "sensor = false";

// Izgradnja parametara web usluge

Parametri niza = str_origin+"&"+str_dest+"&"+senzor+"&"+međutočke;

// Izlazni format

String output = "json";

// Izgradnja URL -a za web uslugu

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

return url;

}

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

@Premosti javnu prazninu 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 (); }

// Crtanje ruta

// Dobivanje URL -a u Google Directions API

Lista bodova = novi ArrayList (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);

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

DownloadTask downloadTask = novi DownloadTask (); // Pokretanje preuzimanja json podataka iz API -ja Google Directions downloadTask.execute (url); }

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

Korak 8: Zaključite

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 odlucies sem interferência humana direta. U dodatku, pogledajte video do projekcije do kraja, za ilustraciju, ili kao osnove za aktiviranje bez Androida.

Preporučuje se: