Indholdsfortegnelse:
- Trin 1: Conectando O -sensor
- Trin 2: Montando a Lixeira
- Trin 3: Upload Para a Nuvem
- Trin 4: Recuperando Dados Do ThingSpeak
- Trin 5: Criando og Aplicação Android
- Trin 6: Recuperando O Feed Ingen Android
- Trin 7: Mostrando No Mapa
- Trin 8: Konklusion
Video: SmartBin: 8 trin
2024 Forfatter: John Day | [email protected]. Sidst ændret: 2024-01-31 10:18
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, é needário:
- NodeMCU
- Sensor Ultrassônico de Distancia
- Caixa de papelão
- Protoboard
- Caboer
- Dispositivo Android
Trin 1: Conectando O -sensor
Primeiramente, vamos efetuar a conexão entre o sensor ultrassônico e o NODEMCU. Parat tanto, vamos conectar as portas trigger e echo do sensor nas portas D4 e D3 do NodeMCU:
// definerer pins numre #definer pino_trigger 2 // D4
#define pino_echo 0 // D3
For at få vist, hvad der skal gøres til sensor, kan du se en vejledning til udarbejdelse af FilipeFlop, disponível aqui.
flyde cmMsec, inMsec;
lang mikrosek = ultralyd.timing ();
cmMsec = ultralyd. konvertering (mikrosek, ultralyd:: CM);
inMsec = ultrasonic.convert (mikrosek, ultralyd:: IN);
// Exibe informerer ingen seriel skærm
Serial.print ("Distancia em cm:");
Serial.print (cmMsec);
Serial.print (" - Distancia em polegadas:");
Serial.println (inMsec);
Strengdata = String (cmMsec);
Serial.println (data);
Trin 2: Montando a Lixeira
Agora, vamos montar a lixeira inteligente. Præcisaremos conectar o sensor ultrassônico no “teto” da lixeira. Som eksempel kan du bruge cabo e fita isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. Ingen 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 = tilfældig (1, 5);
}
Trin 3: Upload Para a Nuvem
Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, af bekendtgjort kom o mesmo. Primeiramente, é necessário criar um novo canal, recebendo 4 parâmetros, referentes ao volume de cada lixeira.
For at kontekst og aplicação com ThingSpeak, er det nødvendigt at bruge eller bruge API til 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 identificador e a senha de sua rede).
void connectWifi () {
Serial.print ("Opretter forbindelse til"+ *ssid);
WiFi. Begynd (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 ());
}
Varighed af opsætning, kan også bruges sammen med en løsning.
ugyldig opsætning () {
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) {
hvis (client.connect (server, 80)) {
Serial.println ("Enviando dados para o ThingSpeak");
String postStr = apiKey;
postStr += "& felt";
postStr += id;
postStr += "=";
postStr += String (cmMsec);
postStr += "\ r / n / r / n";
Serial.println (postStr);
client.print ("POST /opdater HTTP /1.1 / n");
client.print ("Host: api.thingspeak.com / n");
client.print ("Forbindelse: tæt / n");
client.print ("X-THINGSPEAKAPIKEY:" + apiKey + "\ n");
client.print ("Indholdstype: application/x-www-form-urlencoded / n");
client.print ("Indholdslængde:");
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.
Trin 4: Recuperando Dados Do ThingSpeak
O ThingSpeak tillader efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Som 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: numero do seu -kanal
- FIELD_NUMBER: o número do campo
- API_KEY: en chave de API do seu -kanal
Esta er en URL, der kan bruges til Android, til genbrug af ting fra ThingSpeak.
Trin 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.
Til brug for Google Maps, kan du også bruge Google til at chave. Vi kan ikke beskrive noget link Obser chave de API.
Uma vez com a chave, você deve também configurá-la na aplicação.
API-nøglen til Google Maps-baserede API'er er defineret som en strengressource.
(Se filen "res/værdier/google_maps_api.xml").
Bemærk, at API -nøglen er knyttet til den krypteringsnøgle, der bruges til at signere APK. Du skal bruge en anden API -nøgle til hver krypteringsnøgle, inklusive udgivelsesnøglen, der bruges til at signere APK'en til udgivelse. Du kan definere nøglerne til fejlfindings- og frigivelsesmålene i src/debug/og src/release/.
<meta-data
android: name = "com.google.android.geo. API_KEY"
android: value = "@string /google_maps_key" />
En konfiguration, der fuldstændigt kan bruges til AndroidManifest anexado ao projeto.
n
Trin 6: Recuperando O Feed Ingen Android
På hoveddel ingen Android, MainActivity, crie 4 varianter til identifikation af ting, der kan gø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";
For at få vist flere oplysninger, kan du også bruge en klasse til Android, herunder 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, String method, Map params) {
prøve {
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 ()); }} hvis (builder.build (). getEncodedQuery ()! = null) {encodedParams = builder.build (). getEncodedQuery ();
}
hvis ("GET".equals (metode)) {url = url + "?" + kodedeParams; urlObj = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metode);
} andet {
urlObj = ny URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metode); urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). skrive (encodedParams.getBytes ()); } // Opret forbindelse til serverens urlConnection.connect (); // Læs svaret er = urlConnection.getInputStream (); BufferedReader reader = new BufferedReader (new InputStreamReader (is)); StringBuilder sb = ny StringBuilder (); String linje;
// Parse svaret
mens ((line = reader.readLine ())! = null) {sb.append (linje + "\ n"); } er.close (); json = sb.toString (); // Konverter svaret til JSON Object jObj = nyt JSONObject (json);
} fangst (UnsupportedEncodingException e) {
e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } fangst (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Fejl ved parsing af data" + e.toString ()); } catch (Undtagelse e) {Log.e ("Undtagelse", "Fejl ved parsing af data" + e.toString ()); }
// returner JSON Object
vende tilbage 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 streng doInBackground (streng … params) {HttpJsonParser jsonParser = ny 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, o 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:
beskyttet void onPostExecute (resultat af streng) {pDialog.dismiss (); runOnUiThread (new Runnable () {public void run () {
// ListView listView = (ListView) findViewById (R.id.feedList);
Vis 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 -lommeregner = ny SmartBinService (); lommeregner.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);
} fang (JSONException e) {
e.printStackTrace (); }
} andet {
Toast.makeText (MainActivity.this, "Nogle fejl opstod under indlæsning af data", Toast. LENGTH_LONG).show ();
}
} }); }
Agora, in tela inicial do aplicativo, serão listados os dados de cada lixeira.
Trin 7: Mostrando No Mapa
Ainda na atividade principal, vi kan også fortælle, at det er muligt at genkende Mapa, og det er officielt.
/ ** Opkaldes, når brugeren 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 (bundt);
startActivity (intention);
}
Ingen mapa, temos três atividades en eksekutø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
Til udførelse af passos acima, kan vi også bruge en API Google Directions. Para desenhar as rotas, foram seguidos os passos do tutorial Tegning af kørselsvejledning mellem to steder ved hjælp af Google Rutevejledning i Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
//Placeringer
privat LatLng nuværende;
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 () {// Kontrollerer, om brugeren har givet tilladelsen, hvis (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Anmodning om tilladelse til placering ActivityCompat.requestPermissions (denne, nye streng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Vend tilbage; }
// Henter den sidste kendte placering ved hjælp af Fus
Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);
// MarkerOptions bruges til at oprette en ny Marker. Du kan angive placering, titel osv. Med MarkerOptions
this.current = ny LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = new MarkerOptions (). Position (current).title ("Posição atual");
// Tilføjelse af den oprettede markør på kortet, flytte kameraet til position
markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("++++++++++++++ Passei aqui! +++++++++++++"); mMap.addMarker (markerOptions);
// Flyt kameraet øjeblikkeligt til placeringen med en zoom på 15.
mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (nuværende, 15));
// Zoom ind, animér kameraet.
mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos lignende ao abaixo:
private void addBinALocation () {// Kontrollerer, om brugeren har givet tilladelsen, hvis (ActivityCompat.checkSelfPermission (dette, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (denne, android.per.mission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Anmodning om tilladelse til placering ActivityCompat.requestPermissions (denne, nye streng {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); Vend tilbage; }
// Praça da Estação
dobbelt breddegrad = -19,9159578; dobbelt længdegrad = -43,9387856; this.lixeiraA = ny LatLng (breddegrad, længdegrad);
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 (f.eks. 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 os Waypoints!
Foi criado um método para traçar a rota entre dois dados pontos:
private String getDirectionsUrl (LatLng -oprindelse, LatLng -dest, List waypointsList) {
// Rutens oprindelse
String str_origin = "origin ="+origin.latitude+","+origin.longitude;
// Destination af rute
String str_dest = "destination ="+dest.breddegrad+","+dest.længdegrad;
// Waypoints 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 aktiveret
Stringsensor = "sensor = falsk";
// Opbygning af parametrene til webtjenesten
Stringparametre = str_origin+"&"+str_dest+"&"+sensor+"&"+waypoints;
// Outputformat
String output = "json";
// Opbygning af url til webtjenesten
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parametre; System.out.println ("++++++++++++++"+url);
return 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
// Hent URL til Google Directions API
Listepunkter = ny ArrayList (); point.add (lixeiraB); point.add (lixeiraC); point.add (lixeiraD);
String url = getDirectionsUrl (nuværende, lixeiraA, point);
DownloadTask downloadTask = ny DownloadTask (); // Start med at downloade 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.
Trin 8: Konklusion
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, se om videoklip til fuldstændige, para ilustração, og os skrifttyper das atividades criadas ingen Android.
Anbefalede:
Arduino bil omvendt parkering alarmsystem - Trin for trin: 4 trin
Arduino bil omvendt parkering alarmsystem. Trin for trin: I dette projekt vil jeg designe en simpel Arduino bil omvendt parkeringssensorkreds ved hjælp af Arduino UNO og HC-SR04 ultralydssensor. Dette Arduino -baserede bilomvendt alarmsystem kan bruges til en autonom navigation, robotafstand og andre rækkevidde
Trin for trin pc -bygning: 9 trin
Trin for trin PC Building: Supplies: Hardware: MotherboardCPU & CPU -køler PSU (strømforsyningsenhed) Opbevaring (HDD/SSD) RAMGPU (ikke påkrævet) CaseTools: Skruetrækker ESD -armbånd/mathermal pasta m/applikator
Tre højttalerkredsløb -- Trin-for-trin vejledning: 3 trin
Tre højttalerkredsløb || Trin-for-trin vejledning: Højttalerkredsløb styrker lydsignalerne, der modtages fra miljøet til MIC og sender det til højttaleren, hvorfra forstærket lyd produceres. Her vil jeg vise dig tre forskellige måder at lave dette højttalerkredsløb på:
Akustisk levitation med Arduino Uno trin for trin (8 trin): 8 trin
Akustisk levitation med Arduino Uno Step-by Step (8-trin): ultralyds lydtransducere L298N Dc kvindelig adapter strømforsyning med en han-DC-pin Arduino UNOBreadboard Sådan fungerer det: Først uploader du kode til Arduino Uno (det er en mikrokontroller udstyret med digital og analoge porte til konvertering af kode (C ++)
SmartBin: 4 trin
SmartBin: Hovedformålet med dette projekt er at oprette en elektronisk enhed, der bruger mindst en Raspberry Pi. Teamet består af 5 fremtidige mekaniske ingeniører og en automatiseringsingeniør. Vores projekt består i at lave en skraldespand, der åbner og lukker