Table des matières:
- Étape 1: Conectando O Sensor
- Étape 2: Montando a Lixeira
- Étape 3: Télécharger Para a Nuvem
- Étape 4: Recuperando Dados Do ThingSpeak
- Étape 5: Criando a Aplicação Android
- Étape 6: Recuperando O Feed No Android
- Étape 7: Mostando No Mapa
- Étape 8: Conclusion
Vidéo: SmartBin : 8 étapes
2024 Auteur: John Day | [email protected]. Dernière modifié: 2024-01-31 10:19
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 up nas informações.
Para montar este projeto, é necessário:
- NodeMCU
- Capteur Ultrassônico de Distancia
- Caixa de papelão
- Protoboard
- Cabos
- Dispositif Android
Étape 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:
// définit les numéros de broches #define 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.
flottant cmMsec, inMsec;
long microsec = ultrasonic.timing();
cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM);
inMsec = ultrasonic.convert(microsec, Ultrasonic::IN);
//Exibe informacoes pas de moniteur série
Serial.print("Distancia em cm: ");
Serial.print(cmMsec);
Serial.print(" - Distancia em polegadas: ");
Serial.println(inMsec);
Données de chaîne = Chaîne(cmMsec);
Serial.println(données);
Étape 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.
Para simulação, visto que não possuo mais de um sensor ultrassônico, foi feito um algoritmo para salvar randomicamente a distance lida em 4 lixeiras diferentes.
//Simulando 4 lixeiras
longue lixeiraID;
boucle vide() {
lixeiraID = aléatoire(1, 5);
}
Étape 3: Télécharger 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, é necessário salvar o número da API do canal criado. Siga os passos descritos aucun site officiel.
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, conflicto o identificador e a senha de sua rede).
void connectWifi(){
Serial.print("Connexion à "+ *ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
retard (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…");
// Connexion au Wi-Fi
connectWifi();
}
E, par enviar os dados para o ThingSpeak, basta ouvrir uma conexão HTTP padrão, passer o número da API e os paramètres.
void sendDataTS(float cmMsec, long id){
if (client.connect(serveur, 80)) {
Serial.println("Envoyer des données pour ThingSpeak ");
Chaîne postStr = apiKey;
postStr += "&champ";
postStr += id;
postStr += "=";
postStr += String(cmMsec);
postStr += "\r\n\r\n";
Serial.println(postStr);
client.print( POST /mise à jour
client.print("Hôte: api.thingspeak.com\n");
client.print("Connexion: fermer\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Type de contenu: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
retard(1000);
}
client.stop();
}
O primeiro parâmetro corresponde à 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 identificar para qual campo será feito o upload do valor lido.
Étape 4: Recuperando Dados Do ThingSpeak
O ThingSpeak permite efetuar leitura dos dados do seu canal, atraves de um serviço retornando um JSON. Comme 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. Les éléments les plus importants pour le projet sont:
- CHANNEL_ID: canal número do seu
- FIELD_NUMBER: o número do campo
- API_KEY: une chave de API do seu canal
Esta é une URL que será lida do aplicativa Android, para recuperar os dodos do ThingSpeak.
Étape 5: Criando a Aplicação Android
Pas d'Android Studio, crie um novo projeto Android. Para o correto funcionamento da aplicação, é necessário configurar as permitões abaixo no AndroidManifest.
Pour utiliser Google Maps, será necessário pegar uma chave junto ao Google. Siga os passos descritos no link Obter chave de API.
Uma vez com a chave, você deve também configurá-la na aplicação.
La clé API pour les API basées sur Google Maps est définie comme une ressource de chaîne.
(Voir le fichier "res/values/google_maps_api.xml").
Notez que la clé API est liée à la clé de chiffrement utilisée pour signer l'APK. Vous avez besoin d'une clé API différente pour chaque clé de chiffrement, y compris la clé de version qui est utilisée pour signer l'APK pour la publication. Vous pouvez définir les clés des cibles de débogage et de libération dans src/debug/ et src/release/.
<méta-données
android:name="com.google.android.geo. API_KEY"
android:value="@string/google_maps_key" />
Une configuration complète est à partir de l'arquivo AndroidManifest anexado ao projeto.
m
Étape 6: Recuperando O Feed No Android
Na atividade principal no Android, MainActivity, crie 4 variáveis para identificar cada um dos canais do ThingSpeak a serem lidos:
chaîne privée url_a = "https://api.thingspeak.com/channels/429823/fields/1/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; chaîne privée url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; chaîne privée url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; chaîne privée 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:
Réponse JSONObjectLixeiraA; Réponse JSONObjectLixeiraB; Réponse de l'objet JSONLixeiraC; Réponse de l'objet JSONLixeiraD;
Pour ouvrir un conexão com comme URL, vamos usar criar uma classe auxiliaire, chamada HttpJsonParser. Esta classe será responsável por ouvrir uma conexão com um URL, efetuar leitura dos dados encontrados, e retornar o objecto JSON montado.
public JSONObject makeHttpRequest (URL de chaîne, méthode de chaîne, paramètres de carte) {
essayer {
Uri. Builder builder = new Uri. Builder(); URL urlObj; Chaîne encodedParams = ""; if (params != null) { for (entrée Map. Entry: params.entrySet()) { builder.appendQueryParameter(entry.getKey(), entry.getValue()); } } if (builder.build().getEncodedQuery() != null) { encodedParams = builder.build().getEncodedQuery();
}
if ("GET".equals(method)) { url = url + "?" + paramètres encodés; urlObj = nouvelle URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(method);
} autre {
urlObj = nouvelle URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(method); urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty("Content-Length", String.valueOf(encodedParams.getBytes().length)); urlConnection.getOutputStream().write(encodedParams.getBytes()); } //Connexion au serveur urlConnection.connect(); //Lire la réponse est = urlConnection.getInputStream(); Lecteur BufferedReader = new BufferedReader(nouveau InputStreamReader(is)); StringBuilder sb = new StringBuilder(); Ligne de chaîne;
//Analyser la réponse
while ((ligne = reader.readLine()) != null) { sb.append(ligne + "\n"); } est près(); json = sb.toString(); //Convertir la réponse en 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", "Error parsing data " + e.toString()); } catch (Exception e) { Log.e("Exception", "Erreur d'analyse des données " + e.toString()); }
// renvoie l'objet JSON
retourner 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);
renvoie null;}
Quando o método doInBackgroundé encerrado, o controle de execução do Android passa para o método onPostExecute. 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);
Voir 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
Calculatrice SmartBinService = new SmartBinService(); calculateur.montaListaLixeiras(feedList);
//Récupérer les composants
TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll(feedList);
//Données réelles
Date currentTime = Calendar.getInstance().getTime(); SimpleDateFormat simpleDate = new SimpleDateFormat("jj/MM/aaaa"); String currentDate = simpleDate.format(currentTime); createDate.setText(KEY_DATE + currentDate + " "); listaDeLixeiras.setAdapter(adaptateur);
} catch (JSONException e) {
e.printStackTrace(); }
} autre {
Toast.makeText(MainActivity.this, "Une erreur s'est produite lors du chargement des données", Toast. LENGTH_LONG).show();
}
} }); }
Agora, na tela inicial do aplicativo, serão listados os dados de cada lixeira.
Étape 7: Mostando No Mapa
Ainda na atividade principal, vamos adicionar uma ação a ser relacionada ao botão Mapa, na tela inicial.
/** Appelé lorsque l'utilisateur appuie sur le bouton 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); intention.putExtras(paquet);
startActivity(intention);
}
No mapa, temos três atividades a executar:
- marcar a posição atual do caminha de lixo
- marcar os pontos correspondantes a cada lixeira no mapa
- traçar a rota entre os pontos
Para executar os passos acima, vamos usar a API Google Directions. Para desenhar as rotas, foram seguidos os passos do tutorial Dessin d'itinéraires routiers entre deux emplacements à l'aide de Google Directions dans Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
//Emplacements
courant LatLng privé;
privé LatLng lixeiraA; privé LatLng lixeiraB; privé LatLng lixeiraC; privé LatLng lixeiraD;.
Para adicionar a posição atual no mapa, foi criado o método:
private void checkLocationandAddToMap() { //Vérification si l'utilisateur a accordé l'autorisation 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) { //Demande de l'autorisation de localisation ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); revenir; }
//Récupération du dernier emplacement connu en utilisant le Fus
Emplacement de l'emplacement = LocationServices. FusedLocationApi.getLastLocation(googleApiClient);
// Les MarkerOptions sont utilisées pour créer un nouveau Marker. Vous pouvez spécifier l'emplacement, le titre, etc. avec MarkerOptions
this.current = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions().position(current).title("Position atual");
//Ajout du marqueur créé sur la carte, déplacement de la caméra vers la position
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_GREEN)); System.out.println("++++++++++++++ Passei aqui! ++++++++++++++"); mMap.addMarker(markerOptions);
// Déplacez la caméra instantanément vers l'emplacement avec un zoom de 15.
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(current, 15));
// Zoom avant, animation de la caméra.
mMap.animateCamera(CameraUpdateFactory.zoomTo(14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation() { //Vérification si l'utilisateur a accordé l'autorisation 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) { //Demande de l'autorisation de localisation ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); revenir; }
//Praça da Estação
double latitude = -19,9159578; double longitude = -43,9387856; this.lixeiraA = new LatLng(latitude, longitude);
MarkerOptions markerOptions = new MarkerOptions().position(lixeiraA).title("Lixeira A");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_RED)); mMap.addMarker(markerOptions); }
Comme posições de latitude et longitude de cada lixeira foram recuperadas atraves do próprio Google Maps, e deixadas fixas no código. Idealmente, estes valores ficariam salvos em um banco de dados (par exemple Firebase). Será a primeira evolução deste projeto!
O último passo agora é traçar as rotas entre os pontos. Para tal, um conceito muito important, 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 (origine LatLng, destination LatLng, liste waypointsList){
// Origine du parcours
String str_origin = "origin="+origin.latitude+", "+origin.longitude;
// Destination de l'itinéraire
String str_dest = "destination="+dest.latitude+", "+dest.longitude;
//Points de cheminement le long de l'itinéraire
//waypoints=optimize:true|-19.9227365, -43.9473546|-19.9168006, -43.9361124 String waypoints = "waypoints=optimize:true"; pour (point LatLng: waypointsList){ waypoints += "|" + point.latitude + ", " + point.longitude; }
// Capteur activé
Capteur de chaîne = "sensor=false";
// Construire les paramètres du service Web
Paramètres de chaîne = str_origin+"&"+str_dest+"&"+sensor + "&" + waypoints;
// Format de sortie
Sortie de chaîne = "json";
// Construction de l'url du service web
URL de chaîne = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; System.out.println("++++++++++++++++ "+url);
URL de retour;
}
E, por fim, juntando tudo no método principal da classe, onMapReady:
@Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap;
vérifierEmplacementetAjouteràMap();
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(); }
//Tracer des itinéraires
// Obtenir l'URL de l'API Google Directions
Points de liste = new ArrayList(); points.add(lixeiraB); points.add(lixeiraC); points.add(lixeiraD);
URL de chaîne = getDirectionsUrl(current, lixeiraA, points);
DownloadTask downloadTask = new DownloadTask(); // Commencer à télécharger les données json à partir de l'API Google Directions downloadTask.execute(url); }
Aqui passamos apenas pelos pontos principais. O código completo do projeto será disponibilizado para consulta.
Étape 8: Conclusion
Este foi um projeto trabalhando conceitos de IoT, mostrando uma das varias opções de conectar dispositivos atraves da nuvem, efetuar tomada 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.
Conseillé:
Comment fabriquer une antenne double biquade 4G LTE en quelques étapes faciles : 3 étapes
Comment créer une antenne double biquade 4G LTE Étapes faciles : La plupart du temps, je n'ai pas une bonne force de signal pour mes travaux quotidiens. Donc. Je recherche et essaye différents types d'antenne mais ne fonctionne pas. Après une perte de temps, j'ai trouvé une antenne que j'espère fabriquer et tester, car ce n'est pas un principe de construction
Game Design dans Flick en 5 étapes : 5 étapes
Game Design dans Flick en 5 étapes : Flick est un moyen très simple de créer un jeu, en particulier quelque chose comme un puzzle, un roman visuel ou un jeu d'aventure
Système d'alerte de stationnement en marche arrière Arduino - Étapes par étape : 4 étapes
Système d'alerte de stationnement en marche arrière Arduino | Étapes par étape : dans ce projet, je vais concevoir un circuit de capteur de stationnement inversé pour voiture Arduino simple à l'aide d'un capteur à ultrasons Arduino UNO et HC-SR04. Ce système d'alerte de marche arrière basé sur Arduino peut être utilisé pour une navigation autonome, une télémétrie de robot et d'autres r
Détection de visage sur Raspberry Pi 4B en 3 étapes : 3 étapes
Détection de visage sur Raspberry Pi 4B en 3 étapes : dans ce Instructable, nous allons effectuer une détection de visage sur Raspberry Pi 4 avec Shunya O/S en utilisant la bibliothèque Shunyaface. Shunyaface est une bibliothèque de reconnaissance/détection de visage. Le projet vise à atteindre la vitesse de détection et de reconnaissance la plus rapide avec
SmartBin : 4 étapes
SmartBin : Le but principal de ce projet est de créer un appareil électronique qui utilise au moins un Raspberry Pi. L'équipe est composée de 5 futurs ingénieurs mécaniciens et d'un ingénieur automation. Notre projet consiste à fabriquer une poubelle qui s'ouvre et se ferme