Innehållsförteckning:

SmartBin: 8 steg
SmartBin: 8 steg

Video: SmartBin: 8 steg

Video: SmartBin: 8 steg
Video: Xiaomi Smart Band 8 (M2239B1) | Обзор и распаковка | Это лучший гаджет 2023 года | NOWADAYS 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, é needsário:

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

Steg 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:

// definierar pin -nummer #definiera 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.

flyta cmMsec, inMsec;

lång mikrosek = ultraljud.timing ();

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

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

// Exibe informacoes no serial monitor

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

Serial.print (cmMsec);

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

Serial.println (inMsec);

Strängdata = String (cmMsec);

Serial.println (data);

Steg 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no “teto” da lixeira. Exemplo, utilizei um cabo e fita isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. Inget 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

lång lixeiraID;

void loop () {

lixeiraID = slumpmässigt (1, 5);

}

Steg 3: Ladda upp 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 of ThingSpeak, é needsário salvar of número da API do canal criado. Siga os passos descritos ingen webbplats 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 ("Ansluter till"+ *ssid);

WiFi. Börjar (ssid, pass);

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

fördröjning (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 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 /uppdatera HTTP /1.1 / n");

client.print ("Värd: api.thingspeak.com / n");

client.print ("Anslutning: stäng / 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);

fördröjning (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 para identifierar para qual campo será feito o ladda upp valor lido.

Steg 4: Recuperando Dados Do ThingSpeak

O ThingSpeak tillåter 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 ingen länk informado previamente. Os mais importantes para o projeto são:

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

Det finns en webbadress som kan användas för Android, för att återhämta oss från ThingSpeak.

Steg 5: Criando och Aplicação Android

Ingen Android Studio, crie um novo projeto Android. Para o correto funcionamento da aplicação, é needsário configurar as permissões abaixo no AndroidManifest.

Para utilizar o Google Maps, será needsário pegar uma chave junto ao Google. Vi kan inte skriva några länkar Observera att API.

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

API-nyckeln för Google Maps-baserade API: er definieras som en strängresurs.

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

Observera att API -nyckeln är länkad till krypteringsnyckeln som används för att signera APK. Du behöver en annan API -nyckel för varje krypteringsnyckel, inklusive releasenyckeln som används för att signera APK för publicering. Du kan definiera nycklarna för felsöknings- och släppmålen i src/debug/och src/release/.

<metadata

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

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

En konfiguration som är komplett för AndroidManifest anexado ao projeto.

n

Steg 6: Recuperando O Feed Ingen Android

Na atividade principal no Android, MainActivity, crie 4 variáveis fora identifierar cada um dos canais do Thing Speak a serem lidos:

privat String url_a = "https://api.thingspeak.com/channels/429823/fields/1/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; privat String url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; privat String url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; privat 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 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 or objeto JSON montado.

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

Prova {

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

} annat {

urlObj = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metod); urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). write (encodedParams.getBytes ()); } // Anslut till servern urlConnection.connect (); // Läs svaret är = urlConnection.getInputStream (); BufferedReader reader = new BufferedReader (new InputStreamReader (is)); StringBuilder sb = new StringBuilder (); Stränglinje;

// Analysera svaret

medan ((line = reader.readLine ())! = null) {sb.append (rad + "\ n"); } är nära(); json = sb.toString (); // Konvertera svaret till JSON Object jObj = nytt JSONObject (json);

} catch (UnsupportedEncodingException e) {

e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Error parsing data" + e.toString ()); } catch (Undantag e) {Log.e ("Undantag", "Fel vid analys av data" + e.toString ()); }

// return JSON Object

återvända 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 skyddad 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);

returnera 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 os dados recuperados do ThingSpeak:

skyddad void onPostExecute (strängresultat) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {

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

Visa mainView = (Visa) 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 -räknare = ny SmartBinService (); calculator.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 = nytt SimpleDateFormat ("dd/MM/åååå"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adapter);

} fånga (JSONException e) {

e.printStackTrace (); }

} annat {

Toast.makeText (MainActivity.this, "Ett fel uppstod när data laddades", Toast. LENGTH_LONG).show ();

}

} }); }

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

Steg 7: Mostrando No Mapa

Mostrando No Mapa
Mostrando No Mapa

Ainda na atividade principal, vi kan också ta reda på om det är möjligt att göra en karta, men inte officiellt.

/ ** Kallas när användaren trycker på Mapa -knappen*/ public void openMaps (View view) {Intent intention = new Intent (this, LixeiraMapsActivity.class);

// Passa a lista de lixeiras

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

startActivity (intention);

}

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

För att utföra våra lösenord kan vi använda API: s Google Directions. Para desenhar as rotas, foram seguidos os passos do to tutorial Rita körvägsanvisningar mellan två platser med Google Directions i Google Map Android API V2

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

// Platser

privat LatLng ström;

privat LatLng lixeiraA; privat LatLng lixeiraB; privat LatLng lixeiraC; privat LatLng lixeiraD;.

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

private void checkLocationandAddToMap () {// Kontrollerar om användaren har beviljat tillståndet om (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (Android. Manifest.permission. ACCESS_FINE_LOCATION)! ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Begär platstillstånd ActivityCompat.requestPermissions (denna, nya sträng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); lämna tillbaka; }

// Hämtar den senaste kända platsen med Fus

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

// MarkerOptions används för att skapa en ny markör. Du kan ange plats, titel etc. med MarkerOptions

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

// Lägga till den skapade markören på kartan, flytta kameran till position

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

// Flytta kameran direkt till platsen med en zoom på 15.

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

// Zooma in, animera kameran.

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

}

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

private void addBinALocation () {// Kontrollerar om användaren har beviljat tillståndet om (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (denna, android. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Begär platstillstånd ActivityCompat.requestPermissions (denna, nya sträng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); lämna tillbaka; }

// Praça da Estação

dubbel latitud = -19,9159578; dubbel longitud = -43,9387856; this.lixeiraA = ny LatLng (latitud, longitud);

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 (exemplo 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 next projeto, uso Waypoints!

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

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

// Ruttens ursprung

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

// Destination av rutt

String str_dest = "destination ="+dest.latitud+","+dest.longitud;

// Waypoints längs rutten

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

// Sensor aktiverad

Strängsensor = "sensor = falsk";

// Bygga parametrarna till webbtjänsten

Strängparametrar = str_origin+"&"+str_dest+"&"+sensor+"&"+waypoints;

// Utmatningsformat

Strängutgång = "json";

// Bygga webbadressen till webbtjänsten

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

retururl;

}

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

// Rita rutter

// Få URL till Google Directions API

Listpunkter = ny ArrayList (); poäng.add (lixeiraB); poäng.add (lixeiraC); poäng.add (lixeiraD);

String url = getDirectionsUrl (aktuell, lixeiraA, poäng);

DownloadTask downloadTask = new DownloadTask (); // Börja ladda ner json -data från Google Directions API downloadTask.execute (url); }

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

Steg 8: Slutsats

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, para ilustração, e os fontes das atividades criadas no Android.

Rekommenderad: