Cuprins:
- Pasul 1: Conectarea senzorului O
- Pasul 2: Montando a Lixeira
- Pasul 3: Încărcați Para a Nuvem
- Pasul 4: Recuperarea Dados Do ThingSpeak
- Pasul 5: Criando a Aplicação Android
- Pasul 6: Recuperarea feedului O fără Android
- Pasul 7: Mostrando fără hartă
- Pasul 8: Concluzie
Video: SmartBin: 8 pași
2024 Autor: John Day | [email protected]. Modificat ultima dată: 2024-01-31 10:24
Este é um proiectat pentru un sistem inteligent de colete, nu pot fi pasionați de lixo recebem dados das lixeiras, identificând o cantitate de lixo prezentă în fiecare uma delas, e uma rota de coletă traçada, com base nas informações recuperadas.
Pentru a monta acest proiect, este necesar:
- NodeMCU
- Senzor ultrasonic de distanță
- Caixa de paperão
- Protoboard
- Cabos
- Dispozitiv Android
Pasul 1: Conectarea senzorului O
Primeiramente, vamos efetuar a conexão entre o sensor ultrassônico e o NODEMCU. Pentru atât, vom conecta ca portele declanșează și echo do sensor nas portas D4 și D3 do NodeMCU:
// definește numerele pinilor #define pino_trigger 2 // D4
#define pino_echo 0 // D3
Para efetuar a leitura dos dados do sensor, a fost urmat sau tutorial elaborat pelo FilipeFlop, disponível aqui.
float cmMsec, inMsec;
lung microsec = ultrasonic.timing ();
cmMsec = ultrasonic.convert (microsec, Ultrasonic:: CM);
inMsec = ultrasonic.convert (microsec, Ultrasonic:: IN);
// Exibe nu informează monitorul serial
Serial.print ("Distancia em cm:");
Serial.print (cmMsec);
Serial.print ("- Distancia em polegadas:");
Serial.println (inMsec);
Date șir = Șir (cmMsec);
Serial.println (date);
Pasul 2: Montando a Lixeira
Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no “teto” da lixeira. Pentru un exemplu, utilizați um cabo și fita izolant. Em urmată, avem că medir a distanței inițiale, pentru saber o valoare pentru a lixeira vazia. No meu caso, foi de 26, 3cm. Esse é o valor care considerarmos pentru uma lixeira vazia.
Para simulação, visto que não possuo mais de um sensor ultrassônico, a fost făcut um algoritm pentru a salva aleatoriu la distanță lida em 4 lixeiras diferite.
// Simulando 4 lixeiras
lung lixeiraID;
bucla nulă () {
lixeiraID = aleatoriu (1, 5);
}
Pasul 3: Încărcați Para a Nuvem
Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por familiaritate com chiar. Primeiramente, este necesar un criar um novo canal, recebendo 4 parametri, referințe la volumul de fiecare lixeira.
Se conectează la aplicație cu ThingSpeak, este necesar să se salveze numărul de API de canal criado. Siga os passos descritos no site oficial.
De volta à aplicação, vamos use a biblioteca ESP8266WiFi.h for efetuar connection with o ThingSpeak, and transferir os dados.
Primeiramente, uma funcționare pentru a efectua conexiuni com a rede (defina anterior duas variáveis, ssid e pass , contendo o identificador e a senha de sua rede).
void connectWifi () {
Serial.print ("Conectarea la" + * ssid);
WiFi.begin (ssid, pass);
while (WiFi.status ()! = WL_CONNECTED) {
întârziere (500);
Serial.print (".");
}
Serial.println ("");
Serial.print ("Conectado na rede");
Serial.println (ssid);
Serial.print ("IP:");
Serial.println (WiFi.localIP ());
}
În timpul configurării, încercăm să conectăm o conexiune cu un red.
configurare nulă () {
Serial.begin (9600);
Serial.println ("Lendo dados do sensor …");
// Conectarea ao Wi-Fi
connectWifi ();
}
E, pentru a trimite date pentru o ThingSpeak, basta deschide o conexiune HTTP padrão, trecând numărul de API și parametrii.
void sendDataTS (float cmMsec, id lung) {
if (client.connect (server, 80)) {
Serial.println ("Enviando dados para o ThingSpeak");
String postStr = apiKey;
postStr + = "& câmp";
postStr + = id;
postStr + = "=";
postStr + = String (cmMsec);
postStr + = "\ r / n / r / n";
Serial.println (postStr);
client.print ("POST / actualizare HTTP / 1.1 / n");
client.print ("Gazdă: api.thingspeak.com / n");
client.print ("Conexiune: închidere / n");
client.print ("X-THINGSPEAKAPIKEY:" + apiKey + "\ n");
client.print ("Content-Type: application / x-www-form-urlencoded / n");
client.print („Lungime conținut:”);
client.print (postStr.length ());
client.print ("\ n / n");
client.print (postStr);
întârziere (1000);
}
client.stop ();
}
O primul parametru corespunde distanței cu centimetri găsit cu senzor ultrasonic. O al doilea parametru este o ID da lixeira care a fost lida (care a fost gerat aleatoriu, un număr de 1 la 4).
O ID da lixeira serve alsom for identificar for qual field will done o upload do valor lido.
Pasul 4: Recuperarea Dados Do ThingSpeak
O ThingSpeak permite efetuar leitura dos dados do seu canal, através de um serviço returnando um JSON. As diferite opțiuni pentru leitura do feed do seu canal estão descritas aqui:
www.mathworks.com/help/thingspeak/get-a-ch…
În acest proiect, optou-se por ler diretamente os dados de cada campo. O pagină de URL pentru acest cenário este:
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 important for o projecteto são:
- CHANNEL_ID: numărul do seu canal
- FIELD_NUMBER: o numărul do campo
- API_KEY: a chave de API do seu canal
Aceasta este o adresă URL care va fi aplicată pentru Android, pentru a recupera dosarele ThingSpeak.
Pasul 5: Criando a Aplicação Android
Nu există Android Studio, creează un proiect nou pentru Android. Pentru funcționarea corectă a aplicației, este necesar să configurați permisiunea abaixo în AndroidManifest.
Pentru a utiliza Google Maps, va fi necesar să vă conectați la Google. Siga os passos descritos no link Obter chave de API.
Uma vez com a chave, você deve alsom configurá-la na aplicação.
Cheia API pentru API-urile bazate pe Google Maps este definită ca o resursă șir.
(A se vedea fișierul „res / values / google_maps_api.xml”).
Rețineți că cheia API este legată de cheia de criptare utilizată pentru semnarea APK-ului. Aveți nevoie de o altă cheie API pentru fiecare cheie de criptare, inclusiv cheia de lansare utilizată pentru semnarea APK-ului pentru publicare. Puteți defini cheile pentru țintele de depanare și de lansare în src / debug / și src / release /.
<meta-date
android: name = "com.google.android.geo. API_KEY"
android: value = "@ string / google_maps_key" />
O configurare completă este mo arquivo AndroidManifest anexado ao projeto.
n
Pasul 6: Recuperarea feedului O fără Android
Na atividade principal no Android, MainActivity, crie 4 variáveis pentru a identifica fiecare 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";
Para efetuar a leitura dos dados, iremos use uma class do Android specific, chamada JSONObject. Mai multe ori, vamos criar um obiect pentru fiecare URL:
JSONObject responseLixeiraA; JSONObject responseLixeiraB; JSONObject responseLixeiraC; JSONObject responseLixeiraD;
Pentru a deschide o conexiune com as urls, vamos use criar uma class auxiliar, chamada HttpJsonParser. Această clasă va fi responsabilă pentru a deschide o conexiune cu un URL, efectua leitura dos dados encontrados, e returnar o object JSON montado.
public JSONObject makeHttpRequest (String url, String method, Map params) {
încerca {
Uri. Builder builder = nou 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 = URL nou (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metodă);
} altceva {
urlObj = URL nou (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 ()); } // Conectați-vă la server urlConnection.connect (); // Citiți răspunsul este = urlConnection.getInputStream (); Cititor BufferedReader = nou BufferedReader (nou InputStreamReader (este)); StringBuilder sb = new StringBuilder (); Linia de corzi;
// Analizați răspunsul
while ((line = reader.readLine ())! = null) {sb.append (line + "\ n"); } este aproape(); json = sb.toString (); // Convertiți răspunsul în obiect JSON jObj = new 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 (Exception e) {Log.e ("Exception", "Error parsing data" + e.toString ()); }
// returnează obiectul JSON
retur jObj;
}
}
De volta a atividade principal, vamos efetuar a chamada às urls de forma assíncrona, escrevendo this code inside do method doInBackground.
@Override protejat String doInBackground (String … params) {HttpJsonParser jsonParser = new HttpJsonParser ();
responseLixeiraA = jsonParser.makeHttpRequest (url_a, "GET", nul);
responseLixeiraB = jsonParser.makeHttpRequest (url_b, "GET", nul); responseLixeiraC = jsonParser.makeHttpRequest (url_c, "GET", nul); responseLixeiraD = jsonParser.makeHttpRequest (url_d, "GET", nul);
return nul;}
Când o metodă doInBackgroundé încearcă, sau controlul de execuție pe Android trece pentru o metodă onPostExecute. În această metodă, putem crea obiecte Lixeira, și popularele noastre sunt recuperate de ThingSpeak:
void protejat onPostExecute (rezultat șir) {pDialog.dismiss (); runOnUiThread (nou Runnable () {public void run () {
// ListView listView = (ListView) findViewById (R.id.feedList);
Vizualizare mainView = (Vizualizare) findViewById (R.id.activity_main); if (success == 1) {try {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira (); Lixeira feedDetails2 = new Lixeira (); Lixeira feedDetails3 = new Lixeira (); Lixeira feedDetails4 = new 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
Calculator SmartBinService = nou SmartBinService (); calculator.montaListaLixeiras (feedList);
// Recupera componente
TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll (feedList);
// Date atuale
Data currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = nou SimpleDateFormat ("zz / LL / aaaa"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adaptor);
} catch (JSONException e) {
e.printStackTrace (); }
} altceva {
Toast.makeText (MainActivity.this, "A apărut o eroare la încărcarea datelor", Toast. LENGTH_LONG).show ();
}
} }); }
Agora, na tela initial do applicativo, serão listados os dados de cada lixeira.
Pasul 7: Mostrando fără hartă
Ainda na atividade principal, vamos adicionar uma ação a ser related to botão Mapa, na tela initial.
/ ** Apelat când utilizatorul atinge butonul Mapa * / public void openMaps (Vizualizare vizualizare) {Intent intent = new Intent (aceasta, LixeiraMapsActivity.class);
// Passa a lista de lixeiras
Bundle bundle = pachet nou (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (pachet);
startActivity (intenție);
}
No map, avem três atividades to executar:
- marcar a posição atual do caminha de lixo
- marcar os pontos corespondente a fiecare lixeira no mapa
- traçar a rota între os pontos
Pentru a executa pasul acima, folosim un API Google Directions. Pentru a dezvolta ca roti, foram urmăriți și treceți tutorial Desenarea direcțiilor rutei de conducere între două locații folosind Direcțiile Google în Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
// Locații
curent LatLng privat;
private LatLng lixeiraA; private LatLng lixeiraB; private LatLng lixeiraC; private LatLng lixeiraD;.
Pentru a adăuga o poziție actuală pe o hartă, a fost criat sau metodă:
private void checkLocationandAddToMap () {// Verificarea dacă utilizatorul a acordat permisiunea dacă (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (this, android. Manifest) ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Solicitarea permisiunii de localizare ActivityCompat.requestPermissions (acest nou șir {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); întoarcere; }
// Preluarea ultimei locații cunoscute folosind Fus
Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);
// MarkerOptions sunt folosite pentru a crea un nou Marker. Puteți specifica locația, titlul etc. cu MarkerOptions
this.current = new LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = new MarkerOptions (). Position (current).title ("Posição atual");
// Adăugarea marcatorului creat pe hartă, mutarea camerei în poziție
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("++++++++++++++ Passei aqui! ++++++++++++++"); mMap.addMarker (markerOptions);
// Mutați camera instantaneu în locație cu un zoom de 15.
mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (curent, 15));
// Măriți, animând camera.
mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, nul);
}
Em urmat, pentru fiecare lixeira, foram criados métodos similar ao abaixo:
private void addBinALocation () {// Verificarea dacă utilizatorul a acordat permisiunea dacă (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Solicitarea permisiunii de localizare ActivityCompat.requestPermissions (acest nou șir {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); întoarcere; }
// Praça da Estação
latitudine dublă = -19.9159578; longitudine dublă = -43.9387856; this.lixeiraA = LatLng nou (latitudine, longitudine);
MarkerOptions markerOptions = new MarkerOptions (). Poziție (lixeiraA).title ("Lixeira A");
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_RED)); mMap.addMarker (markerOptions); }
As posições de latitude e longitude de cada lixeira foram recuperated através do próprio Google Maps, e deixadas fixas no code. În mod ideal, aceste valori sunt salvate cu un banc de date (de exemplu Firebase). A fost prima evoluție a acestui proiect!
O último passo agora é traçar as rotas entre os pontos. Pentru tal, um conceito muito important, și care va fi folosit în acest proiect, s-a salvat de Waypoints!
Foi criado um method for traçar a rota între dois dados pontos:
private String getDirectionsUrl (origine LatLng, LatLng dest, List waypointsList) {
// Originea traseului
String str_origin = "origin =" + origin.latitude + "," + origin.longitude;
// Destinația traseului
String str_dest = "destination =" + dest.latitude + "," + dest.longitude;
// Puncte de parcurs de-a lungul traseului
//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; pentru (punct LatLng: waypointsList) {waypoints + = "|" + point.latitude + "," + point.longitude; }
// Senzor activat
String sensor = "senzor = fals";
// Construirea parametrilor serviciului web
Parametrii șirului = str_origin + "&" + str_dest + "&" + senzor + "&" + puncte de referință;
// Format de iesire
Șir de ieșire = "json";
// Construirea adresei URL către serviciul web
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; System.out.println ("+++++++++++++++" + url);
returnează adresa URL;
}
E, prin film, juntand tot nu metoda principala din clasa, 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 (); }
// Desenați trasee
// Obținerea URL-ului către API-ul Google Directions
Puncte de listă = ArrayList nou (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);
String url = getDirectionsUrl (curent, lixeiraA, puncte);
DownloadTask downloadTask = new DownloadTask (); // Începeți să descărcați date JSON din Google Directions API downloadTask.execute (url); }
Aqui passamos apenas pelos pontos principal. O cod complet al proiectului va fi disponibilizat pentru consultare.
Pasul 8: Concluzie
Este foi um projeto trabalhando conceitos de IoT, mostrando uma das várias opções de conectar dispozitive através da nuvem, e efetuar tomada de decisões sem interferência humana direta. Anexează, îmi urmează un videoclip complet proiectat, pentru ilustrație, și fonturile din activități criadă fără Android.
Recomandat:
Cum să faci 4G LTE dublă antenă BiQuade Pași simpli: 3 pași
Cum să fac 4G LTE Double BiQuade Antenna Pași simpli: De cele mai multe ori mă confrunt, nu am o putere de semnal bună pentru lucrările mele de zi cu zi. Asa de. Căut și încerc diferite tipuri de antenă, dar nu funcționează. După un timp pierdut, am găsit o antenă pe care sper să o fac și să o testez, pentru că nu se bazează pe principiul
Design de joc în Flick în 5 pași: 5 pași
Designul jocului în Flick în 5 pași: Flick este un mod foarte simplu de a crea un joc, în special ceva de genul puzzle, roman vizual sau joc de aventură
Sistemul de alertă pentru parcarea inversă a autovehiculului Arduino - Pași cu pași: 4 pași
Sistemul de alertă pentru parcarea inversă a autovehiculului Arduino | Pași cu pas: în acest proiect, voi proiecta un senzor senzor de parcare inversă Arduino Car Circuit folosind senzorul cu ultrasunete Arduino UNO și HC-SR04. Acest sistem de avertizare auto bazat pe Arduino poate fi utilizat pentru navigație autonomă, autonomie robotică și alte r
Detectarea feței pe Raspberry Pi 4B în 3 pași: 3 pași
Detectarea feței pe Raspberry Pi 4B în 3 pași: În acest instructabil vom efectua detectarea feței pe Raspberry Pi 4 cu Shunya O / S folosind Biblioteca Shunyaface. Shunyaface este o bibliotecă de recunoaștere / detectare a feței. Proiectul își propune să obțină cea mai rapidă viteză de detectare și recunoaștere cu
SmartBin: 4 pași
SmartBin: Scopul principal al acestui proiect este de a crea un dispozitiv electronic care utilizează cel puțin un Raspberry Pi. Echipa este formată din 5 viitori ingineri mecanici și un inginer automatizat. Proiectul nostru constă în realizarea unui coș de gunoi care se deschide și se închide