Innehållsförteckning:
- Steg 1: Conectando O -sensor
- Steg 2: Montando a Lixeira
- Steg 3: Ladda upp Para a Nuvem
- Steg 4: Recuperando Dados Do ThingSpeak
- Steg 5: Criando och Aplicação Android
- Steg 6: Recuperando O Feed Ingen Android
- Steg 7: Mostrando No Mapa
- Steg 8: Slutsats
Video: SmartBin: 8 steg
2024 Författare: John Day | [email protected]. Senast ändrad: 2024-01-31 10:25
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, é needsário:
- NodeMCU
- Sensor Ultrassônico de Distancia
- Caixa de papelão
- Protoboard
- Cabos
- Dispositivo Android
Steg 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:
// definierar pin -nummer #definiera 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.
flyta cmMsec, inMsec;
lång mikrosek = ultraljud.timing ();
cmMsec = ultrasonic.convert (mikrosek, ultraljud:: CM);
inMsec = ultrasonic.convert (mikrosek, ultraljud:: IN);
// Exibe informacoes no serial monitor
Serial.print ("Distancia em cm:");
Serial.print (cmMsec);
Serial.print (" - Distancia em polegadas:");
Serial.println (inMsec);
Strängdata = String (cmMsec);
Serial.println (data);
Steg 2: Montando a Lixeira
Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no “teto” da lixeira. Exemplo, utilizei um cabo e fita isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. Inget 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
lång lixeiraID;
void loop () {
lixeiraID = slumpmässigt (1, 5);
}
Steg 3: Ladda upp 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 of ThingSpeak, é needsário salvar of número da API do canal criado. Siga os passos descritos ingen webbplats 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 ("Ansluter till"+ *ssid);
WiFi. Börjar (ssid, pass);
medan (WiFi.status ()! = WL_CONNECTED) {
fördröjning (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 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 /uppdatera HTTP /1.1 / n");
client.print ("Värd: api.thingspeak.com / n");
client.print ("Anslutning: stäng / 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);
fördröjning (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 para identifierar para qual campo será feito o ladda upp valor lido.
Steg 4: Recuperando Dados Do ThingSpeak
O ThingSpeak tillåter 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 ingen länk informado previamente. Os mais importantes para o projeto são:
- CHANNEL_ID: numero do seu canal
- FIELD_NUMBER: o número do campo
- API_KEY: en chave de API do seu -kanal
Det finns en webbadress som kan användas för Android, för att återhämta oss från ThingSpeak.
Steg 5: Criando och Aplicação Android
Ingen Android Studio, crie um novo projeto Android. Para o correto funcionamento da aplicação, é needsário configurar as permissões abaixo no AndroidManifest.
Para utilizar o Google Maps, será needsário pegar uma chave junto ao Google. Vi kan inte skriva några länkar Observera att API.
Uma vez com a chave, você deve também configurá-la na aplicação.
API-nyckeln för Google Maps-baserade API: er definieras som en strängresurs.
(Se filen "res/values/google_maps_api.xml").
Observera att API -nyckeln är länkad till krypteringsnyckeln som används för att signera APK. Du behöver en annan API -nyckel för varje krypteringsnyckel, inklusive releasenyckeln som används för att signera APK för publicering. Du kan definiera nycklarna för felsöknings- och släppmålen i src/debug/och src/release/.
<metadata
android: name = "com.google.android.geo. API_KEY"
android: value = "@string /google_maps_key" />
En konfiguration som är komplett för AndroidManifest anexado ao projeto.
n
Steg 6: Recuperando O Feed Ingen Android
Na atividade principal no Android, MainActivity, crie 4 variáveis fora identifierar cada um dos canais do Thing Speak a serem lidos:
privat String url_a = "https://api.thingspeak.com/channels/429823/fields/1/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; privat String url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; privat String url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; privat 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 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 or objeto JSON montado.
public JSONObject makeHttpRequest (String url, String method, Map params) {
Prova {
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 (metod);
} annat {
urlObj = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metod); urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). write (encodedParams.getBytes ()); } // Anslut till servern urlConnection.connect (); // Läs svaret är = urlConnection.getInputStream (); BufferedReader reader = new BufferedReader (new InputStreamReader (is)); StringBuilder sb = new StringBuilder (); Stränglinje;
// Analysera svaret
medan ((line = reader.readLine ())! = null) {sb.append (rad + "\ n"); } är nära(); json = sb.toString (); // Konvertera svaret till JSON Object jObj = nytt JSONObject (json);
} catch (UnsupportedEncodingException e) {
e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Error parsing data" + e.toString ()); } catch (Undantag e) {Log.e ("Undantag", "Fel vid analys av data" + e.toString ()); }
// return JSON Object
återvända 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 skyddad 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);
returnera 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 os dados recuperados do ThingSpeak:
skyddad void onPostExecute (strängresultat) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {
// ListView listView = (ListView) findViewById (R.id.feedList);
Visa mainView = (Visa) 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 -räknare = ny SmartBinService (); calculator.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 = nytt SimpleDateFormat ("dd/MM/åååå"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adapter);
} fånga (JSONException e) {
e.printStackTrace (); }
} annat {
Toast.makeText (MainActivity.this, "Ett fel uppstod när data laddades", Toast. LENGTH_LONG).show ();
}
} }); }
Agora, na tela inicial do aplicativo, serão listados os dados de cada lixeira.
Steg 7: Mostrando No Mapa
Ainda na atividade principal, vi kan också ta reda på om det är möjligt att göra en karta, men inte officiellt.
/ ** Kallas när användaren trycker på Mapa -knappen*/ public void openMaps (View view) {Intent intention = new Intent (this, LixeiraMapsActivity.class);
// Passa a lista de lixeiras
Bundle bundle = new Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); intention.putExtras (bunt);
startActivity (intention);
}
Inga mapa, temos três atividades en exekutör:
- 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
För att utföra våra lösenord kan vi använda API: s Google Directions. Para desenhar as rotas, foram seguidos os passos do to tutorial Rita körvägsanvisningar mellan två platser med Google Directions i Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
// Platser
privat LatLng ström;
privat LatLng lixeiraA; privat LatLng lixeiraB; privat LatLng lixeiraC; privat LatLng lixeiraD;.
Para adicionar a posição atual no mapa, foi criado o método:
private void checkLocationandAddToMap () {// Kontrollerar om användaren har beviljat tillståndet om (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (Android. Manifest.permission. ACCESS_FINE_LOCATION)! ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Begär platstillstånd ActivityCompat.requestPermissions (denna, nya sträng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); lämna tillbaka; }
// Hämtar den senaste kända platsen med Fus
Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);
// MarkerOptions används för att skapa en ny markör. Du kan ange plats, titel etc. med MarkerOptions
this.current = new LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = new MarkerOptions (). Position (current).title ("Posição atual");
// Lägga till den skapade markören på kartan, flytta kameran till position
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("++++++++++++++ Passei aqui! +++++++++++++"); mMap.addMarker (markerOptions);
// Flytta kameran direkt till platsen med en zoom på 15.
mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (aktuell, 15));
// Zooma in, animera kameran.
mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation () {// Kontrollerar om användaren har beviljat tillståndet om (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (denna, android. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Begär platstillstånd ActivityCompat.requestPermissions (denna, nya sträng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); lämna tillbaka; }
// Praça da Estação
dubbel latitud = -19,9159578; dubbel longitud = -43,9387856; this.lixeiraA = ny LatLng (latitud, longitud);
MarkerOptions markerOptions = new MarkerOptions (). Position (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 (exemplo 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 next projeto, uso Waypoints!
Foi criado um método para traçar a rota entre dois dados pontos:
private String getDirectionsUrl (LatLng -ursprung, LatLng -dest, List waypointsList) {
// Ruttens ursprung
String str_origin = "origin ="+origin.latitude+","+origin.longitude;
// Destination av rutt
String str_dest = "destination ="+dest.latitud+","+dest.longitud;
// Waypoints längs rutten
//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; för (LatLng -punkt: waypointsList) {waypoints += "|" + point.latitude + "," + point.longitude; }
// Sensor aktiverad
Strängsensor = "sensor = falsk";
// Bygga parametrarna till webbtjänsten
Strängparametrar = str_origin+"&"+str_dest+"&"+sensor+"&"+waypoints;
// Utmatningsformat
Strängutgång = "json";
// Bygga webbadressen till webbtjänsten
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parametrar; System.out.println ("++++++++++++++"+url);
retururl;
}
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 (); }
// Rita rutter
// Få URL till Google Directions API
Listpunkter = ny ArrayList (); poäng.add (lixeiraB); poäng.add (lixeiraC); poäng.add (lixeiraD);
String url = getDirectionsUrl (aktuell, lixeiraA, poäng);
DownloadTask downloadTask = new DownloadTask (); // Börja ladda ner json -data från Google Directions API downloadTask.execute (url); }
Aqui passamos apenas pelos pontos principais. O código completeo do projeto será disponibilizado para consulta.
Steg 8: Slutsats
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, para ilustração, e os fontes das atividades criadas no Android.
Rekommenderad:
Arduino Car Reverse Parking Alert System - Steg för steg: 4 steg
Arduino Car Reverse Parking Alert System | Steg för steg: I det här projektet kommer jag att utforma en enkel Arduino Car Reverse Parking Sensor Circuit med Arduino UNO och HC-SR04 Ultrasonic Sensor. Detta Arduino -baserade bilomvändningsvarningssystem kan användas för autonom navigering, robotavstånd och andra
Steg för steg PC -byggnad: 9 steg
Steg för steg PC -byggnad: Tillbehör: Hårdvara: ModerkortCPU & CPU -kylarePSU (strömförsörjningsenhet) Lagring (HDD/SSD) RAMGPU (krävs inte) CaseTools: Skruvmejsel ESD -armband/mathermisk pasta med applikator
Tre högtalarkretsar -- Steg-för-steg handledning: 3 steg
Tre högtalarkretsar || Steg-för-steg-handledning: Högtalarkretsen förstärker ljudsignalerna som tas emot från miljön till MIC och skickar den till högtalaren varifrån förstärkt ljud produceras. Här visar jag dig tre olika sätt att göra denna högtalarkrets med:
Akustisk levitation med Arduino Uno Steg-för-steg (8-steg): 8 steg
Akustisk levitation med Arduino Uno Steg-för-steg (8-steg): ultraljudsgivare L298N Dc kvinnlig adapter strömförsörjning med en manlig DC-pin Arduino UNOBreadboardHur det fungerar: Först laddar du upp kod till Arduino Uno (det är en mikrokontroller utrustad med digital och analoga portar för att konvertera kod (C ++)
SmartBin: 4 steg
SmartBin: Huvudsyftet med detta projekt är att skapa en elektronisk enhet som använder minst en Raspberry Pi. Teamet består av 5 framtida mekaniska ingenjörer och en automationsingenjör. Vårt projekt består av att göra en papperskorg som öppnar och stänger