Съдържание:

SmartBin: 8 стъпки
SmartBin: 8 стъпки

Видео: SmartBin: 8 стъпки

Видео: SmartBin: 8 стъпки
Видео: Первый обзор Mi Band 8 — лучший Band в истории! 2024, Ноември
Anonim
SmartBin
SmartBin

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
  • Сензор Ultrassônico de Distancia
  • Caixa de papelão
  • Protoboard
  • Кабос
  • Dispositivo Android

Стъпка 1: Conectando O сензор

Премиера, вамос ефективен conexão entre о сензор ultrassônico e или NODEMCU. Para tanto, vamos conectar as portas trigger e echo do sensor nas portas D4 e D3 do NodeMCU:

// дефинира номера на щифтове #дефинира pino_trigger 2 // D4

#дефинирайте pino_echo 0 // D3

За да направите това, трябва да използвате сензора, за да се запознаете с урока, разработен от FilipeFlop, да споделите aqui.

поплавък cmMsec, inMsec;

дълъг микросек = ултразвуково синхронизиране ();

cmMsec = ултразвук.конвертиране (микросек, ултразвук:: CM);

inMsec = ултразвук.конвертиране (микросек, ултразвук:: IN);

// Exibe informacoes no serial monitor

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

Serial.print (cmMsec);

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

Serial.println (inMsec);

Низови данни = String (cmMsec);

Serial.println (данни);

Стъпка 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Предварително свързан или сензорен ултразвуков сензор без „teto“да lixeira. Para o exemplo, utilizei um cabo e fita isolante. Em seguida, temos que medir a distância inicial, para sabre o valor para a lixeira vazia. Без meu caso, на 26, 3 см. Esse é o valor que consurarmos 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

дълъг lixeiraID;

void loop () {

lixeiraID = случаен (1, 5);

}

Стъпка 3: Качете Para a Nuvem

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, от фамилията на com или mesmo. Primeiramente, é needário criar um novo canal, recebendo 4 parâmetros, препраща към ao том de cada lixeira.

Pará conectar a applicação com o ThingSpeak, é needário salvar o número da API до channel criado. Siga os passos descritos no site oficial.

De volta à applicação, vamos utilarar 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 ("Свързване към"+ *ssid);

WiFi.begin (ssid, pass);

while (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 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, за да се уверите, че можете да използвате ThingSpeak, въведете ума conexão HTTP padrão, passando o número да API и os parâmetros.

void sendDataTS (float cmMsec, long id) {

if (client.connect (сървър, 80)) {

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

Низ postStr = apiKey;

postStr += "& field";

postStr += id;

postStr += "=";

postStr += Низ (cmMsec);

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

Serial.println (postStr);

client.print ("POST /актуализиране на 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 ("Content-Length:");

client.print (postStr.length ());

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

client.print (postStr);

забавяне (1000);

}

client.stop ();

}

O primeiro parâmetro korespondnde à 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 служат тамбем para identificar para qual campo será feito o качване до доблест лидо.

Стъпка 4: Recuperando Dados Do ThingSpeak

O ThingSpeak permite efetuar leitura dos dados do seu channel, através de um serviço retornando um JSON. Като 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 няма връзка с информация за предварителна информация. Os mais importantes para o projeto são:

  • CHANNEL_ID: канал número do seu
  • FIELD_NUMBER: o número do campo
  • API_KEY: a chave de API do seu канал

Това е URL адрес, който е подходящ за Android, за да се възстанови от ThingSpeak.

Стъпка 5: Criando и Aplicação Android

Без Android Studio, crie um novo projeto Android. За да коригирате функционалността на приложението, е необходимо да конфигурирате като разрешения за използване на AndroidManifest.

За да използвате Google Maps, трябва да се обърнете към 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 Maps API се дефинира като низов ресурс.

(Вижте файла „res/values/google_maps_api.xml“).

Имайте предвид, че API ключът е свързан с ключа за шифроване, използван за подписване на APK. Нуждаете се от различен API ключ за всеки ключ за шифроване, включително ключа за освобождаване, който се използва за подписване на APK за публикуване. Можете да дефинирате ключовете за целите за отстраняване на грешки и освобождаване в src/debug/и 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

На активиращ главен без Android, MainActivity, crie 4 варианти за идентифициране на cada um dos canais до ThingSpeak 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";

За да постигнете това, можете да използвате класове за Android, които са специални за 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 като 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 objectto JSON montado.

публичен JSONObject makeHttpRequest (String url, String method, Map params) {

опитвам {

Uri. Builder builder = нов Uri. Builder (); URL urlObj; Низ кодиранParams = ""; 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 (метод)) {url = url + "?" + encodedParams; urlObj = нов URL адрес (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (метод);

} else {

urlObj = нов URL адрес (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (метод); urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). write (encodedParams.getBytes ()); } // Свързване със сървъра urlConnection.connect (); // Прочетете отговора = urlConnection.getInputStream (); BufferedReader четец = нов BufferedReader (нов InputStreamReader (е)); StringBuilder sb = нов StringBuilder (); Низова линия;

// Анализирайте отговора

while ((line = reader.readLine ())! = null) {sb.append (line + "\ n"); } близо е(); json = sb.toString (); // Конвертираме отговора в JSON Object jObj = нов JSONObject (json);

} catch (UnsupportedEncodingException e) {

e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Грешка при синтактичния анализ на данни" + e.toString ()); } catch (Exception e) {Log.e ("Exception", "Error parsing data" + e.toString ()); }

// връща JSON обект

връщане 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 защитен String doInBackground (String… params) {HttpJsonParser jsonParser = нов 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);

return null;}

Quando o método doInBackgroundé encerrado, o controle de execução to Android passa para or 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); if (success == 1) {try {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = нов 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 (); Calculator.montaListaLixeiras (feedList);

// Възстановяващи компоненти

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

// Актуални данни

Дата currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = нов SimpleDateFormat ("dd/MM/yyyy"); Низ currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (адаптер);

} catch (JSONException e) {

e.printStackTrace (); }

} else {

Toast.makeText (MainActivity.this, "Възникна грешка при зареждане на данни", Toast. LENGTH_LONG).show ();

}

} }); }

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

Стъпка 7: Mostrando No Mapa

Без карта
Без карта

Ainda na atividade principal, 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 bundle = нов Bundle (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (пакет);

startActivity (намерение);

}

Без карта, temos três atividades и изпълнител:

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

За да изпълните, можете да използвате API на Google Directions. Para desenhar as rotas, foram seguidos os passos do tutorial Рисуване на упътвания по маршрута за шофиране между две локации с помощта на Google Directions в 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;.

Para adicionar a posição atual no mapa, foi criado o método:

private void checkLocationandAddToMap () {// Проверка дали потребителят е предоставил разрешението if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat. MectionServer, ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Искане на разрешение за местоположение ActivityCompat.requestPermissions (този, нов низ {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); връщане; }

// Извличане на последното известно местоположение с помощта на Fus

Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);

// MarkerOptions се използват за създаване на нов Marker. Можете да посочите местоположение, заглавие и т.н. с MarkerOptions

this.current = нов LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = нови MarkerOptions (). Позиция (текуща).title ("Позиция 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, нула);

}

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

private void addBinALocation () {// Проверява дали потребителят е дал разрешението if (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission this (ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Искане на разрешение за местоположение ActivityCompat.requestPermissions (този, нов низ {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); връщане; }

// Praça da Estação

двойна ширина = -19,9159578; двойна дължина = -43.9387856; this.lixeiraA = нов LatLng (географска ширина, дължина);

MarkerOptions markerOptions = нови MarkerOptions (). Позиция (lixeiraA).title ("Lixeira A");

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

Като позиции на географска ширина и дължина на cada lixeira foram recuperadas através do próprio Google Maps, e deixadas fixas no código. Идеално, estes valores ficariam salvos em um banco de dados (например exebase 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 neste projeto, são os Waypoints!

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

private String getDirectionsUrl (LatLng origin, LatLng dest, List waypointsList) {

// Произход на маршрута

Низ str_origin = "origin ="+origin.latitude+","+origin.longitude;

// Дестинация на маршрута

Низ str_dest = "destination ="+dest.latitude+","+dest.longitude;

// Пътни точки по маршрута

//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 Низови waypoints = "waypoints = optimize: true"; за (LatLng точка: waypointsList) {waypoints += "|" + точка.ширина + "," + точка.дължина; }

// Сензорът е активиран

Низови сензор = "сензор = невярно";

// Изграждане на параметрите към уеб услугата

Параметри на низа = str_origin+"&"+str_dest+"&"+сензор+"&"+точки;

// Изходен формат

Низово извеждане = "json";

// Изграждане на URL адреса към уеб услугата

String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+параметри; System.out.println ("++++++++++++++"+url);

URL за връщане;

}

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

@Отмяна на публична празнота 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 (); }

// Начертайте маршрути

// Получаване на URL адрес към API на Google Directions

Списък точки = нов ArrayList (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);

String url = getDirectionsUrl (current, lixeiraA, точки);

DownloadTask downloadTask = нов DownloadTask (); // Започнете изтеглянето на json данни от Google Directions API downloadTask.execute (url); }

Aqui passamos apenas pelos pontos principais. O código completo do projekto será disponibilizado para consulting.

Стъпка 8: Заключение

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 odločões sem interferência humana direta. Em anexo, segue um vídeo do projekto completo, para ilustração, e os fontes das atividades criadas no Android.

Препоръчано: