Isi kandungan:

SmartBin: 8 Langkah
SmartBin: 8 Langkah

Video: SmartBin: 8 Langkah

Video: SmartBin: 8 Langkah
Video: Xiaomi Band 8 Unboxing - It's Not Just A Bracelet Anymore! 2024, November
Anonim
SmartBin
SmartBin

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, perlu:

  • NodeMCU
  • Sensor Ultrassônico de Distancia
  • Caixa de papelão
  • Papan Protob
  • Cabos
  • Dispositivo Android

Langkah 1: Sensor Conectando O

Primeiramente, vamos efetuar a conexão entre o sensor ultrassônico e o NODEMCU. Sebagai tanto, conectar vamos sebagai porta mencetuskan echo do sensor nas portas D4 e D3 do NodeMCU:

// mentakrifkan nombor pin #menentukan pino_trigger 2 // D4

#tentukan pino_echo 0 // D3

Para efetuar a leitura dos dados do sensor, juga seguido o tutorial elaborado pelo FilipeFlop, disponível aqui.

terapung cmMsec, inMsec;

panjang mikro = ultrasonik.timing ();

cmMsec = ultrasonic.convert (microsec, Ultrasonic:: CM);

inMsec = ultrasonic.convert (microsec, Ultrasonic:: IN);

// Exibe informacoes tiada monitor bersiri

Serial.print ("Distancia em cm:");

Serial.print (cmMsec);

Serial.print ("- Distancia em polegadas:");

Serial.println (dalamMsec);

Data rentetan = Rentetan (cmMsec);

Serial.println (data);

Langkah 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no “teto” da lixeira. Sebagai contoh, gunakan isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. Tanpa meu caso, juga 26, 3cm. Esse é o valor que mempertimbangkanarmos para uma lixeira vazia.

Para simulação, visto que não possuo mais de um sensor ultrassônico, juga feito um algoritmo para salvar randomicamente a distancia lida em 4 lixeiras diferentes.

// Simulando 4 lixeiras

lixeiraID panjang;

gelung kosong () {

lixeiraID = rawak (1, 5);

}

Langkah 3: Muat naik Para a Nuvem

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, daripada familiar comade mes o mesmo. Primeiramente, canal umri novo canal, recebendo 4 parâmetros, referentes ao volume de cada lixeira.

Pará conectar a aplicação com o ThingSpeak, perlu Salvar o número da API do canal criado. Siga os passos descritos tiada laman rasmi.

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).

batal connectWifi () {

Serial.print ("Menyambung ke" + * ssid);

WiFi.begin (ssid, lulus);

sementara (WiFi.status ()! = WL_CONNECTED) {

kelewatan (500);

Cetakan bersiri (".");

}

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.

batal persediaan () {

Serial.begin (9600);

Serial.println ("Lendo dados do sensor…");

// Conectando ao Wi-Fi

sambungWifi ();

}

E, para enviar os dados para o ThingSpeak, basta abrir uma conexão HTTP padrão, passando o número da API dan os parâmetros.

batal sendDataTS (apungan cmMsec, panjang id) {

jika (client.connect (pelayan, 80)) {

Serial.println ("Enviando dados para o ThingSpeak");

String postStr = apiKey;

postStr + = "& bidang";

postStr + = id;

postStr + = "=";

postStr + = Rentetan (cmMsec);

postStr + = "\ r / n / r / n";

Serial.println (postStr);

client.print ("POST / kemas kini HTTP / 1.1 / n");

client.print ("Host: api.thingspeak.com / n");

client.print ("Sambungan: tutup / n");

client.print ("X-THINGSPEAKAPIKEY:" + apiKey + "\ n");

client.print ("Content-Type: application / x-www-form-urlencoded / n");

client.print ("Panjang Kandungan:");

client.print (postStr.length ());

client.print ("\ n / n");

client.print (postStr);

kelewatan (1000);

}

pelanggan.stop ();

}

O primeiro parâmetro koresponden à 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 melayani também para identificar para qual campo será feito o upload do valor lido.

Langkah 4: Recuperando Dados Do ThingSpeak

O ThingSpeak izin efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Sebagai diferentes opções para leitura melakukan 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: terusan número do seu
  • FIELD_NUMBER: o número do campo
  • API_KEY: saluran chave de API do seu

Ini adalah URL que será lida do aplicativa Android, para recuperar os dados do ThingSpeak.

Langkah 5: Criando a Aplicação Android

Tanpa Android Studio, crie um novo projeto Android. Para o correto funcionamento da aplicação, perlu konfigurasi sebagai izin abaixo no AndroidManifest.

Para pengguna Peta Google, será requá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.

Kunci API untuk API berasaskan Peta Google didefinisikan sebagai sumber rentetan.

(Lihat fail "res / values / google_maps_api.xml").

Perhatikan bahawa kunci API dihubungkan dengan kunci penyulitan yang digunakan untuk menandatangani APK. Anda memerlukan kunci API yang berbeza untuk setiap kunci penyulitan, termasuk kunci pelepasan yang digunakan untuk menandatangani APK untuk penerbitan. Anda boleh menentukan kunci untuk sasaran debug dan rilis dalam src / debug / dan src / release /.

<meta-data

android: name = "com.google.android.geo. API_KEY"

android: value = "@ string / google_maps_key" />

Konfigurasi yang sesuai untuk Android, Manifest anexado ao projeto.

n

Langkah 6: Recuperando O Feed Tanpa Android

Na atividade principal no Android, MainActivity, crie 4 variáveis para identificar cada um dos canais do ThingBeritahu serid lidos:

rentetan peribadi url_a = "https://api.thingspeak.com/channels/429823/fields/1/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; rentetan peribadi url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; rentetan peribadi url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; rentetan peribadi 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:

JSONObjectjectLixeiraA; JSONObjectjectLixeiraB; JSONObjectjectLixeiraC; JSONObject responsLixeiraD;

Para abrir a conexão com sebagai url, 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) {

cuba {

Pembangun Uri. Builder = Uri. Builder baru (); URL urlObj; String encodedParams = ""; if (params! = null) {untuk (Map. Entry entri: params.entrySet ()) {builder.appendQueryParameter (entry.getKey (), entry.getValue ()); }} if (builder.build (). getEncodedQuery ()! = null) {encodedParams = builder.build (). getEncodedQuery ();

}

jika ("GET". sama (kaedah)) {url = url + "?" + Param dikodkan; urlObj = URL baru (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (kaedah);

} lain {

urlObj = URL baru (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (kaedah); urlConnection.setRequestProperty ("Content-Type", "application / x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). panjang)); urlConnection.getOutputStream (). tulis (encodedParams.getBytes ()); } // Sambungkan ke pelayan urlConnection.connect (); // Baca jawapannya ialah = urlConnection.getInputStream (); Pembaca BufferedReader = BufferedReader baru (InputStreamReader baru (adalah)); StringBuilder sb = StringBuilder baru (); Garisan tali;

// Luruskan tindak balas

sementara ((line = reader.readLine ())! = null) {sb.append (baris + "\ n"); } ialah.tutup (); json = sb.toString (); // Tukarkan tindak balas ke Objek JSON jObj = JSONObject baru (json);

} tangkapan (UnsupportedEncodingException e) {

e.printStackTrace (); } tangkapan (ProtocolException e) {e.printStackTrace (); } tangkapan (IOException e) {e.printStackTrace (); } tangkapan (JSONException e) {Log.e ("JSON Parser", "Ralat menguraikan data" + e.toString ()); } tangkapan (Pengecualian e) {Log.e ("Pengecualian", "Ralat menguraikan data" + e.toString ()); }

// kembali Objek JSON

kembali 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 dilindungi String doInBackground (String… params) {HttpJsonParser jsonParser = HttpJsonParser baru ();

responsLixeiraA = jsonParser.makeHttpRequest (url_a, "GET", null);

responsLixeiraB = jsonParser.makeHttpRequest (url_b, "GET", null); responsLixeiraC = jsonParser.makeHttpRequest (url_c, "GET", null); responsLixeiraD = jsonParser.makeHttpRequest (url_d, "GET", null);

kembali kosong;}

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 recuperados com os dados yang popular melakukan perkara yang Bercakap:

void dilindungi onPostExecute (Hasil rentetan) {pDialog.dismiss (); runOnUiThread (Runnable baru () {public void run () {

// ListView listView = (ListView) findViewById (R.id.feedList);

Lihat mainView = (Lihat) findViewById (R.id.activity_main); jika (kejayaan == 1) {cuba {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = Lixeira baru (); Lixeira feedDetails2 = Lixeira baru (); Lixeira feedDetails3 = Lixeira baru (); Lixeira feedDetails4 = Lixeira baru ();

feedDetails1.setId ('A');

feedDetails1.setPesoLixo (Double.parseDouble (responsLixeiraA.getString (KEY_FIELD1))); feedDetails1.setVolumeLixo (Double.parseDouble (ResponsLixeiraA.getString (KEY_FIELD1)));

feedDetails2.setId ('B');

feedDetails2.setPesoLixo (Double.parseDouble (ResponsLixeiraB.getString (KEY_FIELD2))); feedDetails2.setVolumeLixo (Double.parseDouble (ResponsLixeiraB.getString (KEY_FIELD2)));

feedDetails3.setId ('C');

feedDetails3.setPesoLixo (Double.parseDouble (ResponsLixeiraC.getString (KEY_FIELD3))); feedDetails3.setVolumeLixo (Double.parseDouble (ResponsLixeiraC.getString (KEY_FIELD3)));

feedDetails4.setId ('D');

feedDetails4.setPesoLixo (Double.parseDouble (ResponsLixeiraD.getString (KEY_FIELD4))); feedDetails4.setVolumeLixo (Double.parseDouble (ResponsLixeiraD.getString (KEY_FIELD4)));

feedList.add (feedDetails1);

feedList.add (feedDetails2); feedList.add (feedDetails3); feedList.add (feedDetails4);

// Calcula dados das lixeiras

Kira SmartBinService = SmartBinService baru (); kalkulator.montaListaLixeiras (feedList);

// Recupera komponen

TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll (feedList);

// Data secara automatik

Date currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = SimpleDateFormat baru ("dd / MM / yyyy"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (penyesuai);

} tangkapan (JSONException e) {

e.printStackTrace (); }

} lain {

Toast.makeText (MainActivity.this, "Beberapa ralat berlaku semasa memuatkan data", Toast. LENGTH_LONG).show ();

}

} }); }

Agora, na tela inicial do aplicativo, serão listados os dados de cada lixeira.

Langkah 7: Mostrando No Mapa

Mostrando No Mapa
Mostrando No Mapa

Ainda na atividade prinsipal, vamos adicionar uma ação a ser relacionada ao botão Mapa, na tela inicial.

/ ** Dipanggil semasa pengguna mengetuk butang Mapa * / public void openMaps (View view) {Intent intent = Intent baru (ini, LixeiraMapsActivity.class);

// Passa a lista de lixeiras

Bundle bundle = Bundle baru (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (bundle);

startActivity (niat);

}

Tidak ada ayah, temos ini membezakan seorang pelaksana:

  1. marcar a posição atual do caminha de lixo
  2. koresponden marcar os pontos a cada lixeira no mapa
  3. traçar a rota entre os pontos

Para pelaksana os passos acima, vamos menggunakan API Petunjuk Google. Para desenhar as rotas, foram seguidos os passos do tutorial Melukis arah laluan pemanduan antara dua lokasi menggunakan Google Petunjuk di Google Map Android API V2

Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:

// Lokasi

LatLng peribadi semasa;

LatLng lixeiraA peribadi; LatLng lixeiraB peribadi; LatLng lixeiraC peribadi; LatLng lixeiraD peribadi;.

Sebagai tambahan dan positif, tidak ada mapa, juga criado o método:

periksa kekosongan peribadiLocationandAddToMap () {// Memeriksa sama ada pengguna telah memberikan kebenaran sekiranya (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (ini, android. Android. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Meminta kebenaran Lokasi ActivityCompat.requestPermissions (ini, String baru {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); kembali; }

// Mengambil lokasi terakhir yang diketahui menggunakan Fus

Lokasi lokasi = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);

// MarkerOptions digunakan untuk membuat Marker baru. Anda boleh menentukan lokasi, tajuk dll dengan MarkerOptions

this.current = LatLng baru (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = MarkerOptions baru (). Kedudukan (semasa). Tajuk ("Posição atual");

// Menambahkan penanda yang dibuat di peta, memindahkan kamera ke kedudukan

markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("+++++++++++++ Passei aqui! ++++++++++++++"); mMap.addMarker (markerOptions);

// Pindahkan kamera seketika ke lokasi dengan zoom 15.

mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (semasa, 15));

// Zum masuk, animasikan kamera.

mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, null);

}

Em seguida, para cada lixeira, foram criados métodos serupa dengan abaixo:

private void addBinALocation () {// Memeriksa sama ada pengguna telah memberikan kebenaran jika (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED & ActivityCompat.checkSelfPermission (ini, android. Manifest.per. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Meminta kebenaran Lokasi ActivityCompat.requestPermissions (ini, String baru {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); kembali; }

// Praça da Estação

garis lintang berganda = -19.9159578; bujur dua kali = -43.9387856; this.lixeiraA = LatLng baru (garis lintang, garis bujur);

MarkerOptions markerOptions = kedudukan MarkerOptions baru (). (LixeiraA).title ("Lixeira A");

markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_RED)); mMap.addMarker (markerOptions); }

Sebagai kedudukan lintang dan garis bujur 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 (por exemplo Firebase). Será a primeira evolução deste projeto!

Oltimo passo agora é traçar sebagai rotas entre os pontos. Sebaliknya, um confito 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:

String getDirectionsUrl peribadi (LatLng asal, LatLng dest, List waypointsList) {

// Asal laluan

String str_origin = "origin =" + origin.latitude + "," + origin.longitude;

// Destinasi laluan

String str_dest = "destination =" + dest.latitude + "," + dest.longitude;

// Titik arah di sepanjang laluan

//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; untuk (Titik LatLng: waypointsList) {waypoints + = "|" + point.latitude + "," + point.longitude; }

// Sensor diaktifkan

Sensor rentetan = "sensor = false";

// Membangun parameter ke perkhidmatan web

Parameter rentetan = str_origin + "&" + str_dest + "&" + sensor + "&" + titik jalan;

// Format output

Output rentetan = "json";

// Membangunkan url ke perkhidmatan web

Rentetan url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameter; System.out.println ("++++++++++++++" + url);

mengembalikan url;

}

E, por fim, juntando tudo no método principal da classe, onMapReady:

@ Override public void onMapReady (GoogleMap googleMap) {mMap = googleMap;

checkLocationandAddToMap ();

jika (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 (); }

// Lukis laluan

// Mendapatkan URL ke API Petunjuk Google

Titik senarai = ArrayList baru (); points.add (lixeiraB); points.add (lixeiraC); poin.add (lixeiraD);

String url = getDirectionsUrl (semasa, lixeiraA, mata);

DownloadTask downloadTask = DownloadTask baru (); // Mula memuat turun data json dari Google Arah API downloadTask.execute (url); }

Aqui passamos apenas pelos pontos Principais. O código completeo do projeto será disponibilizado para consulta.

Langkah 8: Kesimpulannya

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.

Disyorkan: