Բովանդակություն:

SmartBin: 8 քայլ
SmartBin: 8 քայլ

Video: SmartBin: 8 քայլ

Video: SmartBin: 8 քայլ
Video: Первый обзор Mi Band 8 — лучший Band в истории! 2024, Նոյեմբեր
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 informacões recuperadas.

Para montar este projeto, անհրաժեշտ անհրաժեշտություն:

  • NodeMCU
  • Սենսոր Ultrassônico de Distancia
  • Caixa de papelão
  • Նախատախտակ
  • Կաբոս
  • Dispositivo Android

Քայլ 1: Conectando O ցուցիչ

Primeiramente, vamos efetuar a conexão entre o sensor ultrassônico e o NODEMCU. Բացի այդ, vamos conectar as portas trigger echo do sensor nas portas D4 e D3 do NodeMCU:

// սահմանում է կապում համարները #սահմանել pino_trigger 2 // D4

#սահմանել pino_echo 0 // D3

Որպեսզի կարողանաք զգուշություն ցուցաբերել, սովորեք կամ սովորեցրեք մանրամասն ուսումնասիրել FilipeFlop- ը, բաց թողնել ջրերը:

float cmMsec, inMsec;

երկար microsec = ultrasonic.timing ();

cmMsec = ուլտրաձայնային. փոխակերպում (միկրոսեկ, Ուլտրաձայնային:: CM);

inMsec = ուլտրաձայնային. փոխակերպում (միկրոսեկ, Ուլտրաձայնային:: IN);

// Exibe տեղեկատվությունը չունի սերիական մոնիտոր

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

Serial.print (cmMsec);

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

Serial.println (inMsec);

Լարային տվյալներ = Լար (սմՄսեկ);

Serial.println (տվյալներ);

Քայլ 2: Մոնտանդո և Լիկսեյրա

Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no “teto” da lixeira. Օրինակ ՝ օգտագործել, օգտագործել կաբո և ֆիտա isolante: Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. Ոչ, me 26, 3 սմ Esse é o valor que konsiderrarmos para uma lixeira vazia.

Որպեսզի կարողանանք պարզել, թե որն է մեր ուլտրամանրաչափ սենսորը, մենք կարող ենք մեծացնել մեր հնարավորությունները 4 տարբեր հեռավորությունների հեռավորության վրա:

// Simulando 4 lixeiras

երկար lixeiraID;

դատարկ շրջան () {

lixeiraID = պատահական (1, 5);

}

Քայլ 3: Վերբեռնեք Para a Nuvem- ի համար

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por familiaridade com o mesmo. Primeiramente, é needário criar um novo canal, recebendo 4 parâmetros, referentes ao volume de cada lixeira:

Առանց կապի մի բան կիրառեք ThingSpeak- ի միջոցով, անհրաժեշտ է փրկել ձեր API- ն ջրանցքի խոչընդոտից: Siga os passos descritos no site oficial.

De volta à aplicação, vamos use 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 red (defina previamente duas variáveis, ssid e pass , contendo o identificador e a senha de sua rede):

void connectWifi () {

Serial.print ("Միացում"+ *ssid);

WiFi.begin (ssid, pass);

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

ուշացում (500);

Serial.print (".");

}

Serial.println ("");

Serial.print («Conectado na rede»);

Serial.println (ssid);

Serial.print ("IP:");

Serial.println (WiFi.localIP ());

}

Հաստատում կամ տեղադրում, վճռականություն է ձեռք բերում և հարմարեցում է գնումներին:

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, երկար id) {

if (client.connect (սերվեր, 80)) {

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

Լարային postStr = apiKey;

postStr += "& դաշտ";

postStr += id;

postStr += "=";

postStr += լարային (cmMsec);

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

Serial.println (postStr);

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

client.print ("Հաղորդավար` api.thingspeak.com / n ");

client.print ("Միացում. փակել / n");

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

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

client.print ("Բովանդակություն-երկարություն.");

client.print (postStr.length ());

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

client.print (postStr);

ուշացում (1000);

}

client.stop ();

}

O Primeiro parâmetro համապատասխանի à 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 ծառայել também para identificar para qual campo será feito o upload to valor lido.

Քայլ 4. Recuperando Dados Do ThingSpeak

O ThingSpeak permite efetuar leitura dos dados do seu ջրանցք, 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 ջրանցք
  • FIELD_NUMBER: o número do campo
  • API_KEY: chave de API do seu ջրանցք

Ստացեք URL, որը թույլ է տալիս օգտագործել Android- ը, այն վերականգնելու համար ThingSpeak- ը:

Քայլ 5: Criando and Aplicação Android

Android Studio չկա, Android- ի նոր տարբերակ: Կիրառական գործառույթների կիրառման համար անհրաժեշտ է կարգավորել այնպես, ինչպես թույլատրվում է AndroidManifest- ի միջոցով:

Google Քարտեզների օգտագործման համար անհրաժեշտ է օգտագործել 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:

Google Քարտեզների վրա հիմնված API- ների API բանալին սահմանվում է որպես լարային ռեսուրս:

(Տես «res/values/google_maps_api.xml» ֆայլը):

Նկատի ունեցեք, որ API բանալին կապված է APK- ի ստորագրման համար օգտագործվող ծածկագրման բանալին: Ձեզ անհրաժեշտ է մեկ այլ API բանալին յուրաքանչյուր ծածկագրման բանալու համար, ներառյալ թողարկման բանալին, որն օգտագործվում է հրապարակման համար APK- ի ստորագրման համար: Դուք կարող եք կարգաբերել և ազատել թիրախների բանալիները src/debug/և src/release/:

<մետատվյալներ

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

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

Ամբողջական կազմաձևումն այն է, ինչ նախատեսված է AndroidManifest- ի արագացման կամ նախագծման համար:

n

Քայլ 6. Recuperando O Feed No Android

Na atividade principal no Android, MainActivity, crie 4 variáveis para identicalar 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"; 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";

Որպեսզի կարողանաք օգտվել ձեր համակարգչից, օգտագործեք ևս մի քանի տարբերակ ՝ օգտագործելով Android հատուկ, 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. Ստանալ classe será responsável for abrir uma conexão com um URL, efetuar leitura dos dados encontrados, e retornar or objeto JSON montado.

հանրային JSONObject makeHttpRequest (Լարային url, String մեթոդ, Քարտեզի պարամետրեր) {

փորձիր {

Uri. Builder builder = նոր 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».հավասար (մեթոդ)) {url = url + "?" + կոդավորված պարամետրեր; urlObj = նոր URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (մեթոդ);

} ուրիշ {

urlObj = նոր URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (մեթոդ); urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty («Բովանդակություն-երկարություն», String.valueOf (encodedParams.getBytes (). երկարություն)); urlConnection.getOutputStream (). գրել (encodedParams.getBytes ()); } // Միացեք urlConnection.connect սերվերին (); // Կարդալ պատասխանը = urlConnection.getInputStream (); BufferedReader reader = նոր BufferedReader (նոր InputStreamReader (է)); StringBuilder sb = նոր StringBuilder (); Լարային գիծ;

// Վերլուծել պատասխանը

while ((line = reader.readLine ())! = null) {sb.append (տող + "\ n"); } is.close (); json = sb.toString (); // Պատասխանը փոխակերպել JSON օբյեկտի jObj = նոր JSONObject (json);

} բռնել (UnsupportedEncodingException ե) {

e.printStackTrace (); } catch (ProtocolException ե) {e.printStackTrace (); } բռնել (IOException ե) {e.printStackTrace (); } catch (JSONException ե) {Log.e («JSON վերլուծիչ», «Տվյալների վերլուծության սխալ» + e.toString ()); } catch (բացառություն ե) {Log.e («Բացառություն», «Տվյալների վերլուծության սխալ» + e.toString ()); }

// վերադարձ JSON օբյեկտը

վերադարձ 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 պաշտպանված String doInBackground (Լարային… պարամետրեր) {HttpJsonParser jsonParser = new HttpJsonParser ();

respondLixeiraA = jsonParser.makeHttpRequest (url_a, "GET", null);

respondLixeiraB = jsonParser.makeHttpRequest (url_b, "GET", null); respondLixeiraC = jsonParser.makeHttpRequest (url_c, "GET", null); respondLixeiraD = jsonParser.makeHttpRequest (url_d, "GET", null);

վերադարձ null;}

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

պաշտպանված դատարկություն onPostExecute (Լարային արդյունք) {pDialog.dismiss (); runOnUiThread (նոր Runnable () {հրապարակային դատարկ վազք () {

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

Դիտել mainView = (Դիտել) findViewById (R.id.activity_main); if (success == 1) {try {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira (); Lixeira feedDetails2 = նոր Lixeira (); Lixeira feedDetails3 = նոր Lixeira (); Lixeira feedDetails4 = նոր Lixeira ();

feedDetails1.setId ('A');

feedDetails1.setPesoLixo (Double.parseDouble (respondLixeiraA.getString (KEY_FIELD1)))); feedDetails1.setVolumeLixo (Double.parseDouble (respondLixeiraA.getString (KEY_FIELD1))));

feedDetails2.setId ('B');

feedDetails2.setPesoLixo (Double.parseDouble (respondLixeiraB.getString (KEY_FIELD2)))); feedDetails2.setVolumeLixo (Double.parseDouble (respondLixeiraB.getString (KEY_FIELD2))));

feedDetails3.setId ('C');

feedDetails3.setPesoLixo (Double.parseDouble (respondLixeiraC.getString (KEY_FIELD3)))); feedDetails3.setVolumeLixo (Double.parseDouble (respondLixeiraC.getString (KEY_FIELD3))));

feedDetails4.setId ('D');

feedDetails4.setPesoLixo (Double.parseDouble (respondLixeiraD.getString (KEY_FIELD4)))); feedDetails4.setVolumeLixo (Double.parseDouble (respondLixeiraD.getString (KEY_FIELD4))));

feedList.add (feedDetails1);

feedList.add (feedDetails2); feedList.add (feedDetails3); feedList.add (feedDetails4);

// Calcula dados das lixeiras

SmartBinService հաշվիչ = նոր SmartBinService (); calculator.montaListaLixeiras (feedList);

// Recupera բաղադրիչներ

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

// Ատուալ տվյալներ

Ամսաթիվ currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = նոր SimpleDateFormat («օր/օր/տարի»); Լարային currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (ադապտեր);

} բռնել (JSONException ե) {

e.printStackTrace (); }

} ուրիշ {

Toast.makeText (MainActivity.this, «Տվյալների բեռնման ընթացքում տեղի է ունեցել որոշակի սխալ», Toast. LENGTH_LONG). Ցուցադրել ();

}

} }); }

Agora, na tela inicial do aplicativo, ser listo listados os dados de cada lixeira:

Քայլ 7: Mostrando No Mapa

Mostrando No Mapa
Mostrando No Mapa

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

/ ** ledանգահարվում է, երբ օգտվողը հպում է Mapa կոճակին*/ public void openMaps (Դիտել տեսքը) {Intent purpose = new Intent (this, LixeiraMapsActivity.class);

// Passa a lista de lixeiras

Bundle bundle = new Bundle (); bundle.putParcelableArrayList («lixeiras», feedList); purpose.putExtras (փաթեթ);

startActivity (մտադրություն);

}

No mapa, temos três atividades a execar:

  1. marcar a posição atual do caminha de lixo
  2. marcar os pontos- ը թղթակցում է cada lixeira no mapa- ին
  3. traçar a rota entre os pontos

Օգտագործեք os passos acima, vamos օգտագործեք API Google Directions- ը: Որպեսզի իմանաք, թե ինչպես կարելի է սովորել ուղեցույցի գծեր գծել երկու վայրերի միջև ՝ օգտագործելով Google Directions- ը Google Map- ում Android API V2

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

// Տեղադրություններ

մասնավոր LatLng ընթացիկ;

մասնավոր LatLng lixeiraA; մասնավոր LatLng lixeiraB; մասնավոր LatLng lixeiraC; մասնավոր LatLng lixeiraD;.

Նախքան որևէ պաշտոնական քարտեզ չընդունելը, fri criado o método:

private void checkLocationandAddToMap () {// Ստուգում, արդյոք օգտագործողը թույլտվություն է տվել, եթե (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelf ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Տեղադրման թույլտվության հայցում ActivityCompat.request Թույլտվություններ (սա, նոր տող {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); վերադարձ; }

// Fus- ի միջոցով ստանալ վերջին հայտնի վայրը

Տեղադրության վայրը = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);

// MarkerOptions- ը օգտագործվում է նոր նշիչ ստեղծելու համար: MarkerOptions- ով կարող եք նշել գտնվելու վայրը, վերնագիրը և այլն:

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

// Ստեղծված նշիչը քարտեզի վրա ավելացնելը, տեսախցիկը տեղափոխելով դիրք

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

// Տեղափոխեք տեսախցիկը անմիջապես 15 վայրկյան խոշորացումով:

mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (ընթացիկ, 15));

// Մեծացրեք ՝ տեսախցիկը կենդանացնելով:

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

}

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

private void addBinALocation () {// Ստուգում, արդյոք օգտագործողը թույլտվություն է տվել, եթե (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (this, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Տեղադրման թույլտվության հայցում ActivityCompat.request Թույլտվություններ (սա, նոր տող {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); վերադարձ; }

// Praça da Estação

երկակի լայնություն = -19.9159578; կրկնակի երկայնություն = -43.9387856; this.lixeiraA = նոր LatLng (լայնություն, երկայնություն);

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

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

Լայնության և երկայնության սահմանները կարող են օգտագործվել Google Քարտեզների վերականգնման համար, և դրանք չեն շտկվում: 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, and 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 ծագում, LatLng dest, List waypointsList) {

// Երթուղու ծագումը

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

// Երթուղու նպատակակետ

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

// Երթուղու երկայնքով ճանապարհային կետեր

//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; for (LatLng point: waypointsList) {waypoints += "|" + կետ. լայնություն + "," + կետ. երկարություն; }

// Սենսորը միացված է

Լարերի ցուցիչ = "ցուցիչ = կեղծ";

// Վեբ ծառայության պարամետրերի կառուցում

Լարային պարամետրեր = str_origin+"&"+str_dest+"&"+sensor+"&"+waypoints;

// Ելքի ձևաչափ

Լարային ելք = "json";

// Վեբ ծառայության url կառուցում

Լարային url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+ պարամետրեր; System.out.println ("+++++++++++++++"+url);

վերադարձի հասցե;

}

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

// Նկարեք երթուղիներ

// Google ուղղությունների API- ի URL- ի ստացում

Pointsանկի կետեր = նոր ArrayList (); միավորներ ավելացնել (lixeiraB); միավորներ ավելացնել (lixeiraC); միավորներ ավելացնել (lixeiraD);

Լարային url = getDirectionsUrl (ընթացիկ, lixeiraA, միավոր);

DownloadTask downloadTask = նոր DownloadTask (); // Սկսեք json տվյալների ներբեռնում Google Directions API downloadTask.execute (url); }

Aqui passamos apenas pelos pontos principais. Խորհրդատվության համար անհրաժեշտ է լրացնել ձեր առաջարկած ծառայությունը:

Քայլ 8: Եզրակացություն

Este foi um projeto trabalhando conceitos de IoT, mostrando uma das vasrias opções de conectar dispositivos através da nuvem, and efetuar tomada de decisões sem interferência humana direta. Ավելին, մենք պետք է լրացնենք մեր տվյալները, օրինակները, եթե մենք Android- ի համար օգտագործում ենք տառատեսակներ:

Խորհուրդ ենք տալիս: