Indholdsfortegnelse:

SmartBin: 8 trin
SmartBin: 8 trin

Video: SmartBin: 8 trin

Video: SmartBin: 8 trin
Video: REVIEW: Xiaomi Mi Band 8 Smart Band - Full Walkthrough - BEST Budget Fitness Tracker Again? 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, 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
  • Sensor Ultrassônico de Distancia
  • Caixa de papelão
  • Protoboard
  • Caboer
  • Dispositivo Android

Trin 1: Conectando O -sensor

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

// definerer pins numre #definer pino_trigger 2 // D4

#define pino_echo 0 // D3

For at få vist, hvad der skal gøres til sensor, kan du se en vejledning til udarbejdelse af FilipeFlop, disponível aqui.

flyde cmMsec, inMsec;

lang mikrosek = ultralyd.timing ();

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

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

// Exibe informerer ingen seriel skærm

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

Serial.print (cmMsec);

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

Serial.println (inMsec);

Strengdata = String (cmMsec);

Serial.println (data);

Trin 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Præcisaremos conectar o sensor ultrassônico no “teto” da lixeira. Som eksempel kan du bruge cabo e fita isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. Ingen 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 = tilfældig (1, 5);

}

Trin 3: Upload Para a Nuvem

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

For at kontekst og aplicação com ThingSpeak, er det nødvendigt at bruge eller bruge API til 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 identificador e a senha de sua rede).

void connectWifi () {

Serial.print ("Opretter forbindelse til"+ *ssid);

WiFi. Begynd (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 ());

}

Varighed af opsætning, kan også bruges sammen med en løsning.

ugyldig opsætning () {

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

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

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

String postStr = apiKey;

postStr += "& felt";

postStr += id;

postStr += "=";

postStr += String (cmMsec);

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

Serial.println (postStr);

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

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

client.print ("Forbindelse: tæt / n");

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

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

client.print ("Indholdslængde:");

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.

Trin 4: Recuperando Dados Do ThingSpeak

O ThingSpeak tillader efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Som 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: numero do seu -kanal
  • FIELD_NUMBER: o número do campo
  • API_KEY: en chave de API do seu -kanal

Esta er en URL, der kan bruges til Android, til genbrug af ting fra ThingSpeak.

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

Til brug for Google Maps, kan du også bruge Google til at chave. Vi kan ikke beskrive noget link Obser chave de API.

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

API-nøglen til Google Maps-baserede API'er er defineret som en strengressource.

(Se filen "res/værdier/google_maps_api.xml").

Bemærk, at API -nøglen er knyttet til den krypteringsnøgle, der bruges til at signere APK. Du skal bruge en anden API -nøgle til hver krypteringsnøgle, inklusive udgivelsesnøglen, der bruges til at signere APK'en til udgivelse. Du kan definere nøglerne til fejlfindings- og frigivelsesmålene i src/debug/og src/release/.

<meta-data

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

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

En konfiguration, der fuldstændigt kan bruges til AndroidManifest anexado ao projeto.

n

Trin 6: Recuperando O Feed Ingen Android

På hoveddel ingen Android, MainActivity, crie 4 varianter til identifikation af ting, der kan gø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";

For at få vist flere oplysninger, kan du også bruge en klasse til Android, herunder 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, String method, Map params) {

prøve {

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 ()); }} hvis (builder.build (). getEncodedQuery ()! = null) {encodedParams = builder.build (). getEncodedQuery ();

}

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

} andet {

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

// Parse svaret

mens ((line = reader.readLine ())! = null) {sb.append (linje + "\ n"); } er.close (); json = sb.toString (); // Konverter svaret til JSON Object jObj = nyt JSONObject (json);

} fangst (UnsupportedEncodingException e) {

e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Fejl ved parsing af data" + e.toString ()); } catch (Undtagelse e) {Log.e ("Undtagelse", "Fejl ved parsing af data" + e.toString ()); }

// returner JSON Object

vende tilbage 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 streng doInBackground (streng … params) {HttpJsonParser jsonParser = ny 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, o control de execução to Android passa para o método onPostExecute. Neste método, vamos criar os objetos Lixeira, e popular com os dados recuperados do ThingSpeak:

beskyttet void onPostExecute (resultat af streng) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {

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

Vis 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 -lommeregner = ny SmartBinService (); lommeregner.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);

} fang (JSONException e) {

e.printStackTrace (); }

} andet {

Toast.makeText (MainActivity.this, "Nogle fejl opstod under indlæsning af data", Toast. LENGTH_LONG).show ();

}

} }); }

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

Trin 7: Mostrando No Mapa

Mostrando No Mapa
Mostrando No Mapa

Ainda na atividade principal, vi kan også fortælle, at det er muligt at genkende Mapa, og det er officielt.

/ ** Opkaldes, når brugeren 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 (bundt);

startActivity (intention);

}

Ingen mapa, temos três atividades en eksekutør:

  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

Til udførelse af passos acima, kan vi også bruge en API Google Directions. Para desenhar as rotas, foram seguidos os passos do tutorial Tegning af kørselsvejledning mellem to steder ved hjælp af Google Rutevejledning i Google Map Android API V2

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

//Placeringer

privat LatLng nuværende;

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 () {// Kontrollerer, om brugeren har givet tilladelsen, hvis (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Anmodning om tilladelse til placering ActivityCompat.requestPermissions (denne, nye streng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Vend tilbage; }

// Henter den sidste kendte placering ved hjælp af Fus

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

// MarkerOptions bruges til at oprette en ny Marker. Du kan angive placering, titel osv. Med MarkerOptions

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

// Tilføjelse af den oprettede markør på kortet, flytte kameraet til position

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

// Flyt kameraet øjeblikkeligt til placeringen med en zoom på 15.

mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (nuværende, 15));

// Zoom ind, animér kameraet.

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

}

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

private void addBinALocation () {// Kontrollerer, om brugeren har givet tilladelsen, hvis (ActivityCompat.checkSelfPermission (dette, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (denne, android.per.mission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Anmodning om tilladelse til placering ActivityCompat.requestPermissions (denne, nye streng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Vend tilbage; }

// Praça da Estação

dobbelt breddegrad = -19,9159578; dobbelt længdegrad = -43,9387856; this.lixeiraA = ny LatLng (breddegrad, længdegrad);

MarkerOptions markerOptions = new MarkerOptions (). Position (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 (f.eks. 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 os Waypoints!

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

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

// Rutens oprindelse

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

// Destination af rute

String str_dest = "destination ="+dest.breddegrad+","+dest.længdegrad;

// Waypoints 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 aktiveret

Stringsensor = "sensor = falsk";

// Opbygning af parametrene til webtjenesten

Stringparametre = str_origin+"&"+str_dest+"&"+sensor+"&"+waypoints;

// Outputformat

String output = "json";

// Opbygning af url til webtjenesten

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

return 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

// Hent URL til Google Directions API

Listepunkter = ny ArrayList (); point.add (lixeiraB); point.add (lixeiraC); point.add (lixeiraD);

String url = getDirectionsUrl (nuværende, lixeiraA, point);

DownloadTask downloadTask = ny DownloadTask (); // Start med at downloade 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.

Trin 8: Konklusion

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, se om videoklip til fuldstændige, para ilustração, og os skrifttyper das atividades criadas ingen Android.

Anbefalede: