Sadržaj:
- Korak 1: Conectando O senzor
- Korak 2: Montando a Lixeira
- Korak 3: Postavite Para a Nuvem
- Korak 4: Recuperando Dados Do ThingSpeak
- Korak 5: Criando i Aplikação Android
- Korak 6: Recuperando O Feed Nema Androida
- Korak 7: Mostrando bez karte
- Korak 8: Zaključite
Video: SmartBin: 8 koraka
2024 Autor: John Day | [email protected]. Zadnja izmjena: 2024-01-31 10:17
Este é um projeto para sistem sistema inteligente de coletas, no qual os caminhões de lixo recebem dados das lixeiras, identificira 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, é neophodário:
- NodeMCU
- Senzor Ultrassônico de Distancia
- Caixa de papelão
- Protoboard
- Cabos
- Dispozitivo Android
Korak 1: Conectando O senzor
Primarno, vamos efektivno povezivanje ultrazvučnog senzora i NODEMCU -a. Para tanto, vamos konektar kao okidač porta i senzor eho do nas porta D4 i D3 do NodeMCU:
// definira brojeve pinova #define pino_trigger 2 // D4
#define pino_echo 0 // D3
Para efektiar leitura dos dados do senzor, foi seguido o tutorial elaborado pelo FilipeFlop, disponível aqui.
float cmMsec, inMsec;
dugačak mikrosek = ultrazvučni.timing ();
cmMsec = ultrasonic.convert (mikrosek, Ultrazvuk:: CM);
inMsec = ultrasonic.convert (mikrosek, Ultrazvuk:: IN);
// Exibe informacoes no serijski monitor
Serial.print ("Distancia em cm:");
Serial.print (cmMsec);
Serial.print (" - Distancia em polegadas:");
Serial.println (inMsec);
String data = String (cmMsec);
Serial.println (podaci);
Korak 2: Montando a Lixeira
Agora, vamos montar a lixeira inteligente. Precisaremos konektor ili ultrazvučni senzor bez "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 simulaciju, ako ne morate koristiti ultrazvučni senzor, možete primijeniti algoritam za automatsko čuvanje i distanciranje 4 liksera različitosti.
// Simulando 4 lixeiras
long lixeiraID;
void loop () {{100} {101}
lixeiraID = slučajno (1, 5);
}
Korak 3: Postavite Para a Nuvem
Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, ili familiidade com o mesmo. Primeiramente, é neophodário criar um novo channel, recebendo 4 parámetros, reores ao volume de cada lixeira.
Par parametar koji se primjenjuje u ThingSpeak -u, neophodan je za korištenje API -ja u kanalu. Siga os passos descritos no site oficial.
Da biste primijenili aplikaciju, možete koristiti biblioteku ESP8266WiFi.h za efektivno povezivanje s ThingSpeakom ili prijenosom.
Primeiramente, uma função para efetuar conexão com a rede (definirajte previamente duas variáveis, ssid i pass , contendo o identificador e a senha de sua rede).
void connectWifi () {
Serial.print ("Povezivanje sa"+ *ssid);
WiFi.begin (ssid, pass);
while (WiFi.status ()! = WL_CONNECTED) {
kašnjenje (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, za dodatne informacije o ThingSpeak -u, jednostavno uklonite uzajamno povezivanje HTTP -a, pređite na numeru API -ja i provjerite parametre.
void sendDataTS (float cmMsec, long id) {
if (client.connect (server, 80)) {
Serial.println ("Enviando dados para o ThingSpeak");
String postStr = apiKey;
postStr += "& polje";
postStr += id;
postStr += "=";
postStr += String (cmMsec);
postStr += "\ r / n / r / n";
Serial.println (postStr);
client.print ("POST /ažuriraj HTTP /1.1 / n");
client.print ("Domaćin: api.thingspeak.com / n");
client.print ("Veza: zatvori / 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);
kašnjenje (1000);
}
client.stop ();
}
O primjeru odgovarajućeg parametra odgovara à distância em centímetros encontrada pelo senzora 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 tambem para identificar para qual campo será feito o upload do valor lido.
Korak 4: Recuperando Dados Do ThingSpeak
O ThingSpeak dozvolite da efektivno učinite sve što možete učiniti sa kanalom, através de um serviço retornando um JSON. Kako se razlikuju opções para leitura do feed do seu kanala 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 adrã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 nema veze sa informacijama unaprijed. Os mais importantes para o projeto são:
- CHANNEL_ID: número do seu kanal
- FIELD_NUMBER: o número do campo
- API_KEY: API za seve kanal
Ovo je URL adresa koja sadrži aplikacije za Android, za potrebe oporavka za ThingSpeak.
Korak 5: Criando i Aplikação Android
Nema Android Studija, pogledajte novi projekat za Android. Da biste primijenili funkcionalnost aplikacije koja je potrebna, morate konfigurirati dopuštenja za Android ili Manifest.
Za korištenje Google karata, ako vam je potrebna pomoć za korištenje Googlea. Siga os passos descritos no link Obter chave de API.
Uma vez com a chave, você deve também configurá-la na aplikaciji.
API ključ za API-je zasnovane na Google kartama definiran je kao niz izvor.
(Pogledajte datoteku "res/values/google_maps_api.xml").
Imajte na umu da je API ključ povezan s ključem za šifriranje koji se koristi za potpisivanje APK -a. Za svaki ključ šifriranja potreban vam je drugačiji API ključ, uključujući ključ za izdanje koji se koristi za potpisivanje APK -a za objavljivanje. Ključeve za ciljeve otklanjanja grešaka i izdanja možete definirati u src/debug/i src/release/.
<meta-podaci
android: name = "com.google.android.geo. API_KEY"
android: value = "@string /google_maps_key" />
Konfiguracija je potpuna i dostupna za AndroidManifest kao dodatak ao projektu.
n
Korak 6: Recuperando O Feed Nema Androida
Na aktivnom principu nema Androida, MainActivity, pogledajte 4 varijacije za identifikaciju kad je u pitanju kanaliranje 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"; privatni niz 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";
Za efektivnu i korisničku nadogradnju, iremos korištenja uma klase za Android específica, chamada JSONObject. Više informacija možete pronaći u objektu za URL 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, efektuar leitura dos dados encontrados, e retornar or object JSON montado.
javni JSONObject makeHttpRequest (URL niza, metoda niza, parametri karte) {
probaj {
Uri. Builder builder = novi 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 = novi URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metoda);
} else {
urlObj = novi 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 ()); } // Povezivanje sa serverom urlConnection.connect (); // Pročitajte odgovor je = urlConnection.getInputStream (); BufferedReader čitač = novi BufferedReader (novi InputStreamReader (je)); StringBuilder sb = novi StringBuilder (); String line;
// Raščlanjivanje odgovora
while ((line = reader.readLine ())! = null) {sb.append (line + "\ n"); } is.close (); json = sb.toString (); // Pretvorimo odgovor u JSON Objekt jObj = novi JSONObject (json);
} catch (UnsupportedEncodingException e) {
e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Greška pri raščlanjivanju podataka" + e.toString ()); } catch (Izuzetak e) {Log.e ("Izuzetak", "Greška pri raščlanjivanju podataka" + e.toString ()); }
// vraća JSON objekt
return jObj;
}
}
De volta atividade principal, vamos efetuar chamada as urls de forma assíncrona, escrevendo este código dentro do método doInBackground.
@Override zaštićen niz doInBackground (String… params) {HttpJsonParser jsonParser = novi 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);
return null;}
Možete preuzeti doInBackground encerrado, izvršnu kontrolu za Android prolaz za metodi naPostExecute. Neste método, vamos criar os Objetos Lixeira, and popular com os dados recuperados do ThingSpeak:
zaštićena praznina naPostExecute (rezultat niza) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {
// ListView listView = (ListView) findViewById (R.id.feedList);
View mainView = (View) findViewById (R.id.activity_main); if (success == 1) {try {// 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 = novi SmartBinService (); calculator.montaListaLixeiras (feedList);
// Recupera components
TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll (feedList);
// Stvarni podaci
Datum currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = novi SimpleDateFormat ("dd/MM/ggggg"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adapter);
} catch (JSONException e) {
e.printStackTrace (); }
} else {
Toast.makeText (MainActivity.this, "Došlo je do neke greške pri učitavanju podataka", Toast. LENGTH_LONG).show ();
}
} }); }
Agora, na tela inicial za apliciranje, popis stranica koje su navedene kao cada lixeira.
Korak 7: Mostrando bez karte
Ainda na atividade principal, vamos adicionar uma ação a ser relacionada ao botão Mapa, na tela inicial.
/ ** Poziva se kada korisnik dodirne dugme Mapa*/ public void openMaps (prikaz) {Intent intent = new Intent (this, LixeiraMapsActivity.class);
// Prelazak na listu de lixeiras
Bundle bundle = new Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (paket);
startActivity (namjera);
}
Nema mape, temos três atividades je izvršilac:
- marcar a posição atual do caminha de lixo
- marcar os pontos korespondentes a cada lixeira no mapa
- traçar a rota entre os pontos
Da biste izvršili sve potrebne korake, koristite API Google smjernice. Para desenhar as rotas, foram seguidos os passos do tutorial Crtanje uputstava za rutu vožnje između dvije lokacije pomoću Google smjerova na Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
// Lokacije
privatna LatLng struja;
privatni LatLng lixeiraA; privatni LatLng lixeiraB; privatni LatLng lixeiraC; privatni LatLng lixeiraD;.
Para adicionar a posição atual no mapa, foi criado o método:
private void checkLocationandAddToMap () {// Provjeravamo je li korisnik odobrio dozvolu if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.missionChement, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Traženje dozvole za lokaciju ActivityCompat.requestPermissions (ovaj, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); return; }
// Dohvaćanje posljednje poznate lokacije pomoću Fus -a
Lokacija lokacije = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);
// MarkerOptions se koriste za kreiranje novog Marker -a. Možete odrediti lokaciju, naslov itd. Pomoću MarkerOptions
this.current = novi LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = new MarkerOptions (). Position (current).title ("Posição atual");
// Dodavanje kreiranog markera na mapu, pomicanje kamere u položaj
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("++++++++++++++ Passei aqui! +++++++++++++"); mMap.addMarker (markerOptions);
// Odmah premjestite kameru na lokaciju sa zumiranjem od 15.
mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (trenutno, 15));
// Uvećajte prikaz, animirajući kameru.
mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation () {// Provjerava je li korisnik odobrio dozvolu if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission this, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Traženje dozvole za lokaciju ActivityCompat.requestPermissions (ovaj, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); return; }
// Praça da Estação
dvostruka širina = -19,9159578; dvostruka geografska dužina = -43.9387856; this.lixeiraA = novi LatLng (zemljopisna širina, dužina);
MarkerOptions markerOptions = new MarkerOptions (). Position (lixeiraA).title ("Lixeira A");
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_RED)); mMap.addMarker (markerOptions); }
Kao geografska širina i dužina prikazane su cada lixeira za recuperadas através do próprio Google Maps, i deixadas fixas no código. Idealno, estes valores ficariam salvos em um banco de dados (na primjer 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 (LatLng origin, LatLng dest, List waypointsList) {
// Polazište rute
String str_origin = "origin ="+origin.latitude+","+origin.longitude;
// Odredište rute
String str_dest = "destination ="+dest.latitude+","+dest.longitude;
// Međutočke duž rute
//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; za (LatLng point: waypointsList) {waypoints += "|" + point.latitude + "," + point.longitude; }
// Senzor omogućen
String sensor = "sensor = false";
// Izgradnja parametara web usluge
Parametri niza = str_origin+"&"+str_dest+"&"+senzor+"&"+međutočke;
// Izlazni format
String output = "json";
// Izgradnja URL -a za web uslugu
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parametri; System.out.println ("++++++++++++++"+url);
return url;
}
E, por fim, juntando tudo no método principal da classe, onMapReady:
@Premosti javnu prazninu 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 (); }
// Crtanje ruta
// Dobivanje URL -a u Google Directions API
Lista bodova = novi ArrayList (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);
String url = getDirectionsUrl (current, lixeiraA, points);
DownloadTask downloadTask = novi DownloadTask (); // Pokretanje preuzimanja json podataka iz API -ja Google Directions downloadTask.execute (url); }
Aqui passamos apenas pelos pontos principais. O código completo do projeto será disponibilizado para consulting.
Korak 8: 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 odlucies sem interferência humana direta. U dodatku, pogledajte video do projekcije do kraja, za ilustraciju, ili kao osnove za aktiviranje bez Androida.
Preporučuje se:
Dizajn igre brzim pokretom u 5 koraka: 5 koraka
Dizajn igre u Flick -u u 5 koraka: Flick je zaista jednostavan način da napravite igru, posebno nešto poput zagonetke, vizuelnog romana ili avanturističke igre
Prepoznavanje lica na Raspberry Pi 4B u 3 koraka: 3 koraka
Prepoznavanje lica na Raspberry Pi 4B u 3 koraka: U ovom uputstvu ćemo izvršiti otkrivanje lica na Raspberry Pi 4 sa Shunya O/S koristeći biblioteku Shunyaface. Shunyaface je biblioteka za prepoznavanje/otkrivanje lica. Cilj projekta je postići najbržu brzinu otkrivanja i prepoznavanja sa
Kako napraviti brojač koraka?: 3 koraka (sa slikama)
Kako napraviti brojač koraka?: Nekada sam se dobro snašao u mnogim sportovima: hodanje, trčanje, vožnja bicikla, igranje badmintona itd. Volim jahanje da bih brzo putovao. Pa, pogledaj moj trbušni trbuh … Pa, u svakom slučaju, odlučujem ponovo početi vježbati. Koju opremu treba pripremiti?
SmartBin: 4 koraka
SmartBin: Glavna svrha ovog projekta je stvaranje elektroničkog uređaja koji koristi barem jedan Raspberry Pi. Tim čini 5 budućih mašinskih inženjera i jedan inženjer automatizacije. Naš projekt sastoji se u izradi kante za smeće koja se otvara i zatvara
Broj koraka / koraka: 3 koraka
পেনড্রাইভ / মেমোরি কার্ডে ভাইরাসের ভাইরাসের হারিয়ে সমাধান সমাধান সমাধান সমাধান সমাধান পেনড্রাইভ পেনড্রাইভ পেনড্রাইভ পেনড্রাইভ মেমোরি মেমোরি মেমোরি মেমোরি মেমোরি মেমোরি মেমোরি এখন এখন এখন।।।।।। Zaštita podataka, pristup prečicama / virusima