Оглавление:

SmartBin: 8 шагов
SmartBin: 8 шагов

Видео: SmartBin: 8 шагов

Видео: SmartBin: 8 шагов
Видео: SmartBin in Action 2024, Ноябрь
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 informadases.

Para montar este projeto, при необходимости:

  • NodeMCU
  • Датчик Ultrassônico de Distancia
  • Caixa de papelão
  • Протоборд
  • Cabos
  • Диспетчер Android

Шаг 1. Датчик Conectando O

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:

// определяет номера контактов #define pino_trigger 2 // D4

#define pino_echo 0 // D3

Для efetuar a leitura dos dados do sensor, foi seguido or tutorial development pelo FilipeFlop, disponível aqui.

float cmMsec, inMsec;

длинные микросекунды = ultrasonic.timing ();

cmMsec = ultrasonic.convert (микросекунды, Ultrasonic:: CM);

inMsec = ultrasonic.convert (микросекунды, Ultrasonic:: IN);

// Exibe informacoes no serial monitor

Serial.print ("Расстояние в см:");

Serial.print (смМсек);

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

Serial.println (миллисекунды);

Строковые данные = Строка (смМсек);

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 isolante. Em seguida, temos que medir a distância inicial, para saber o valor para a lixeira vazia. No meu caso, foi de 26, 3 см. Esse é o доблесть que рассмотрениеrmos para uma lixeira vazia.

Para simulação, Visto que não possible 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 = random (1, 5);

}

Шаг 3. Загрузите Para a Nuvem

Agora, Precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por famainidade com o mesmo. Primeiramente, é needário criar um novo canal, recbendo 4 parâmetros, referentes ao volume de cada lixeira.

Пара conectar a aplicação com o ThingSpeak, необходимо использовать номер API для критического канала. Siga os passos descritos не является официальным сайтом.

Чтобы использовать приложение, вам нужно использовать библиотеку ESP8266WiFi.h для связи с ThingSpeak и переводить на него.

Primeiramente, uma função para efetuar conexão com a rede (defina previamente duas varáveis, ssid e pass , Consundo 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, para enviar os dados para o ThingSpeak, basta abrir uma conexão HTTP padrão, passando número da API e os parâmetros.

void sendDataTS (float cmMsec, long id) {

if (client.connect (server, 80)) {

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

Строка postStr = apiKey;

postStr + = "& поле";

postStr + = id;

postStr + = "=";

postStr + = Строка (смМсек);

postStr + = "\ г / п / г / п";

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 ("Content-Type: 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 соответствует расстоянию 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 служить тамбем для идентификации пара qual campo será feito или загрузить 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. Как разные варианты действий кормить для 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: канал Número do seu
  • FIELD_NUMBER: o número do campo
  • API_KEY: API-интерфейс для морского канала

Это URL-адрес, который используется для приложения Android, для восстановления данных для ThingSpeak.

Шаг 5. Создание приложения для Android

Нет Android Studio, это новый проект Android. Для правильной работы приложения необходимо настроить его в соответствии с разрешениями на отсутствие AndroidManifest.

Для использования Google Maps, необходимо использовать Google Maps. Siga os passos descritos no link Obter chave de API.

Uma vez com a chave, voiceê deve também configurá-la na aplicação.

Ключ API для API на основе Карт Google определяется как строковый ресурс.

(См. Файл "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, созданного для проекта.

п

Шаг 6: Recuperando O Feed No Android

На самом деле нет Android, MainActivity, crie 4 различных параметра для идентификации cada um dos canais do ThingSpeak a serem lidos:

частная строка 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";

Для работы с лейтмотивом данных можно использовать специальный класс для Android, chamada JSONObject. Mais uma vez, vamos criar um objeto para cada URL:

JSONObject responseLixeiraA; JSONObject responseLixeiraB; JSONObject responseLixeiraC; JSONObject responseLixeiraD;

Для отказа от соединения в качестве URL-адресов, вам нужно использовать новый класс, chamada HttpJsonParser. Esta class será responseável por abrir uma conexão com um URL, efetuar leitura dos dados encontrados, e retornar or objeto JSON montado.

общедоступный JSONObject makeHttpRequest (String url, String method, Map params) {

пытаться {

Uri. Builder builder = новый Uri. Builder (); URL urlObj; String encodedParams = ""; if (params! = null) {для (запись Map. Entry: params.entrySet ()) {builder.appendQueryParameter (entry.getKey (), entry.getValue ()); }} если (builder.build (). getEncodedQuery ()! = null) {encodedParams = builder.build (). getEncodedQuery ();

}

if ("GET".equals (method)) {url = url + "?" + encodedParams; urlObj = новый URL (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (метод);

} еще {

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 (); // Чтение ответа is = urlConnection.getInputStream (); Читатель BufferedReader = новый BufferedReader (новый InputStreamReader (есть)); StringBuilder sb = новый StringBuilder (); Строка строки;

// Разбираем ответ

в то время как ((строка = reader.readLine ())! = ноль) {sb.append (строка + "\ n"); } закрыто(); json = sb.toString (); // Преобразование ответа в объект JSON 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", "Ошибка анализа данных" + e.toString ()); } catch (Exception e) {Log.e ("Exception", "Error parsing data" + e.toString ()); }

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

return jObj;

}

}

De volta 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 HttpJsonParser ();

responseLixeiraA = jsonParser.makeHttpRequest (url_a, «ПОЛУЧИТЬ», ноль);

responseLixeiraB = jsonParser.makeHttpRequest (url_b, «ПОЛУЧИТЬ», ноль); responseLixeiraC = jsonParser.makeHttpRequest (url_c, «ПОЛУЧИТЬ», ноль); responseLixeiraD = jsonParser.makeHttpRequest (url_d, «ПОЛУЧИТЬ», ноль);

return null;}

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 популярный 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 = new Lixeira (); Lixeira feedDetails2 = новая Lixeira (); Lixeira feedDetails3 = новая Lixeira (); Lixeira feedDetails4 = новая Lixeira ();

feedDetails1.setId ('А');

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

// Компоненты Recupera

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

// Данные atual

Дата currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = новый SimpleDateFormat ("дд / ММ / гггг"); Строка 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: 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 (View view) {Intent intent = new Intent (this, LixeiraMapsActivity.class);

// Passa a lista de lixeiras

Пакетный пакет = новый пакет (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (связка);

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

}

Нет mapa, temos três atividades исполняемый файл:

  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

Для выполнения без прохода вам нужно использовать 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 current;

частный 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.checkSelf.permissionMermission. (this ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Запрос разрешения Location ActivityCompat.requestPermissions (this, new String {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); возвращение; }

// Получение последнего известного местоположения с помощью Fus

Местоположение location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);

// MarkerOptions используются для создания нового маркера. Вы можете указать местоположение, заголовок и т. Д. С помощью MarkerOptions

this.current = new LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = новый 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, ноль);

}

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, android.permission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Запрос разрешения Location 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 = новый LatLng (широта, долгота);

MarkerOptions markerOptions = новый 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 proprio Google Maps, e deixadas fixas no código. Idealmente, estes valores ficariam salvos em um banco de dados (например, 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 String waypoints = "waypoints = optimize: true"; для (точка широты и долгота: список путевых точек) {путевые точки + = "|" + point.latitude + "," + point.longitude; }

// Датчик включен

Строка sensor = "sensor = false";

// Создание параметров веб-службы

Строковые параметры = str_origin + "&" + str_dest + "&" + сенсор + "&" + путевые точки;

// Формат вывода

Строка output = "json";

// Создание URL-адреса веб-службы

Строка url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; System.out.println ("++++++++++++++" + url);

вернуть 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 (); } если (lixeirasList.get (1).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (1).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinBLocation (); } если (lixeirasList.get (2).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (2).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinCLocation (); } если (lixeirasList.get (3).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (3).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinDLocation (); }

// Рисуем маршруты

// Получение URL-адреса в Google Directions API

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

Строка url = getDirectionsUrl (текущий, lixeiraA, очки);

DownloadTask downloadTask = новый DownloadTask (); // Начинаем загрузку данных json из Google Directions API downloadTask.execute (url); }

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

Шаг 8: Заключение

Este foi um projeto trabalhando creatos 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. Смотрите видео, чтобы перейти к полному проекту, для иллюстраций, и не только для Android.

Рекомендуемые: