Kazalo:

SmartBin: 8 korakov
SmartBin: 8 korakov

Video: SmartBin: 8 korakov

Video: SmartBin: 8 korakov
Video: ТЕПЕРЬ НЕ ПРОПАДУ 10-ть самоделок ВЫРУЧАТ ГДЕ УГОДНО! 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 nas informações recuperadas.

Para montar este projeto, é needário:

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

Korak: Senzor Conectando O

Primeramente, vamos effecttuar 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:

// definira številke zatičev #define 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.

float cmMsec, inMsec;

dolg mikrosek = ultrazvočni čas ();

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

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

// Exibe informacoes no serijski monitor

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

Serijski.tisk (cmMsec);

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

Serial.println (inMsec);

Podatkovni niz = niz (cmMsec);

Serial.println (podatki);

2. korak: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Precisaremos conectar o ultrassônico senzor brez "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 simulacijo, visto que não possuo mais de um senzor ultrassônico, foi feito um algoritmo para salvar randomicamente in distancia lida em 4 lixeiras diferentes.

// Simulando 4 lixeiras

dolga lixeiraID;

void loop () {

lixeiraID = naključno (1, 5);

}

Korak: Naložite Para a Nuvem

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por familiaridade com o mesmo. Primeiramente, é neophodário criar um novo channel, recebendo 4 parâmetros, sklicuje se na ao volume de cada lixeira.

Pará conectar a applicação com o ThingSpeak, é needário salvar o número da API do channel criado. Siga os passos descritos no site oficial.

De volta à applicação, vamos utiralar 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 identificador e a senha de sua rede).

void connectWifi () {

Serial.print ("Povezovanje z"+ *ssid);

WiFi.begin (ssid, pass);

medtem ko (WiFi.status ()! = WL_CONNECTED) {

zamuda (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, para enviar os dados para ThingSpeak, basta abrir uma conexão HTTP padrão, passando o número da API e os parâmetros.

void sendDataTS (float cmMsec, dolg id) {

if (client.connect (strežnik, 80)) {

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

Niz postStr = apiKey;

postStr += "& polje";

postStr += id;

postStr += "=";

postStr += niz (cmMsec);

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

Serial.println (postStr);

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

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

client.print ("Povezava: zaprta / n");

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

client.print ("Vrsta vsebine: aplikacija/x-www-form-urlencoded / n");

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

client.print (postStr.length ());

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

client.print (postStr);

zamuda (1000);

}

client.stop ();

}

O primeiro parâmetro ustreza à distância em centímetros encontrada pelo senzor 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 também para identificar para qual campo será feito o upload do valor lido.

4. korak: Recuperando Dados Do ThingSpeak

O ThingSpeak dovolite efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Kot 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 naslovu URL za 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: kanal número do seu
  • FIELD_NUMBER: o številki dela
  • API_KEY: a chave de API do seu kanal

Namestite URL, ki je namenjen aplikaciji Android, za obnovitev ali uporabo ThingSpeak.

5. korak: Criando in Aplicação Android

No Android Studio, crie um novo projeto Android. Če želite popraviti funkcijo, ki jo je treba aplicirati, je potrebno konfigurirati kot dovoljenja za uporabo brez AndroidManifesta.

Če uporabljate Google Zemljevide, potrebujete nekaj časa za uporabo 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.

Ključ API za API-je, ki temeljijo na Google Zemljevidih, je opredeljen kot vir niza.

(Glejte datoteko "res/values/google_maps_api.xml").

Upoštevajte, da je ključ API povezan s šifrirnim ključem, ki se uporablja za podpis APK. Za vsak šifrirni ključ potrebujete drugačen ključ API, vključno s ključem za sprostitev, ki se uporablja za podpis APK za objavo. Ključe za cilje za odpravljanje napak in sprostitev lahko določite v src/debug/in src/release/.

<metapodatki

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

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

Konfiguracija, ki je dokončana z arkivo AndroidManifest, je anexado ao projeto.

n

6. korak: Recuperando O Feed No Android

Na glavnem glavnem mestu Androida, MainActivity, 4 različice za identifikacijo 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"; zasebni niz url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; zasebni niz url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; zasebni niz url_d = "https://api.thingspeak.com/channels/429823/fields/4/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true";

Če želite, da vaš računalnik uporablja vse, kar potrebujete, uporabite razred za Android, posebno JSONObject. Več o tem, naslov 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.

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

poskusi {

Uri. Builder builder = nov 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 (metoda)) {url = url + "?" + encodedParams; urlObj = nov URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metoda);

} drugo {

urlObj = nov 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 ()); } // Povežite se s strežnikom urlConnection.connect (); // preberite odgovor je = urlConnection.getInputStream (); BufferedReader reader = nov BufferedReader (nov InputStreamReader (je)); StringBuilder sb = nov StringBuilder (); Vrvica;

// Razčlenite odgovor

medtem ko ((vrstica = bralec.readLine ())! = nič) {sb.append (vrstica + "\ n"); } is.close (); json = sb.toString (); // Pretvorimo odgovor v Objekt JSON jObj = nov JSONObject (json);

} catch (UnsupportedEncodingException e) {

e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Napaka pri razčlenjevanju podatkov" + e.toString ()); } catch (Izjema e) {Log.e ("Izjema", "Napaka pri razčlenjevanju podatkov" + e.toString ()); }

// vrne objekt JSON

vrnitev 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 zaščiteni niz doInBackground (String… params) {HttpJsonParser jsonParser = nov HttpJsonParser ();

responseLixeiraA = jsonParser.makeHttpRequest (url_a, "GET", ničelno);

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

return null;}

Omogoča vam, da izvedete doInBackgroundé encerrado, ali nadzirate izvajanje operacijskega sistema Android za uporabo na spletnem mestu PostExecute. Neste método, vamos criar os objetos Lixeira, popularni com os dados recuperados do ThingSpeak:

zaščitena praznina onPostExecute (rezultat niza) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {

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

Ogled mainView = (Ogled) findViewById (R.id.activity_main); if (uspeh == 1) {poskusite {// 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 = nov SmartBinService (); calculator.montaListaLixeiras (feedList);

// Recupera komponente

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

// Realni podatki

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

} catch (JSONException e) {

e.printStackTrace (); }

} drugo {

Toast.makeText (MainActivity.this, "Pri nalaganju podatkov je prišlo do napake", Toast. LENGTH_LONG).show ();

}

} }); }

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

Korak 7: Mostrando brez zemljevida

Mostrando Brez zemljevida
Mostrando Brez zemljevida

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

/ ** Pokliče se, ko uporabnik pritisne gumb Mapa*/ public void openMaps (pogled Pogled) {Namen namera = nov namen (to, LixeiraMapsActivity.class);

// Passa a lista de lixeiras

Bundle bundle = new Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (sveženj);

startActivity (namen);

}

Brez zemljevida, temos três atividades a executer:

  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

Če želite izvedeti več o tem, uporabite Google API za navodila. Para desenhar as rotas, foram seguidos os passos do tutorial Risanje navodil za pot vožnje med dvema lokacijama z uporabo Google Directions v Google Map Android API V2

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

// Lokacije

zasebni tok LatLng;

zasebni LatLng lixeiraA; zasebni LatLng lixeiraB; zasebni LatLng lixeiraC; zasebni LatLng lixeiraD;.

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

private void checkLocationandAddToMap () {// Preverjanje, ali je uporabnik podelil dovoljenje if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.missionChement, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Zahtevanje dovoljenja za lokacijo ActivityCompat.requestPermissions (ta, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); vrnitev; }

// Pridobivanje zadnje znane lokacije s pomočjo Fus

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

// MarkerOptions se uporabljajo za ustvarjanje novega Markerja. Z MarkerOptions lahko določite lokacijo, naslov itd

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

// Dodajanje ustvarjenega označevalca na zemljevid, premikanje kamere v položaj

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

// Fotoaparat takoj premaknite na lokacijo s povečavo 15.

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

// Povečajte, animirajte kamero.

mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, nič);

}

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

private void addBinALocation () {// Preverjanje, ali je uporabnik podelil dovoljenje if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission this, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Zahtevanje dovoljenja za lokacijo ActivityCompat.requestPermissions (ta, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); vrnitev; }

// Praça da Estação

dvojna zemljepisna širina = -19,9159578; dvojna zemljepisna dolžina = -43.9387856; this.lixeiraA = nov LatLng (zemljepisna širina, dolžina);

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

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

Kot zemljepisna širina in dolžina de cada lixeira za recuperadas através do próprio Google Maps, e deixadas fixas no código. Idealno, estes valores ficariam salvos em um banco de dados (na primer 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 (izvor LatLng, cilj LatLng, List waypointsList) {

// Izvor poti

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

// Cilj poti

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

// Točke poti na poti

//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 Niz waypoints = "waypoints = optimize: true"; for (LatLng point: waypointsList) {waypoints += "|" + point. Latitude + "," + point. Longitude; }

// Senzor omogočen

String sensor = "sensor = false";

// Ustvarjanje parametrov spletne storitve

Parametri niza = str_origin+"&"+str_dest+"&"+senzor+"&"+točke poti;

// Izhodni format

Niz izhod = "json";

// Ustvarjanje URL -ja za spletno storitev

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

povratni url;

}

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

@Odpravite javno void na 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 (); }

// Nariši poti

// Pridobivanje URL -ja do API -ja Google Directions

Seznam točk = nov ArrayList (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);

Niz url = getDirectionsUrl (trenutni, lixeiraA, točke);

DownloadTask downloadTask = nov DownloadTask (); // Začnite nalagati podatke json iz API -ja Google Directions downloadTask.execute (url); }

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

8. korak: 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 odločões sem interferência humana direta. Em anexo, segue um vídeo do projeto completeto, para ilustração, e os fontes das atividades criadas no Android.

Priporočena: