Sommario:
- Passaggio 1: collegamento del sensore O
- Fase 2: Montando a Lixeira
- Passaggio 3: caricare Para a Nuvem
- Passaggio 4: Recuperando Dados Do ThingSpeak
- Passaggio 5: creazione di un'applicazione Android
- Passaggio 6: Recuperando O Feed No Android
- Step 7: Mostrando No Mapa
- Fase 8: Conclusione
Video: SmartBin: 8 passaggi
2024 Autore: John Day | [email protected]. Ultima modifica: 2024-01-31 10:21
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, è necessario:
- NodeMCU
- Sensore Ultrasonico di Distanza
- Caixa de papelão
- Protoboard
- Cabos
- Dispositivo Android
Passaggio 1: collegamento del sensore O
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:
// definisce i numeri dei pin #define pino_trigger 2 //D4
#define pino_echo 0 //D3
Per efetuare a leitura dos dados do sensor, per seguire o tutorial elaborato pelo FilipeFlop, disponível aqui.
float cmMsec, inMsec;
microsec lungo = ultrasonic.timing();
cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM);
inMsec = ultrasonic.convert(microsec, Ultrasonic::IN);
// Mostra informazioni senza monitor seriale
Serial.print("Distancia em cm: ");
Serial.print(cmMsec);
Serial.print(" - Distancia em polegadas: ");
Serial.println(inMsec);
Dati stringa = Stringa (cmMsec);
Serial.println(dati);
Fase 2: Montando a Lixeira
Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no “teto” da lixeira. Para o exemplo, usei um 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.
Per simulação, visto che non si può più avere un sensore ultrassônico, si ha un algoritmo per salvare casualmente una distanza lida e 4 lixeiras diferentes.
//Simulando 4 lixeiras
lungo lixeiraID;
ciclo vuoto() {
IDlixeira = random(1, 5);
}
Passaggio 3: caricare Para a Nuvem
Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por familiaridade com o mesmo. Primeiramente, é necessário criar um novo canal, recebendo 4 parâmetros, referentes ao volume de cada lixeira.
Pará conectar a aplicação com o ThingSpeak, é necessario salvare o número da API do canal criado. Siga os passis descritos no site oficial.
De volta à aplicação, vamos utilizza una biblioteca ESP8266WiFi.h per 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 identificatodor e a senha de sua rede).
void connectWifi(){
Serial.print("Connessione a "+ *ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
ritardo (500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connessione alla rete");
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("Leggi i dati del sensore…");
//Collegamento al Wi-Fi
connectWifi();
}
E, para 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("Inviare dati per ThingSpeak ");
String postStr = apiKey;
postStr += "&campo";
postStr += id;
postStr += "=";
postStr += String(cmMsec);
postStr += "\r\n\r\n";
Serial.println(postStr);
client.print( POST /update
client.print("Host: api.thingspeak.com\n");
client.print("Connessione: chiudi\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Lunghezza contenuto: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
ritardo(1000);
}
cliente.stop();
}
O primeiro parâmetro corrisponde alla distanza 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 identificator para qual campo será feito o upload do valor lido.
Passaggio 4: Recuperando Dados Do ThingSpeak
O ThingSpeak permite efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Come 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 informato previamente. Altre cose importanti per il progetto:
- CHANNEL_ID: número do seu canal
- FIELD_NUMBER: o número do campo
- API_KEY: un chave de API do seu canal
È un URL che serve per eseguire l'applicazione Android, per recuperare i dati di ThingSpeak.
Passaggio 5: creazione di un'applicazione Android
No Android Studio, piangi un nuovo progetto Android. Per correggere il funzionamento dell'applicazione, è necessario configurare come permessi abaixo no AndroidManifest.
Per utilizzare Google Maps, se necessario pegar uma chave junto ao Google. Siga os passi descritti no link Otter chave de API.
Uma vez com a chave, você deve também configurá-la na aplicação.
La chiave API per le API basate su Google Maps è definita come risorsa stringa.
(Vedi il file "res/values/google_maps_api.xml").
Tieni presente che la chiave API è collegata alla chiave di crittografia utilizzata per firmare l'APK. È necessaria una chiave API diversa per ogni chiave di crittografia, inclusa la chiave di rilascio utilizzata per firmare l'APK per la pubblicazione. Puoi definire le chiavi per le destinazioni di debug e rilascio in src/debug/ e src/release/.
<meta-dati
android:name="com.google.android.geo. API_KEY"
android:value="@string/google_maps_key" />
Una configurazione completa è disponibile in qualsiasi momento AndroidManifest anexado ao project.
n
Passaggio 6: Recuperando O Feed No Android
Na atividade principal no Android, MainActivity, crie 4 variáveis para identificator 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";
Para efetuar a leitura dos dados, iremos utilizar uma class do Android específica, chamada JSONObject. Mais uma vez, vamos 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.
public JSONObject makeHttpRequest (String url, metodo String, parametri mappa) {
Tentativo {
Uri. Builder builder = new Uri. Builder(); URL urlObj; String encodedParams = ""; if (params != null) { for (voce Map. Entry: params.entrySet()) { builder.appendQueryParameter(entry.getKey(), entry.getValue()); } } if (builder.build().getEncodedQuery() != null) { encodedParams = builder.build().getEncodedQuery();
}
if ("GET".uguale(metodo)) { url = url + "?" + parametri codificati; urlObj = nuovo URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(metodo);
} altro {
urlObj = nuovo URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(metodo); urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty("Content-Length", String.valueOf(encodedParams.getBytes().length)); urlConnection.getOutputStream().write(encodedParams.getBytes()); } //Connettiti al server urlConnection.connect(); //Leggi la risposta è = urlConnection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); linea di stringa;
// Analizza la risposta
while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } è chiuso(); json = sb.toString(); //Converti la risposta in JSON Object 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", "Errore durante l'analisi dei dati " + e.toString()); } catch (Exception e) { Log.e("Exception", "Errore durante l'analisi dei dati " + e.toString()); }
// restituisce l'oggetto JSON
restituire 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 protected String doInBackground(String… params) { HttpJsonParser jsonParser = new
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);
restituire null;}
Quando si esegue il metodo di esecuzione inBackground, o si controlla l'esecuzione di Android passa per il metodo su PostExecute. Neste método, vamos criar os objetos Lixeira, e popular com os dados recuperados do ThingSpeak:
protected void onPostExecute(String result) { pDialog.dismiss(); runOnUiThread(new Runnable() { public void run() {
//ListView listView =(ListView)findViewById(R.id.feedList);
Visualizza mainView =(View)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
Calcolatrice SmartBinService = new SmartBinService(); calcolatrice.montaListaLixeiras(feedList);
//Recupera componenti
TextView createDate = (TextView) mainView.findViewById(R.id.date); ListView listaDeLixeiras = (ListView) findViewById(R.id.lista); adapter.addAll(feedList);
//Dati attuali
Data currentTime = Calendar.getInstance().getTime(); SimpleDateFormat simpleDate = new SimpleDateFormat("gg/MM/aaaa"); String datacorrente = simpleDate.format(currentTime); createDate.setText(KEY_DATE + currentDate + " "); listaDeLixeiras.setAdapter(adattatore);
} catch (JSONException e) {
e.printStackTrace(); }
} altro {
Toast.makeText(MainActivity.this, "Si è verificato un errore durante il caricamento dei dati", Toast. LENGTH_LONG).show();
}
} }); }
Agora, na tela inicial do aplicativo, serão listados os dados de cada lixeira.
Step 7: Mostrando No Mapa
Ainda na atividade principal, vamos adicionar uma ação a ser relacionada ao botão Mapa, na tela inicial.
/** Chiamato quando l'utente tocca il pulsante Mapa */ public void openMaps(View view) { Intent intent = new Intent(this, LixeiraMapsActivity.class);
//Passa a lista de lixeiras
Bundle bundle = new Bundle(); bundle.putParcelableArrayList("lixeiras", feedList); intent.putExtras(pacchetto);
startActivity(intento);
}
No mapa, temos três atividades a executar:
- marcar a posição atual do caminha de lixo
- marcar os pontos corrispondenti a cada lixeira no mapa
- traçar a rota entre os pontos
Per eseguire i passaggi, è possibile utilizzare un'API Google Directions. Para desenhar as rotas, foram seguidos os passis do tutorial Disegnare le indicazioni stradali del percorso di guida tra due posizioni utilizzando Google Directions in Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
//Località
corrente LatLng privata;
latLng privato lixeiraA; latLng privato lixeiraB; latLng privato lixeiraC; privato LatLng lixeiraD;.
Para adicionar a posição atual no mapa, foi criado o método:
private void checkLocationandAddToMap() { // Verifica se l'utente ha concesso l'autorizzazione if (ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_FINE_LOCATION) != PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_COARSE_LOCATION) != PackageManager. PERMISSION_GRANTED) { //Richiesta l'autorizzazione alla posizione ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Restituzione; }
//Recupero dell'ultima posizione conosciuta usando il Fus
Posizione posizione = LocationServices. FusedLocationApi.getLastLocation(googleApiClient);
//MarkerOptions viene utilizzato per creare un nuovo Marker. Puoi specificare posizione, titolo, ecc. con MarkerOptions
this.current = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions().position(current).title("Posizione attuale");
//Aggiungendo il marker creato sulla mappa, spostando la telecamera in posizione
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_GREEN)); System.out.println("+++++++++++++ Passei aqui! ++++++++++++"); mMap.addMarker(markerOptions);
// Sposta istantaneamente la telecamera nella posizione con uno zoom di 15.
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(current, 15));
// Ingrandisci, animando la telecamera.
mMap.animateCamera(CameraUpdateFactory.zoomTo(14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation() { // Verifica se l'utente ha concesso l'autorizzazione if (ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_FINE_LOCATION) != PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android. Manifest.permission. ACCESS_COARSE_LOCATION) != PackageManager. PERMISSION_GRANTED) { //Richiesta l'autorizzazione alla posizione ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Restituzione; }
//Praça da Estação
doppia latitudine = -19,9159578; doppia longitudine = -43.9387856; this.lixeiraA = new LatLng(latitudine, longitudine);
MarkerOptions markerOptions = new MarkerOptions().position(lixeiraA).title("Lixeira A");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_RED)); mMap.addMarker(markerOptions); }
Come 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 salvas em um banco de dados (per esempio Firebase). Será a primeira evolução deste projeto!
O último passo agora é traçar as rotas entre os pontos. Per questo, 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){
// Origine del percorso
String str_origin = "origin="+origin.latitude+", "+origin.longitude;
// Destinazione del percorso
String str_dest = "destination="+dest.latitude+", "+dest.longitude;
//Waypoint lungo il percorso
//waypoint=optimize:true|-19.9227365, -43.9473546|-19.9168006, -43.9361124 Waypoint stringa = "waypoint=optimize:true"; for (LatLng point: waypointsList){ waypoint += "|" + punto.latitudine + ", " + punto.longitudine; }
// Sensore abilitato
Sensore stringa = "sensore=falso";
// Costruire i parametri per il servizio web
Parametri stringa = str_origin+"&"+str_dest+"&"+sensor + "&" + waypoint;
// Formato di output
Uscita stringa = "json";
// Costruire l'URL del servizio web
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; System.out.println("++++++++++++++ "+url);
URL di ritorno;
}
E, por fim, juntando tudo no método principal da classe, 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(); }
//Disegna percorsi
// Ottenere l'URL per l'API di Google Directions
Elenco punti = new ArrayList(); points.add(lixeiraB); points.add(lixeiraC); points.add(lixeiraD);
String url = getDirectionsUrl(current, lixeiraA, points);
DownloadTask downloadTask = new DownloadTask(); // Inizia a scaricare i dati json dall'API di Google Directions downloadTask.execute(url); }
Aqui passamos apenas pelos pontos principais. O código completo do projeto será disponibilizado para consulta.
Fase 8: Conclusione
Estendi il tuo progetto trabalando i concetti di IoT, mostrando tutte le varie opzioni di connessione dispositivi che attraversano il nuovo, ed effettivamente tutte le decisioni sem interferência umana diretta. Inoltre, segue il video del progetto completo, per l'illustrazione, e le fonti di attività non sono disponibili su Android.
Consigliato:
Come realizzare un'antenna doppia biQuade 4G LTE Semplici passaggi: 3 passaggi
Come realizzare un'antenna doppia biQuade 4G LTE Semplici passaggi: La maggior parte delle volte che ho affrontato, non ho una buona potenza del segnale per i miei lavori quotidiani. Così. Cerco e provo diversi tipi di antenna ma non funziona. Dopo aver perso tempo ho trovato un'antenna che spero di realizzare e testare, perché è principio costruttivo non
Rilevamento del volto su Raspberry Pi 4B in 3 passaggi: 3 passaggi
Rilevamento del volto su Raspberry Pi 4B in 3 passaggi: In questo Instructable eseguiremo il rilevamento del volto su Raspberry Pi 4 con Shunya O/S utilizzando la libreria Shunyaface. Shunyaface è una libreria di riconoscimento/rilevamento facciale. Il progetto mira a raggiungere la massima velocità di rilevamento e riconoscimento con
Specchio per il trucco fai-da-te in semplici passaggi (usando le strisce luminose a LED): 4 passaggi
Specchio per il trucco fai-da-te in semplici passaggi (usando le strisce luminose a LED): in questo post, ho realizzato uno specchio per il trucco fai-da-te con l'aiuto delle strisce LED. Sono davvero fantastici e devi provarli anche tu
Gioca a Doom sul tuo iPod in 5 semplici passaggi!: 5 passaggi
Gioca a Doom sul tuo iPod in 5 semplici passaggi!: una guida passo passo su come eseguire il dual-boot di Rockbox sul tuo iPod per giocare a Doom e a dozzine di altri giochi. È qualcosa di veramente facile da fare, ma molte persone rimangono stupite quando mi vedono giocare a doom sul mio iPod e si confondono con le istruzioni
SmartBin: 4 passaggi
SmartBin: Lo scopo principale di questo progetto è creare un dispositivo elettronico che utilizzi almeno un Raspberry Pi. Il team è composto da 5 futuri ingegneri meccanici e un ingegnere dell'automazione. Il nostro progetto consiste nel realizzare un bidone della spazzatura che si apre e si chiude