Sisällysluettelo:
- Vaihe 1: Conectando O -anturi
- Vaihe 2: Montando ja Lixeira
- Vaihe 3: Lataa Nuvem
- Vaihe 4: Recuperando Dados Do ThingSpeak
- Vaihe 5: Criando a Aplicação Android
- Vaihe 6: Palauta O -syöte Ei Androidia
- Vaihe 7: Mostrando No Mapa
- Vaihe 8: Conclusão
Video: SmartBin: 8 vaihetta
2024 Kirjoittaja: John Day | [email protected]. Viimeksi muokattu: 2024-01-31 10:19
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 informações recuperadas.
Para montar este projeto, e välttämättömyys:
- NodeMCU
- Anturi Ultrassônico de Distancia
- Caixa de papelão
- Protoboard
- Cabos
- Androidin käyttö
Vaihe 1: Conectando O -anturi
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:
// määrittelee nastojen numerot #define pino_trigger 2 // D4
#define pino_echo 0 // D3
Parempi kuin leitura dos dados do -anturi, sekoitus tai opetusohjelma FilipeFlop -pelissä, joka on suunniteltu käytettäväksi.
kellua cmMsec, inMsec;
pitkä mikrosekunti = ultraääni.ajoitus ();
cmMsec = ultraääni.muunnos (mikrosekunti, ultraääni:: CM);
inMsec = ultraääni.muunnos (mikrosekunti, ultraääni:: IN);
// Exibe informacoes no serial monitor
Serial.print ("Distancia em cm:");
Sarjajälki (cmMsec);
Serial.print (" - Distancia em polegadas:");
Sarja.println (inMsec);
Merkkijonotiedot = Jono (cmMsec);
Serial.println (data);
Vaihe 2: Montando ja Lixeira
Agora, vamos montar ja lixeira inteligente. Tarkka liitäntäanturi tai ultraäänitunnistin ilman "teto" da lixeiraa. Esimerkkinä voidaan käyttää cabo ja fita isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. Ei meu caso, foi de 26, 3cm. Esse é o valor que Regardrarmos para uma lixeira vazia.
Simulaatio, visto que não possuo mais de um sensor ultrassônico, foi feito um algoritmo para salvar randomicamente and distancia lida em 4 lixeiras diferentes.
// Simulando 4 lixeiras
pitkä lixeiraID;
void loop () {
lixeiraID = satunnainen (1, 5);
}
Vaihe 3: Lataa Nuvem
Agora, tarkat enviar estes dados para a nuvem. Eu esholhi tai ThingSpeak, familiaridade com o mesmo. Primeiramente, é välttämätön criar um novo canal, recebendo 4 parâmetros, referentes ao volume de cada lixeira.
Parque conectar a aplicação com o ThingSpeak, e, välttämätön salvar tai número da API do canal criado. Siga os passos descritos no site virallinen.
De volta à aplicação, vamos utilizar a biblioteca ESP8266WiFi.h for efetuar conexão com or ThingSpeak, and transferir os dados.
Primeiramente, uma função para efetuar conexão com a rede (defina previamente duas variáveis, ssid e pass , contendo o identifador e a senha de sua rede).
void connectWifi () {
Serial.print ("Yhdistäminen"+ *ssid);
WiFi. Alku (ssid, pass);
while (WiFi.status ()! = WL_CONNECTED) {
viive (500);
Serial.print (".");
}
Serial.println ("");
Serial.print ("Conectado na rede");
Sarja.println (ssid);
Serial.print ("IP:");
Serial.println (WiFi.localIP ());
}
Durante o setup, tentamos efetuar a conexão com a rede.
void setup () {
Sarja.alku (9600);
Serial.println ("Lendo dados do sensor …");
// Yhdistä Wi-Fi
connectWifi ();
}
E, para enviar os dados para or 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 (palvelin, 80)) {
Serial.println ("Enviando dados para o ThingSpeak");
Merkkijono postStr = apiKey;
postStr += "& kenttä";
postStr += id;
postStr += "=";
postStr += Jono (cmMsec);
postStr += "\ r / n / r / n";
Serial.println (postStr);
client.print ("POST /päivitä HTTP /1.1 / n");
client.print ("Isäntä: api.thingspeak.com / n");
client.print ("Yhteys: sulje / 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);
viive (1000);
}
client.stop ();
}
O primeiro parâmetro vastaa à 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 identifar para para campo será feito o upload do valor lido.
Vaihe 4: Recuperando Dados Do ThingSpeak
O ThingSpeak permite 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 directtamente os dados de cada campo. Osoita URL -osoite para cen cenio:
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. Tärkeää tietoa projektista:
- CHANNEL_ID: número do seu -kanava
- FIELD_NUMBER: o número do campo
- API_KEY: chave de API do seu -kanava
Tämä on Android -sovelluksen URL -osoite, joka toimii ThingSpeakin tallentimena.
Vaihe 5: Criando a Aplicação Android
Ei Android Studiota, huuda Android -ohjelma. Paranna tai korjaa funktionamento da aplicação, ja välttämätön konfiguraattori, joka on sallittu ilman AndroidManifestia.
Käytä Google Mapsia tai Google -palvelua. 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 Maps -pohjaisten sovellusliittymien sovellusliittymäavain määritellään merkkijonoresurssiksi.
(Katso tiedosto "res/values/google_maps_api.xml").
Huomaa, että API -avain on linkitetty salausavaimeen, jota käytetään APK: n allekirjoittamiseen. Tarvitset eri API -avaimen kullekin salausavaimelle, mukaan lukien julkaisuavain, jota käytetään APK: n allekirjoittamiseen julkaisemista varten. Voit määrittää avaimet debug- ja release -kohteille src/debug/ja src/release/.
<metatiedot
android: name = "com.google.android.geo. API_KEY"
android: value = "@string /google_maps_key" />
Täydellinen kokoonpano, joka on suunniteltu AndroidManifest anexado -ohjelmaan.
n
Vaihe 6: Palauta O -syöte Ei Androidia
Ei Android-, MainActivity-, crie 4 -versioita, jotka on määritetty tunnistamaan 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";
Parempi kuin leitura dos dados, iremos utilizar uma classe do Android específica, chamada JSONObject. Mais uma vez, vamos criar um objeto para cada URL:
JSONObjektin vastausLixeiraA; JSONObjektin vastausLixeiraB; JSONObjektin vastausLixeiraC; JSONObjektin vastausLixeiraD;
Jos haluat käyttää URL -osoitetta, voit käyttää criar uma classe auxiliar, chamada HttpJsonParser. Esta classe -palvelun vastaus, joka on saatavilla abrir uma conexão com um URL, efetuar leitura dos dados encontrados, e retornar or objeto JSON montado.
julkinen JSONObject makeHttpRequest (merkkijonon URL -osoite, merkkijonomenetelmä, kartan parametrit) {
yrittää {
Uri. Builder builder = uusi Uri. Builder (); URL -osoite urlObj; String encodedParams = ""; if (params! = null) {for (Map. Entry -merkintä: params.entrySet ()) {builder.appendQueryParameter (entry.getKey (), entry.getValue ()); }} if (builder.build (). getEncodedQuery ()! = null) {encodedParams = builder.build (). getEncodedQuery ();
}
if ("GET".equals (method)) {url = url + "?" + koodatutParams; urlObj = uusi URL -osoite (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (menetelmä);
} muuta {
urlObj = uusi URL -osoite (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (menetelmä); urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). write (encodedParams.getBytes ()); } // Yhdistä palvelimeen urlConnection.connect (); // Lue vastaus on = urlConnection.getInputStream (); BufferedReader -lukija = new BufferedReader (uusi InputStreamReader (on)); StringBuilder sb = uusi StringBuilder (); Merkkijono;
// jäsennä vastaus
while ((rivi = lukija.lukulinja ())! = null) {sb.append (rivi + "\ n"); } on lähellä(); json = sb.toString (); // Muunna vastaus muotoon JSON -objekti jObj = new JSONObject (json);
} saalis (UnsupportedEncodingException e) {
e.printStackTrace (); } saalis (ProtocolException e) {e.printStackTrace (); } saalis (IOException e) {e.printStackTrace (); } saalis (JSONException e) {Log.e ("JSON -jäsennys", "Virhe jäsentäessä tietoja" + e.toString ()); } catch (Poikkeus e) {Log.e ("Exception", "Error parsing data" + e.toString ()); }
// palauta JSON -objekti
paluu jObj;
}
}
De volta a atividade princip, vamos efetuar a chamada às urls de forma assíncrona, escrevendo este código dentro do método doInBackground.
@Ohita suojattu merkkijono doInBackground (Jono… parametrit) {HttpJsonParser jsonParser = uusi 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;}
Quando o método doInBackgroundé encerrado, o control of execução do Android passage or metétodo on PostExecute. Neste metodo, vamos criar os objetos Lixeira, e popular com os dados recuperados do ThingSpeak:
suojattu void onPostExecute (merkkijonon tulos) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {
// ListView listView = (ListView) findViewById (R.id.feedList);
Näytä mainView = (Näytä) findViewById (R.id.activity_main); if (menestys == 1) {try {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira (); Lixeira feedDetails2 = uusi Lixeira (); Lixeira feedDetails3 = uusi Lixeira (); Lixeira feedDetails4 = uusi 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 -laskin = uusi SmartBinService (); calculator.montaListaLixeiras (feedList);
// Paranna komponentteja
TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll (feedList);
// Tietojen tiedot
Päivämäärä currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = uusi SimpleDateFormat ("pp/kk/vvvv"); Merkkijono currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (sovitin);
} saalis (JSONException e) {
e.printStackTrace (); }
} muuta {
Toast.makeText (MainActivity.this, "Tietojen lataamisessa tapahtui virhe", Toast. LENGTH_LONG).show ();
}
} }); }
Agora, tela inicial do aplicativo, serão listados os dados de cada lixeira.
Vaihe 7: Mostrando No Mapa
Ainda na atividade rehtorina, näytä viittaukselta uma ação a ser relacionada ao botão Mapa, na tela inicial.
/ ** Soitetaan, kun käyttäjä napauttaa Mapa -painiketta*/ public void openMaps (Näytä näkymä) {Intent aim = new Intent (this, LixeiraMapsActivity.class);
// Passa a lista de lixeiras
Bundle nippu = new Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); aim.putExtras (nippu);
startActivity (tarkoitus);
}
Ei karttaa, temos três atividades a executar:
- marcar a posição atual do caminha de lixo
- marcar os tarkat kirjeenvaihtajat ja cada lixeira no mapa
- traçar a rota entre os pontos
Käyttämällä pass passia acima -palvelua voit käyttää Google -reittiohjeiden sovellusliittymää. Ajo -ohjeiden piirtäminen kahden paikan välillä käyttämällä Google -reittiohjeita Google Mapissa Android API V2
Primeiro, vamos criar localidades para cada um dos tarkka que desejamos marcar:
// Sijainnit
yksityinen LatLng -virta;
yksityinen LatLng lixeiraA; yksityinen LatLng lixeiraB; yksityinen LatLng lixeiraC; yksityinen LatLng lixeiraD;.
Näytä kaikki mahdolliset mahdolliset kartat, jotka ovat peräisin seuraavista tavoista:
private void checkLocationandAddToMap () {// Tarkistetaan, onko käyttäjä myöntänyt luvan, jos (ActivityCompat.checkSelfPermission (tämä, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkPifest ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Sijaintiluvan pyytäminen ActivityCompat.requestPermissions (tämä, uusi merkkijono {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); palata; }
// Viimeisen tunnetun sijainnin hakeminen Fus -toiminnolla
Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);
// MarkerOptionia käytetään uuden merkin luomiseen. Voit määrittää sijainnin, otsikon jne. MarkerOptions -toiminnolla
this.current = new LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = uusi MarkerOptions (). Sijainti (nykyinen).title ("Posição atual");
// Luodun merkin lisääminen kartalle, kameran siirtäminen paikkaan
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("+++++++++++++ Passei aqui! +++++++++++++"); mMap.addMarker (markerOptions);
// Siirrä kamera välittömästi paikkaan zoomaamalla 15.
mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (nykyinen, 15));
// Lähennä, animoi kameraa.
mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation () {// Tarkistetaan, onko käyttäjä myöntänyt luvan, jos (ActivityCompat.checkSelfPermission (tämä, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission.html, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Sijaintiluvan pyytäminen ActivityCompat.requestPermissions (tämä, uusi merkkijono {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); palata; }
// Praça da Estação
kaksoisleveysaste = -19,9159578; kaksinkertainen pituusaste = -43,9387856; this.lixeiraA = uusi leveysaste (leveysaste, pituusaste);
MarkerOptions markerOptions = uusi MarkerOptions (). Sijainti (lixeiraA).title ("Lixeira A");
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_RED)); mMap.addMarker (markerOptions); }
Kuten leveysaste ja pituusaste de cada lixeira foram recuperadas através do próprio Google Maps, e deixadas fixas no código. Ihanteellinen, estes valores ficariam salvos em um banco de dados (esimerkiksi 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 tarkka:
yksityinen merkkijono getDirectionsUrl (LatLng -alkuperä, LatLng -kohde, luettelo reittipisteiden luettelo) {
// Reitin alkuperä
Merkkijono str_origin = "origin ="+origin.latitude+","+origin.longitude;
// Reitin määränpää
Merkkijono str_dest = "määränpää ="+kohde. Leveysaste ","+kohde.pituusaste;
// Reittipisteet reitin varrella
// reittipisteet=optimoi:totodellisia for (LatLng point: waypointsList) {waypoints += "|" + piste. leveyspiiri + "," + piste. pituusaste; }
// Anturi käytössä
Jousisensori = "anturi = epätosi";
// Parametrien rakentaminen verkkopalveluun
Merkkijonoparametrit = str_origin+"&"+str_dest+"&"+sensor+"&"+reittipisteet;
// Tulostusmuoto
Merkkijonoulostulo = "json";
// URL -osoitteen luominen verkkopalveluun
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; System.out.println ("++++++++++++++"+url);
paluuosoite;
}
E, por fim, juntando tudo no método princip da dalasse, 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 (); }
// Piirrä reittejä
// URL -osoitteen hakeminen Google -reittiohjeiden sovellusliittymään
Listapisteet = uusi ArrayList (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);
String url = getDirectionsUrl (nykyinen, lixeiraA, pisteet);
DownloadTask downloadTask = uusi DownloadTask (); // Aloita json -tietojen lataaminen Google Directions -sovellusliittymästä downloadTask.execute (url); }
Aqui passamos apenas pelos pontos principais. O código complete to do projeto será disponibilizado para consulta.
Vaihe 8: Conclusão
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 directta. An anime, se videon videoprojektin täydellinen, kuvassa, ja os fontit das atividades criadas ei Android.
Suositeltava:
Akustinen levitaatio Arduino Unon kanssa Askel askeleelta (8 vaihetta): 8 vaihetta
Akustinen levitaatio Arduino Unon kanssa Askel askeleelta (8 vaihetta): ultraäänikaiuttimet L298N DC-naarasadapterin virtalähde urospuolisella dc-nastalla ja analogiset portit koodin muuntamiseksi (C ++)
4G/5G HD -videon suoratoisto DJI Dronesta alhaisella latenssilla [3 vaihetta]: 3 vaihetta
4G/5G HD -videon suoratoisto DJI Dronesta alhaisella latenssilla [3 vaihetta]: Seuraava opas auttaa sinua saamaan live-HD-videovirtoja lähes mistä tahansa DJI-dronesta. FlytOS -mobiilisovelluksen ja FlytNow -verkkosovelluksen avulla voit aloittaa videon suoratoiston droonilta
Pultti - DIY -langaton latauskello (6 vaihetta): 6 vaihetta (kuvilla)
Pultti - DIY -langaton latausyökello (6 vaihetta): Induktiiviset lataukset (tunnetaan myös nimellä langaton lataus tai langaton lataus) on langattoman voimansiirron tyyppi. Se käyttää sähkömagneettista induktiota sähkön tuottamiseen kannettaville laitteille. Yleisin sovellus on langaton Qi -latauslaite
4 vaihetta akun sisäisen vastuksen mittaamiseksi: 4 vaihetta
4 vaihetta akun sisäisen vastuksen mittaamiseksi: Tässä on 4 yksinkertaista vaihetta, joiden avulla voit mitata taikinan sisäisen vastuksen
SmartBin: 4 vaihetta
SmartBin: Tämän projektin päätarkoitus on luoda elektroninen laite, joka käyttää vähintään yhtä Raspberry Pi -laitetta. Tiimiin kuuluu viisi tulevaa koneinsinööriä ja yksi automaatioinsinööri. Projektimme koostuu roskakorin valmistamisesta, joka avautuu ja sulkeutuu