Kazalo:
- Korak: Senzor Conectando O
- 2. korak: Montando a Lixeira
- Korak: Naložite Para a Nuvem
- 4. korak: Recuperando Dados Do ThingSpeak
- 5. korak: Criando in Aplicação Android
- 6. korak: Recuperando O Feed No Android
- Korak 7: Mostrando brez zemljevida
- 8. korak: Zaključite
Video: SmartBin: 8 korakov
2024 Avtor: John Day | [email protected]. Nazadnje spremenjeno: 2024-01-31 10:24
Este é um projeto para um sistema 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
- Senzor Ultrassônico de Distancia
- Caixa de papelão
- Protoboard
- Cabos
- Prenesite Android
Korak: Senzor Conectando O
Primeramente, vamos effecttuar 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:
// definira številke zatičev #define 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.
float cmMsec, inMsec;
dolg mikrosek = ultrazvočni čas ();
cmMsec = ultrasonic.convert (microsec, Ultrasonic:: CM);
inMsec = ultrasonic.convert (mikrosek, Ultrasonic:: IN);
// Exibe informacoes no serijski monitor
Serial.print ("Distancia em cm:");
Serijski.tisk (cmMsec);
Serial.print (" - Distancia em polegadas:");
Serial.println (inMsec);
Podatkovni niz = niz (cmMsec);
Serial.println (podatki);
2. korak: Montando a Lixeira
Agora, vamos montar a lixeira inteligente. Precisaremos conectar o ultrassônico senzor brez "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 simulacijo, visto que não possuo mais de um senzor ultrassônico, foi feito um algoritmo para salvar randomicamente in distancia lida em 4 lixeiras diferentes.
// Simulando 4 lixeiras
dolga lixeiraID;
void loop () {
lixeiraID = naključno (1, 5);
}
Korak: Naložite Para a Nuvem
Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por familiaridade com o mesmo. Primeiramente, é neophodário criar um novo channel, recebendo 4 parâmetros, sklicuje se na ao volume de cada lixeira.
Pará conectar a applicação com o ThingSpeak, é needário salvar o número da API do channel criado. Siga os passos descritos no site oficial.
De volta à applicação, vamos utiralar 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 ("Povezovanje z"+ *ssid);
WiFi.begin (ssid, pass);
medtem ko (WiFi.status ()! = WL_CONNECTED) {
zamuda (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 ThingSpeak, basta abrir uma conexão HTTP padrão, passando o número da API e os parâmetros.
void sendDataTS (float cmMsec, dolg id) {
if (client.connect (strežnik, 80)) {
Serial.println ("Enviando dados para o ThingSpeak");
Niz postStr = apiKey;
postStr += "& polje";
postStr += id;
postStr += "=";
postStr += niz (cmMsec);
postStr += "\ r / n / r / n";
Serial.println (postStr);
client.print ("POST /posodobi HTTP /1.1 / n");
client.print ("Gostitelj: api.thingspeak.com / n");
client.print ("Povezava: zaprta / n");
client.print ("X-THINGSPEAKAPIKEY:" + apiKey + "\ n");
client.print ("Vrsta vsebine: aplikacija/x-www-form-urlencoded / n");
client.print ("Content-Length:");
client.print (postStr.length ());
client.print ("\ n / n");
client.print (postStr);
zamuda (1000);
}
client.stop ();
}
O primeiro parâmetro ustreza à distância em centímetros encontrada pelo senzor 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 também para identificar para qual campo será feito o upload do valor lido.
4. korak: Recuperando Dados Do ThingSpeak
O ThingSpeak dovolite efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Kot 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 naslovu URL za 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: kanal número do seu
- FIELD_NUMBER: o številki dela
- API_KEY: a chave de API do seu kanal
Namestite URL, ki je namenjen aplikaciji Android, za obnovitev ali uporabo ThingSpeak.
5. korak: Criando in Aplicação Android
No Android Studio, crie um novo projeto Android. Če želite popraviti funkcijo, ki jo je treba aplicirati, je potrebno konfigurirati kot dovoljenja za uporabo brez AndroidManifesta.
Če uporabljate Google Zemljevide, potrebujete nekaj časa za uporabo 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.
Ključ API za API-je, ki temeljijo na Google Zemljevidih, je opredeljen kot vir niza.
(Glejte datoteko "res/values/google_maps_api.xml").
Upoštevajte, da je ključ API povezan s šifrirnim ključem, ki se uporablja za podpis APK. Za vsak šifrirni ključ potrebujete drugačen ključ API, vključno s ključem za sprostitev, ki se uporablja za podpis APK za objavo. Ključe za cilje za odpravljanje napak in sprostitev lahko določite v src/debug/in src/release/.
<metapodatki
android: name = "com.google.android.geo. API_KEY"
android: value = "@string /google_maps_key" />
Konfiguracija, ki je dokončana z arkivo AndroidManifest, je anexado ao projeto.
n
6. korak: Recuperando O Feed No Android
Na glavnem glavnem mestu Androida, MainActivity, 4 različice za identifikacijo 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"; zasebni niz url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; zasebni niz url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; zasebni niz url_d = "https://api.thingspeak.com/channels/429823/fields/4/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true";
Če želite, da vaš računalnik uporablja vse, kar potrebujete, uporabite razred za Android, posebno JSONObject. Več o tem, naslov 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.
javni JSONObject makeHttpRequest (URL niza, metoda niza, parametri zemljevida) {
poskusi {
Uri. Builder builder = nov 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 (metoda)) {url = url + "?" + encodedParams; urlObj = nov URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metoda);
} drugo {
urlObj = nov 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 ()); } // Povežite se s strežnikom urlConnection.connect (); // preberite odgovor je = urlConnection.getInputStream (); BufferedReader reader = nov BufferedReader (nov InputStreamReader (je)); StringBuilder sb = nov StringBuilder (); Vrvica;
// Razčlenite odgovor
medtem ko ((vrstica = bralec.readLine ())! = nič) {sb.append (vrstica + "\ n"); } is.close (); json = sb.toString (); // Pretvorimo odgovor v Objekt JSON jObj = nov JSONObject (json);
} catch (UnsupportedEncodingException e) {
e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Napaka pri razčlenjevanju podatkov" + e.toString ()); } catch (Izjema e) {Log.e ("Izjema", "Napaka pri razčlenjevanju podatkov" + e.toString ()); }
// vrne objekt JSON
vrnitev 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 zaščiteni niz doInBackground (String… params) {HttpJsonParser jsonParser = nov HttpJsonParser ();
responseLixeiraA = jsonParser.makeHttpRequest (url_a, "GET", ničelno);
responseLixeiraB = jsonParser.makeHttpRequest (url_b, "GET", ničelno); responseLixeiraC = jsonParser.makeHttpRequest (url_c, "GET", ničelno); responseLixeiraD = jsonParser.makeHttpRequest (url_d, "GET", ničelno);
return null;}
Omogoča vam, da izvedete doInBackgroundé encerrado, ali nadzirate izvajanje operacijskega sistema Android za uporabo na spletnem mestu PostExecute. Neste método, vamos criar os objetos Lixeira, popularni com os dados recuperados do ThingSpeak:
zaščitena praznina onPostExecute (rezultat niza) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {
// ListView listView = (ListView) findViewById (R.id.feedList);
Ogled mainView = (Ogled) findViewById (R.id.activity_main); if (uspeh == 1) {poskusite {// 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 = nov SmartBinService (); calculator.montaListaLixeiras (feedList);
// Recupera komponente
TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll (feedList);
// Realni podatki
Datum currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = nov SimpleDateFormat ("dd/MM/llll"); Niz currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adapter);
} catch (JSONException e) {
e.printStackTrace (); }
} drugo {
Toast.makeText (MainActivity.this, "Pri nalaganju podatkov je prišlo do napake", Toast. LENGTH_LONG).show ();
}
} }); }
Agora, na tela inicial do aplicativo, serão listados os dados de cada lixeira.
Korak 7: Mostrando brez zemljevida
Ainda na atividade principal, vamos adicionar uma ação a ser relacionada ao botão Mapa, na tela inicial.
/ ** Pokliče se, ko uporabnik pritisne gumb Mapa*/ public void openMaps (pogled Pogled) {Namen namera = nov namen (to, LixeiraMapsActivity.class);
// Passa a lista de lixeiras
Bundle bundle = new Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (sveženj);
startActivity (namen);
}
Brez zemljevida, temos três atividades a executer:
- 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
Če želite izvedeti več o tem, uporabite Google API za navodila. Para desenhar as rotas, foram seguidos os passos do tutorial Risanje navodil za pot vožnje med dvema lokacijama z uporabo Google Directions v Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
// Lokacije
zasebni tok LatLng;
zasebni LatLng lixeiraA; zasebni LatLng lixeiraB; zasebni LatLng lixeiraC; zasebni LatLng lixeiraD;.
Para adicionar a posição atual no mapa, foi criado o método:
private void checkLocationandAddToMap () {// Preverjanje, ali je uporabnik podelil dovoljenje if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.missionChement, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Zahtevanje dovoljenja za lokacijo ActivityCompat.requestPermissions (ta, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); vrnitev; }
// Pridobivanje zadnje znane lokacije s pomočjo Fus
Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);
// MarkerOptions se uporabljajo za ustvarjanje novega Markerja. Z MarkerOptions lahko določite lokacijo, naslov itd
this.current = nov LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = new MarkerOptions (). Position (current).title ("Posição atual");
// Dodajanje ustvarjenega označevalca na zemljevid, premikanje kamere v položaj
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("+++++++++++++ Passei aqui! +++++++++++++"); mMap.addMarker (markerOptions);
// Fotoaparat takoj premaknite na lokacijo s povečavo 15.
mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (trenutno, 15));
// Povečajte, animirajte kamero.
mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, nič);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation () {// Preverjanje, ali je uporabnik podelil dovoljenje if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission this, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Zahtevanje dovoljenja za lokacijo ActivityCompat.requestPermissions (ta, novi niz {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); vrnitev; }
// Praça da Estação
dvojna zemljepisna širina = -19,9159578; dvojna zemljepisna dolžina = -43.9387856; this.lixeiraA = nov LatLng (zemljepisna širina, dolžina);
MarkerOptions markerOptions = new MarkerOptions (). Position (lixeiraA).title ("Lixeira A");
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_RED)); mMap.addMarker (markerOptions); }
Kot zemljepisna širina in dolžina de cada lixeira za recuperadas através do próprio Google Maps, e deixadas fixas no código. Idealno, estes valores ficariam salvos em um banco de dados (na primer 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 (izvor LatLng, cilj LatLng, List waypointsList) {
// Izvor poti
Niz str_origin = "origin ="+origin.latitude+","+origin.longitude;
// Cilj poti
String str_dest = "destination ="+dest.latitude+","+dest.longitude;
// Točke poti na poti
//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 Niz waypoints = "waypoints = optimize: true"; for (LatLng point: waypointsList) {waypoints += "|" + point. Latitude + "," + point. Longitude; }
// Senzor omogočen
String sensor = "sensor = false";
// Ustvarjanje parametrov spletne storitve
Parametri niza = str_origin+"&"+str_dest+"&"+senzor+"&"+točke poti;
// Izhodni format
Niz izhod = "json";
// Ustvarjanje URL -ja za spletno storitev
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parametri; System.out.println ("++++++++++++++"+url);
povratni url;
}
E, por fim, juntando tudo no método principal da classe, onMapReady:
@Odpravite javno void na 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 (); }
// Nariši poti
// Pridobivanje URL -ja do API -ja Google Directions
Seznam točk = nov ArrayList (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);
Niz url = getDirectionsUrl (trenutni, lixeiraA, točke);
DownloadTask downloadTask = nov DownloadTask (); // Začnite nalagati podatke json iz API -ja Google Directions downloadTask.execute (url); }
Aqui passamos apenas pelos pontos principais. O código completo do projekto será disponibilizado para consulting.
8. korak: 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 odločões sem interferência humana direta. Em anexo, segue um vídeo do projeto completeto, para ilustração, e os fontes das atividades criadas no Android.
Priporočena:
Števec korakov - mikro: Bit: 12 korakov (s slikami)
Števec korakov - Micro: Bit: Ta projekt bo števec korakov. Za merjenje korakov bomo uporabili senzor pospeška, ki je vgrajen v Micro: Bit. Vsakič, ko se Micro: Bit trese, bomo štetju dodali 2 in ga prikazali na zaslonu
Akustična levitacija z Arduino Uno Korak po korak (8 korakov): 8 korakov
Akustična levitacija z Arduino Uno Korak po korak (8 korakov): ultrazvočni pretvorniki zvoka L298N Dc ženski adapter z napajalnim vtičem za enosmerni tok Arduino UNOBreadboard Kako to deluje: Najprej naložite kodo v Arduino Uno (to je mikrokrmilnik, opremljen z digitalnim in analogna vrata za pretvorbo kode (C ++)
Vijak - Nočna ura za brezžično polnjenje DIY (6 korakov): 6 korakov (s slikami)
Bolt - Nočna ura za brezžično polnjenje DIY (6 korakov): Induktivno polnjenje (znano tudi kot brezžično polnjenje ali brezžično polnjenje) je vrsta brezžičnega prenosa energije. Za zagotavljanje električne energije prenosnim napravam uporablja elektromagnetno indukcijo. Najpogostejša aplikacija je brezžično polnjenje Qi
Merilnik korakov 1. del: Enobarvni zaslon 128x32 in Arduino: 5 korakov
Pedometer 1. del: Enobarvni zaslon 128x32 in Arduino: To je osnovna vadnica, ki uči, kako uporabljati zaslon OLED s svojim Arduinom. Uporabljam zaslon velikosti 128x32, lahko pa uporabite tudi drugačen zaslon z ločljivostjo in po potrebi spremenite ločljivost/koordinate. V tem delu vam bom pokazal, kako
SmartBin: 4 koraki
SmartBin: Glavni namen tega projekta je ustvariti elektronsko napravo, ki uporablja vsaj eno Raspberry Pi. Ekipo sestavlja 5 bodočih strojnih inženirjev in en inženir avtomatizacije. Naš projekt je sestavljen iz smetnjaka, ki se odpre in zapre