جدول المحتويات:

SmartBin: 8 خطوات
SmartBin: 8 خطوات

فيديو: SmartBin: 8 خطوات

فيديو: SmartBin: 8 خطوات
فيديو: Изучите 8-шаговую практическую методологию решения проблем Toyota. 2024, شهر نوفمبر
Anonim
SmartBin
SmartBin

Este é um projeto para um sistema inteligente de coletas، no qual os caminhões de lixo recebem dados das lixeiras، selectando quantidade de lixo present em cada uma delas، e uma rota de coleta traçada، com base nas informações recuperadas.

Para montar este projeto، é Requário:

  • NodeMCU
  • جهاز الاستشعار Ultrassônico de Distancia
  • كايكسا دي بابيلاو
  • بروتوبورد
  • كابوس
  • Dispositivo Android

الخطوة 1: مستشعر Conectando O

Primeiramente ، vamos efetuar a conexão Entre o sensor ultrassônico e o NODEMCU. Para tanto ، vamos conectar كمشغل Portas e echo do sensor nas portas D4 e D3 do NodeMCU:

// يحدد أرقام المسامير #define pino_trigger 2 // D4

#define pino_echo 0 // D3

الفقرة efetuar a leitura dos dados do sensor، foi seguido o التعليمية المتطورة pelo FilipeFlop، disponível aqui.

تعويم cmMsec ، inMsec ؛

ميكروسيك طويل = ultrasonic.timing () ؛

cmMsec = تحويل فوق صوتي (ميكروسيك ، فوق صوتي:: سم) ؛

inMsec = ultrasonic.convert (ميكروسيك ، فوق صوتي:: IN) ؛

// Exibe informacoes بدون شاشة تسلسلية

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

المسلسل المطبوع (سم مسك) ؛

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

Serial.println (inMsec) ؛

بيانات السلسلة = String (cmMsec) ؛

Serial.println (بيانات) ؛

الخطوة 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 المعزل. Em seguida، temos que medir a distância inicial، para saber o valor para a lixeira vazia. كاسو نو ميو ، foi de 26 ، 3 سم. Esse é o valor que lookingarmos para uma lixeira vazia.

الفقرة simulação ، visto que não posuo mais de um sensor ultrassônico ، foi feito um algoritmo para salvar randomicamente a distancia em 4 lixeiras diferentes.

// Simulando 4 lixeiras

طويل lixeiraID ؛

حلقة فارغة() {

lixeiraID = عشوائي (1 ، 5) ؛

}

الخطوة 3: تحميل Para a Nuvem

Agora، precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak ، من خلال وسائل مألوفة. Primeiramente ، é ضرورة قناة criar um novo ، recebendo 4 parâmetros ، refentes ao volume de cada lixeira.

Pará conectar a aplicação com o ThingSpeak، é implário salvar o número da API do canal criado. Siga os passos descritos no site oficial.

De volta à aplicação، vamos useizar 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).

connectWifi باطل () {

Serial.print ("الاتصال بـ" + * ssid) ؛

WiFi.begin (ssid ، تمرير) ؛

بينما (WiFi.status ()! = WL_CONNECTED) {

تأخير (500) ؛

Serial.print (".") ؛

}

Serial.println ("") ؛

Serial.print ("Conectado na rede") ؛

Serial.println (ssid) ؛

Serial.print ("IP:") ؛

Serial.println (WiFi.localIP ()) ؛

}

إعداد Durante o ، tentamos efetuar a conexão com a rede.

الإعداد باطل() {

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.

sendDataTS باطل (عائم cmMsec ، معرّف طويل) {

إذا (client.connect (الخادم ، 80)) {

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

سلسلة postStr = apiKey ؛

postStr + = "& field"؛

postStr + = معرف ؛

postStr + = "=" ؛

postStr + = String (cmMsec) ؛

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

Serial.println (postStr) ؛

client.print ("POST / update HTTP / 1.1 / n") ؛

client.print ("المضيف: api.thingspeak.com / n") ؛

client.print ("الاتصال: إغلاق / n") ؛

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

client.print ("نوع المحتوى: application / x-www-form-urlencoded / n") ؛

client.print ("طول المحتوى:") ؛

client.print (postStr.length ()) ؛

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

client.print (postStr) ؛

تأخير (1000) ؛

}

client.stop () ؛

}

O Primeiro Parâmetro تتوافق مع المسافات مع أجهزة الاستشعار فائقة السرعة. O segundo parâmetro é o ID da lixeira que foi lida (que foi gerado randomicamente، um número de 1 a 4).

بطاقة التعريف da lixeira تخدم também para identificar para qual campo será feito o upload do valor lido.

الخطوة 4: Recuperando Dados Do ThingSpeak

O ThingSpeak يسمح بـ efetuar leitura dos dados do seu canal، através de um serviço retornando um JSON. نظرًا لأن عمليات التشغيل المختلفة التي تقوم بها الفقرة leitura تقوم بإطعام قناة seu ، فقد تم تحديد الوصف المائي:

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. أهمية نظام التشغيل بالنسبة لمشروع ساو:

  • CHANNEL_ID: قناة número do seu
  • FIELD_NUMBER: o número do campo
  • API_KEY: API chave de seu canal

Esta é a URL que será lida do aplicativa Android ، لاستعادة نظام التشغيل dados do ThingSpeak.

الخطوة 5: Criando a Aplicação Android

لا يوجد Android Studio ، crie um novo projeto Android. الفقرة o correto funcionamento da aplicação، é implário configurar as permissões abaixo no AndroidManifest.

استخدام جزء من خرائط Google ، يجب أن يكون هذا هو الحال بالنسبة إلى 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.

يتم تعريف مفتاح API لواجهات برمجة التطبيقات المستندة إلى خرائط Google على أنه مورد سلسلة.

(راجع ملف "res / القيم / google_maps_api.xml").

لاحظ أن مفتاح API مرتبط بمفتاح التشفير المستخدم لتوقيع APK. أنت بحاجة إلى مفتاح API مختلف لكل مفتاح تشفير ، بما في ذلك مفتاح الإصدار المستخدم لتوقيع APK للنشر. يمكنك تحديد المفاتيح الخاصة بأهداف التصحيح والإصدار في src / debug / and src / release /.

<البيانات الوصفية

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

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

التكوين الكامل هو تطبيق AndroidManifest anexado ao projeto.

ن

الخطوة 6: Recuperando O Feed No Android

Na atividade main no Android، MainActivity، crie 4 variáveis para identificar cada um dos canais do Thing

سلسلة خاصة url_a = "https://api.thingspeak.com/channels/429823/fields/1/last.json؟api_key="+API_THINGSPEAK_KEY+"&status=true" ؛ سلسلة خاصة url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json؟api_key="+API_THINGSPEAK_KEY+"&status=true" ؛ سلسلة خاصة url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json؟api_key="+API_THINGSPEAK_KEY+"&status=true" ؛ سلسلة خاصة url_d = "https://api.thingspeak.com/channels/429823/fields/4/last.json؟api_key="+API_THINGSPEAK_KEY+"&status=true" ؛

الفقرة 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:

استجابة JSONObjectLixeiraA ؛ استجابة JSONObjectLixeiraB ؛ استجابة JSONObjectLixeiraC ؛ استجابة JSONObjectLixeiraD ؛

الفقرة abrir a conexão com as urls، vamos usar criar uma classe auxiliar، chamada HttpJsonParser. Esta classe será Respável por abrir uma conexão com URL، efetuar leitura dos dados encontrados، e retornar o objeto JSON montado.

JSONObject العامة makeHttpRequest (عنوان url سلسلة ، أسلوب السلسلة ، معلمات الخريطة) {

محاولة {

Uri. Builder builder = new Uri. Builder ()؛ URL URLObj ؛ سلسلة 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 ()؛

}

إذا ("GET".equals (طريقة)) {url = url + "؟" + encodedParams ؛ urlObj = URL جديد (url) ، urlConnection = (HttpURLConnection) urlObj.openConnection () ، urlConnection.setRequestMethod (طريقة) ،

} آخر {

urlObj = عنوان URL جديد (url) ، urlConnection = (HttpURLConnection) urlObj.openConnection () ، urlConnection.setRequestMethod (طريقة) ، urlConnection.setRequestProperty ("نوع المحتوى" ، "application / x-www-form-urlencoded") ؛ urlConnection.setRequestProperty ("طول المحتوى" ، String.valueOf (encodedParams.getBytes (). length)) ؛ urlConnection.getOutputStream (). write (encodedParams.getBytes ()) ؛ } // الاتصال بخادم urlConnection.connect () ؛ // اقرأ الإجابة = urlConnection.getInputStream () ؛ BufferedReader reader = new BufferedReader (new InputStreamReader (is))؛ StringBuilder sb = new StringBuilder () ، خط السلسلة

// تحليل الاستجابة

while ((line = reader.readLine ())! = null) {sb.append (line + "\ n")؛ } is.close ()؛ json = sb.toString () ، // تحويل الرد إلى JSON Object jObj = new JSONObject (json) ؛

} catch (UnsupportedEncodingException هـ) {

e.printStackTrace () ، } catch (ProtocolException e) {e.printStackTrace () ؛ } catch (IOException e) {e.printStackTrace ()؛ } catch (JSONException e) {Log.e ("JSON Parser"، "خطأ في تحليل البيانات" + e.toString ())؛ } catch (استثناء هـ) {Log.e ("استثناء"، "خطأ في تحليل البيانات" + e.toString ())؛ }

// إرجاع كائن JSON

عودة jObj ؛

}

}

De volta ، مدير المدرسة ، vamos efetuar a chamada às urls de forma assíncrona، escrevendo este código dentro do método doInBackground.

Override المحمية String doInBackground (String… params) {HttpJsonParser jsonParser = new HttpJsonParser ()؛

responseLixeiraA = jsonParser.makeHttpRequest (url_a، "GET"، فارغ) ؛

responseLixeiraB = jsonParser.makeHttpRequest (url_b، "GET"، فارغ) ؛ responseLixeiraC = jsonParser.makeHttpRequest (url_c، "GET"، فارغ) ؛ responseLixeiraD = jsonParser.makeHttpRequest (url_d، "GET"، فارغ) ؛

عودة فارغة؛}

Quando o método doInBackgroundé encerrado، o control 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:

محمية باطلة onPostExecute (سلسلة نتيجة) {pDialog.dismiss () ؛ runOnUiThread (new Runnable () {public void run () {

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

عرض mainView = (عرض) findViewById (R.id.activity_main) ؛ إذا (النجاح == 1) {جرب {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira () ؛ Lixeira feedDetails2 = جديد Lixeira () ؛ Lixeira feedDetails3 = جديد Lixeira () ؛ Lixeira feedDetails4 = جديد 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 = جديد SmartBinService () ؛ آلة حاسبة.

// مكونات Recupera

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

// البيانات أتوال

Date currentTime = Calendar.getInstance (). getTime () ، SimpleDateFormat simpleDate = تنسيق SimpleDateFormat الجديد ("dd / MM / yyyy") ؛ String currentDate = simpleDate.format (currentTime) ، createDate.setText (KEY_DATE + currentDate + "") ؛ listaDeLixeiras.setAdapter (محول) ؛

} catch (JSONException e) {

e.printStackTrace () ، }

} آخر {

Toast.makeText (MainActivity.this، "حدث خطأ أثناء تحميل البيانات" ، Toast. LENGTH_LONG).show () ؛

}

} }); }

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

الخطوة 7: موستراندو نو مابا

موستراندو لا مابا
موستراندو لا مابا

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

/ ** يتم الاتصال عند نقر المستخدم على زر Mapa * / public void openMaps (عرض العرض) {Intent intent = new Intent (this، LixeiraMapsActivity.class)؛

// Passa a lista de lixeiras

حزمة الحزمة = حزمة جديدة () ؛ bundle.putParcelableArrayList ("lixeiras"، feedList) ؛ intent.putExtras (حزمة) ؛

startActivity (intent) ؛

}

لا توجد خريطة ، تيموس تريس أتيفيداديس منفذ تنفيذي:

  1. marcar a posição atual do caminha de lixo
  2. marcar os pontos مراسلي cada lixeira no mapa
  3. traçar a rota entre os pontos

تطبيق تنفيذي لنظام التشغيل passos acima، vamos يستخدم واجهة برمجة تطبيقات Google الاتجاهات. Para desenhar as rotas، foram seguidos os passos do تعليمي رسم اتجاهات طريق القيادة بين موقعين باستخدام اتجاهات Google في Google Map Android API V2

Primeiro ، Vamos Criar localidades para cada um dos pontos que desejamos marcar:

// المواقع

تيار LatLng الخاص ؛

LatLng lixeiraA الخاص ؛ خاص LatLng lixeiraB ؛ خاصة LatLng lixeiraC ؛ خاصة LatLng lixeiraD ؛.

الفقرة adicionar a posição atual no mapa، foi criado o método:

checkLocationandAddToMap () {// التحقق مما إذا كان المستخدم قد منح الإذن إذا كان (ActivityCompat.checkSelfPermission (هذا ، android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// طلب إذن الموقع ActivityCompat.requestPermissions (this، new String {android. Manifest.permission. ACCESS_FINE_LOCATION}، LOCATION_REQUEST_CODE) ؛ إرجاع؛ }

// جلب آخر موقع معروف باستخدام Fus

موقع الموقع = LocationServices. FusedLocationApi.getLastLocation (googleApiClient) ؛

// MarkerOptions تستخدم لإنشاء علامة جديدة. يمكنك تحديد الموقع والعنوان وما إلى ذلك باستخدام MarkerOptions

this.current = new LatLng (location.getLatitude ()، location.getLongitude ()) ؛ MarkerOptions markerOptions = new MarkerOptions (). position (current).title ("Posição atual") ؛

// إضافة العلامة التي تم إنشاؤها على الخريطة ، وتحريك الكاميرا إلى الموضع

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

// انقل الكاميرا على الفور إلى الموقع بتكبير 15.

mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (الحالي ، 15)) ؛

// تكبير وتحريك الكاميرا.

mMap.animateCamera (CameraUpdateFactory.zoomTo (14)، 2000، null) ؛

}

Em seguida، para cada lixeira، foram criados métodos similares ao abaixo:

addBinALocation () باطل خاص {// التحقق مما إذا كان المستخدم قد منح الإذن إذا كان (ActivityCompat.checkSelfPermission (هذا ، android. Manifest.permission. ACCESS_FINE_LOCATION)! ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// طلب إذن الموقع ActivityCompat.requestPermissions (this، new String {android. Manifest.permission. ACCESS_FINE_LOCATION}، LOCATION_REQUEST_CODE) ؛ إرجاع؛ }

// Praça da Estação

خط عرض مزدوج = -19.9159578 ؛ خط الطول المزدوج = -43.9387856 ؛ this.lixeiraA = خط الطول والعرض الجديد ؛

MarkerOptions markerOptions = new MarkerOptions (). position (lixeiraA).title ("Lixeira A") ؛

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

كما 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 (por 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 important، e que será useizado neste projeto، são os waypoints!

Foi criado um método para traçar a rota entre dois dados pontos:

سلسلة خاصة getDirectionsUrl (أصل LatLng ، LatLng dest ، قائمة نقاط الطريق) {

// أصل الطريق

String str_origin = "origin =" + origin.latitude + "،" + origin.longitude؛

// وجهة الطريق

String str_dest = "الوجهة =" + dest.latitude + "،" + dest.longitude؛

// نقاط الطريق على طول الطريق

//waypoints=optimize:true|-19.9227365، -43.9473546 | -19.9168006، -43.9361124 نقاط مسار السلسلة = "waypoints = optimize: true"؛ لـ (LatLng point: waypointsList) {waypoints + = "|" + point.latitude + "،" + point.longitude ؛ }

// تمكين الاستشعار

مستشعر السلسلة = "sensor = false" ؛

// بناء المعلمات لخدمة الويب

معلمات السلسلة = str_origin + "&" + str_dest + "&" + مستشعر + "&" + نقاط الطريق ؛

// تنسيق الإخراج

إخراج السلسلة = "json" ؛

// بناء عنوان url لخدمة الويب

عنوان url للسلسلة = "https://maps.googleapis.com/maps/api/directions/"+output+"؟"+parameters؛ System.out.println ("++++++++++++++" + url) ؛

رابط العودة

}

E، por fim، juntando tudo no método main da classe، onMapReady:

Override public void onMapReady (GoogleMap googleMap) {mMap = googleMap؛

checkLocationandAddToMap () ،

إذا (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 () ؛ }

// رسم المسارات

// الحصول على عنوان URL لواجهة برمجة تطبيقات اتجاهات Google

قائمة النقاط = new ArrayList ()؛ النقاط. add (lixeiraB) ؛ Points.add (lixeiraC) ؛ النقاط. add (lixeiraD) ؛

String url = getDirectionsUrl (current، lixeiraA، Points) ؛

DownloadTask downloadTask = new DownloadTask () ؛ // بدء تنزيل بيانات json من واجهة برمجة تطبيقات Google الاتجاهات downloadTask.execute (url) ؛ }

Aqui passamos apenas pelos pontos Principais. وداعا كاملا للمشروع.

الخطوة 8: Conclusão

Este foi um projeto trabalhando conceitos de IoT، mostrando uma das várias opções de conectar detitivos 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.

موصى به: