Innholdsfortegnelse:
- Trinn 1: Conectando O -sensor
- Trinn 2: Montando a Lixeira
- Trinn 3: Last opp Para a Nuvem
- Trinn 4: Recuperando Dados Do ThingSpeak
- Trinn 5: Criando og Aplicação Android
- Trinn 6: Recuperando O Feed Ingen Android
- Trinn 7: Mostrando No Mapa
- Trinn 8: Konklusjon
Video: SmartBin: 8 trinn
2024 Forfatter: John Day | [email protected]. Sist endret: 2024-01-31 10:23
Este é um projeto para um system inteligente de coletas, no qual os caminhões de lixo recebem dados das lixeiras, identifierando 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
- Sensor Ultrassônico de Distancia
- Caixa de papelão
- Protoboard
- Caboer
- Dispositivo Android
Trinn 1: Conectando O -sensor
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:
// definerer pinnetall #definer 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.
flyte cmMsec, inMsec;
lang mikrosek = ultralyd.timing ();
cmMsec = ultralyd.konvertering (mikrosek, ultralyd:: CM);
inMsec = ultrasonic.convert (mikrosek, ultralyd:: IN);
// Exibe informerer ingen seriell skjerm
Serial.print ("Distancia em cm:");
Serial.print (cmMsec);
Serial.print (" - Distancia em polegadas:");
Serial.println (inMsec);
String data = String (cmMsec);
Serial.println (data);
Trinn 2: Montando a Lixeira
Agora, vamos montar a lixeira inteligente. Presisaremos conectar o sensor ultrassônico no “teto” da lixeira. For eksempel kan du bruke en cabo e fita isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. No meu caso, foi de 26, 3cm. Esse é o valor que considerarmos para uma lixeira vazia.
Para simulação, visto que não possuo mais de um sensor ultrassônico, foi feito um algoritmo para salvar randomicamente a distancia lida em 4 lixeiras diferentes.
// Simulando 4 lixeiras
lang lixeiraID;
void loop () {
lixeiraID = tilfeldig (1, 5);
}
Trinn 3: Last opp Para a Nuvem
Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, av kjent informasjon om en mesmo. Primeiramente, é necessário criar um novo canal, recebendo 4 parâmetros, referentes ao volume de cada lixeira.
Pará conectar a aplicação com ThingSpeak, en nødvendighet salvar eller número da API for canal criado. Siga os passos descritos no site oficial.
De volta à aplicação, vamos utilizar 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 identifierador e a senha de sua rede).
void connectWifi () {
Serial.print ("Koble til"+ *ssid);
WiFi. Begynner (ssid, pass);
mens (WiFi.status ()! = WL_CONNECTED) {
forsinkelse (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.
ugyldig oppsett () {
Serial.begin (9600);
Serial.println ("Lendo dados do sensor …");
// Conectando ao Wi-Fi
connectWifi ();
}
E, for 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, long id) {
if (client.connect (server, 80)) {
Serial.println ("Enviando dados para o ThingSpeak");
String postStr = apiKey;
postStr += "& field";
postStr += id;
postStr += "=";
postStr += String (cmMsec);
postStr += "\ r / n / r / n";
Serial.println (postStr);
client.print ("POST /oppdater HTTP /1.1 / n");
client.print ("Vert: api.thingspeak.com / n");
client.print ("Tilkobling: lukk / n");
client.print ("X-THINGSPEAKAPIKEY:" + apiKey + "\ n");
client.print ("Innholdstype: application/x-www-form-urlencoded / n");
client.print ("Content-Length:");
client.print (postStr.length ());
client.print ("\ n / n");
client.print (postStr);
forsinkelse (1000);
}
client.stop ();
}
O primeiro parâmetro correspondonde à 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 fora identifierar para qual campo será feito o upload to valor lido.
Trinn 4: Recuperando Dados Do ThingSpeak
O ThingSpeak tillater 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 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 canal
- FIELD_NUMBER: o nåmero do campo
- API_KEY: en chave de API do seu -kanal
Det er en URL som kan brukes av Android, for gjenoppretting av ting fra ThingSpeak.
Trinn 5: Criando og Aplicação Android
Ingen Android Studio, crie um novo projeto Android. Para o correto funcionamento da aplicação, é nødvendigvis konfigurer as permissionsões abaixo no AndroidManifest.
For å bruke Google Maps, er det nødvendig å laste ned Google. Vi kan ikke beskrive noen lenker.
Uma vez com a chave, você deve também configurá-la na aplicação.
API-nøkkelen for Google Maps-baserte APIer er definert som en strengressurs.
(Se filen "res/values/google_maps_api.xml").
Vær oppmerksom på at API -nøkkelen er koblet til krypteringsnøkkelen som ble brukt til å signere APK. Du trenger en annen API -nøkkel for hver krypteringsnøkkel, inkludert utgivelsesnøkkelen som brukes til å signere APK -en for publisering. Du kan definere nøklene for feilsøkings- og utgivelsesmålene i src/debug/og src/release/.
<metadata
android: name = "com.google.android.geo. API_KEY"
android: value = "@string /google_maps_key" />
En konfigurasjon som er fullstendig for AndroidManifest, og som også kan brukes.
n
Trinn 6: Recuperando O Feed Ingen Android
På hoveddel ingen Android, MainActivity, crie 4 varianter for identifikasjon av ting du kan gjøre ting Speak 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 utilizar uma classe do Android específica, chamada JSONObject. Mais uma vez, vamos criar um objeto for 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 or objeto JSON montado.
public JSONObject makeHttpRequest (String url, String method, Map params) {
prøv {
Uri. Builder builder = ny 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 = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metode);
} annet {
urlObj = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metode); urlConnection.setRequestProperty ("Innholdstype", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). skrive (encodedParams.getBytes ()); } // Koble til serveren urlConnection.connect (); // Les svaret er = urlConnection.getInputStream (); BufferedReader reader = new BufferedReader (new InputStreamReader (is)); StringBuilder sb = new StringBuilder (); String linje;
// Analyser svaret
while ((line = reader.readLine ())! = null) {sb.append (line + "\ n"); } er nært(); json = sb.toString (); // Konverter svaret til JSON Object jObj = nytt JSONObject (json);
} catch (UnsupportedEncodingException e) {
e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Error parsing data" + e.toString ()); } catch (Unntak e) {Log.e ("Unntak", "Feil ved analyse av data" + e.toString ()); }
// returner JSON Object
retur 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 beskyttet String doInBackground (String … params) {HttpJsonParser jsonParser = new 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);
returner null;}
Quando o método doInBackgroundé encerrado, or control de execução to Android passa para o método onPostExecute. Neste método, vamos criar os objetos Lixeira, e popular com us dados recuperados do ThingSpeak:
protected void onPostExecute (String result) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {
// ListView listView = (ListView) findViewById (R.id.feedList);
View mainView = (Vis) findViewById (R.id.activity_main); if (success == 1) {try {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira (); Lixeira feedDetails2 = ny Lixeira (); Lixeira feedDetails3 = ny Lixeira (); Lixeira feedDetails4 = ny 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 kalkulator = ny SmartBinService (); kalkulator.montaListaLixeiras (feedList);
// Recupera componentes
TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll (feedList);
// Data atual
Date currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = ny SimpleDateFormat ("dd/MM/åååå"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adapter);
} fangst (JSONException e) {
e.printStackTrace (); }
} annet {
Toast.makeText (MainActivity.this, "Noen feil oppstod under lasting av data", Toast. LENGTH_LONG).show ();
}
} }); }
Agora, in tela inicial do aplicativo, serão listados os dados de cada lixeira.
Trinn 7: Mostrando No Mapa
Ainda na atividade rektor, kan også fortelle om en ação a ser relacionada ao botão Mapa, and tela inicial.
/ ** Ringes når brukeren trykker på Mapa -knappen*/ public void openMaps (View view) {Intent intention = new Intent (this, LixeiraMapsActivity.class);
// Passa a list de lixeiras
Bundle bundle = new Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); intention.putExtras (bunt);
startActivity (intention);
}
Ingen mapa, temos três atividades en executar:
- marcar a posição atual do caminha de lixo
- marcar os pontos correspondentes a cada lixeira no mapa
- traçar a rota entre os pontos
For utførelse av passos acima, bruker vi et API Google Directions. Para desenhar as rotas, foram seguidos os passos do do tutorial Tegne kjøreveibeskrivelser mellom to steder ved hjelp av Google Veibeskrivelse i Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
// Steder
privat LatLng gjeldende;
private LatLng lixeiraA; private LatLng lixeiraB; private LatLng lixeiraC; private LatLng lixeiraD;.
Para adicionar a posição atual no mapa, foi criado o método:
private void checkLocationandAddToMap () {// Sjekker om brukeren har gitt tillatelsen hvis (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Be om plasseringstillatelsen ActivityCompat.requestPermissions (denne, nye strengen {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); komme tilbake; }
// Henter den siste kjente plasseringen ved hjelp av Fus
Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);
// MarkerOptions brukes til å lage en ny Marker. Du kan angi plassering, tittel osv. Med MarkerOptions
this.current = ny LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = new MarkerOptions (). Position (current).title ("Posição atual");
// Legger til den opprettede markøren på kartet, flytter kameraet til posisjon
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("++++++++++++++ Passei aqui! ++++++++++++"); mMap.addMarker (markerOptions);
// Flytt kameraet umiddelbart til stedet med en zoom på 15.
mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (nåværende, 15));
// Zoom inn, animere kameraet.
mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation () {// Kontrollerer om brukeren har gitt tillatelse til hvis (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (this, android.per.mission.est. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Be om beliggenhetstillatelsen ActivityCompat.requestPermissions (denne, nye strengen {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); komme tilbake; }
// Praça da Estação
dobbel breddegrad = -19,9159578; dobbel lengdegrad = -43,9387856; this.lixeiraA = ny LatLng (breddegrad, lengdegrad);
MarkerOptions markerOptions = new MarkerOptions (). Posisjon (lixeiraA).title ("Lixeira A");
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_RED)); mMap.addMarker (markerOptions); }
Som posições de latitude e longitude de cada lixeira foram recuperadas através do próprio Google Maps, e deixadas fixas no código. Idealmente, estes valores ficariam salvos em um banco de dados (for eksempel Firebase). Será a primeira evolução deste projeto!
O último passo agora é traçar as rotas entre os pontos. Para tal, om conceito muito importante, e que será utilizado next projeto, eller våre veipunkter!
Foi criado um método para traçar a rota entre dois dados pontos:
private String getDirectionsUrl (LatLng -opprinnelse, LatLng -dest, List waypointsList) {
// Rutens opprinnelse
String str_origin = "origin ="+origin.latitude+","+origin.longitude;
// Destinasjon for rute
String str_dest = "destinasjon ="+dest.breddegrad+","+dest.lengdegrad;
// Veipunkter langs ruten
//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; for (LatLng -punkt: waypointsList) {waypoints += "|" + point.latitude + "," + point.longitude; }
// Sensor aktivert
String sensor = "sensor = false";
// Bygg parametrene til webtjenesten
Stringparametere = str_origin+"&"+str_dest+"&"+sensor+"&"+veipunkter;
// Utgående format
String output = "json";
// Bygger nettadressen til webtjenesten
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parametere; System.out.println ("++++++++++++++"+url);
retur url;
}
E, por fim, juntando tudo no método principal da classe, onMapReady:
@Override public void onMapReady (GoogleMap googleMap) {mMap = googleMap;
checkLocationandAddToMap ();
hvis (lixeirasList.get (0).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE
|| lixeirasList.get (0).getPesoLixo ()-10> Lixeira. MIN_SIZE_GARBAGE) {addBinALocation (); } hvis (lixeirasList.get (1).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (1).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinBLocation (); } hvis (lixeirasList.get (2).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (2).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinCLocation (); } hvis (lixeirasList.get (3).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (3).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinDLocation (); }
// Tegn ruter
// Få URL til Google Directions API
Listepunkter = ny ArrayList (); poeng. legge til (lixeiraB); poeng. legge til (lixeiraC); poeng. legge til (lixeiraD);
String url = getDirectionsUrl (current, lixeiraA, poeng);
DownloadTask downloadTask = ny DownloadTask (); // Start nedlasting av json -data fra Google Directions API downloadTask.execute (url); }
Aqui passamos apenas pelos pontos principais. O código completeo do projeto será disponibilizado para consulta.
Trinn 8: Konklusjon
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 direta. Em anexo, segue um vídeo do projeto completeo, for ilustração and e os fontes das atividades criadas no Android.
Anbefalt:
Arduino bilvarslingssystem for omvendt parkering - Trinn for trinn: 4 trinn
Arduino Car Reverse Parking Alert System | Trinn for trinn: I dette prosjektet skal jeg designe en enkel Arduino Car Reverse Parking Sensor Circuit ved hjelp av Arduino UNO og HC-SR04 Ultrasonic Sensor. Dette Arduino -baserte bilreverseringssystemet kan brukes til autonom navigasjon, robotavstand og andre områder
Trinn for trinn PC -bygging: 9 trinn
Steg for trinn PC -bygging: Rekvisita: Maskinvare: HovedkortCPU & CPU -kjøler PSU (strømforsyningsenhet) Lagring (HDD/SSD) RAMGPU (ikke nødvendig) CaseTools: Skrutrekker ESD -armbånd/mathermal pasta m/applikator
Tre høyttalerkretser -- Trinn-for-trinn opplæring: 3 trinn
Tre høyttalerkretser || Trinn-for-trinn opplæring: Høyttalerkretsen styrker lydsignalene som mottas fra miljøet til MIC og sender den til høyttaleren der forsterket lyd produseres. Her vil jeg vise deg tre forskjellige måter å lage denne høyttalerkretsen på:
RC -sporet robot ved hjelp av Arduino - Trinn for trinn: 3 trinn
RC -sporet robot ved bruk av Arduino - Steg for trinn: Hei folkens, jeg er tilbake med et annet kult Robot -chassis fra BangGood. Håper du har gått gjennom våre tidligere prosjekter - Spinel Crux V1 - Gesture Controlled Robot, Spinel Crux L2 - Arduino Pick and Place Robot with Robotic Arms og The Badland Braw
SmartBin: 4 trinn
SmartBin: Hovedformålet med dette prosjektet er å lage en elektronisk enhet som bruker minst en Raspberry Pi. Teamet består av 5 fremtidige mekaniske ingeniører og en automatiseringsingeniør. Prosjektet vårt består av å lage en søppelbøtte som åpner og lukker