Spisu treści:
- Krok 1: Czujnik Conectando O
- Krok 2: Montando a Lixeira
- Krok 3: Prześlij Para a Nuvem
- Krok 4: Recuperando Dados Czy ThingSpeak
- Krok 5: Criando a Aplicação Android
- Krok 6: Recuperando O Feed bez Androida
- Krok 7: Mostrando bez mapy
- Krok 8: Podsumowanie
Wideo: SmartBin: 8 kroków
2024 Autor: John Day | [email protected]. Ostatnio zmodyfikowany: 2024-01-31 10:23
Este é um projeto dla inteligentnego systemu coletas, nie ma żadnych innych środowisk lixo recebem dados das lixeiras, identyfikuje ilość prezentowanych lixo w cada uma delas, i uma rota de colet recebem.
Para montar este projeto, é necessário:
- WęzełMCU
- Czujnik Ultrassônico de Distancia
- Caixa de papelão
- Płyta prototypowa
- Cabos
- Urządzenie na Androida
Krok 1: Czujnik Conectando O
Primeiramente, vamos efetuar a conexão entre o sensor ultrassônico e o NODEMCU. Para tanto, vamos conectar jako portas trigger e echo do sensor nas portas D4 e D3 do NodeMCU:
// definiuje numery pinów #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.
float cmMsec, inMsec;
długi mikrosekund = ultradźwięki.timing();
cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM);
inMsec = ultrasonic.convert(microsec, Ultrasonic::IN);
//Exibe informacoes brak monitora szeregowego
Serial.print("Odległość em cm: ");
Serial.print(cmMsec);
Serial.print(" - Odległość polega na: ");
Serial.println(w milisekundach);
Dane ciągu = Ciąg (cmMsec);
Serial.println(dane);
Krok 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 rozważarmos 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
długi lixeiraID;
pusta pętla () {
lixeiraID = losowo (1, 5);
}
Krok 3: Prześlij 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 parametros, referentes ao volume de cada lixeira.
Aby połączyć się z aplikacją o ThingSpeak, konieczne jest salvar na numer API do canal criado. Siga os passos descritos nie ma oficjalnej strony.
De volta à aplicação, vamos utilizar na biblioteca ESP8266WiFi.h do połączenia z 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("Łączenie z "+ *ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
opóźnienie (500);
Serial.print(".");
}
Serial.println("");
Serial.print("Połączenie z ponownym");
Serial.println(ssid);
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
Durante o setup, tentamos efetuar a conexão com a rede.
pusta konfiguracja () {
Serial.początek(9600);
Serial.println("Lendo dados do czujnika…");
//Połącz się z Wi-Fi
połączWifi();
}
E, dla enviar os dados dla ThingSpeak, wystarczy połączyć się z HTTP, passando lub numerami z API i dla parametrów.
void sendDataTS(float cmMsec, długi identyfikator){
if (klient.connect(serwer, 80)) {
Serial.println("Enviando dados dla ThingSpeak");
String postStr = apiKey;
postStr += "&field";
postStr += id;
postStr += "=";
postStr += String(cmMsec);
postStr += "\r\n\r\n";
Serial.println(postStr);
client.print( POST /aktualizacja
client.print("Host: api.thingspeak.com\n");
client.print("Połączenie: zamknij\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Typ treści: application/x-www-form-urlencoded\n");
client.print("Treść-Długość: ");
klient.print(postStr.length());
klient.print("\n\n");
klient.print(postStr);
opóźnienie (1000);
}
klient.stop();
}
O primeiro parâmetro korespondencja à distância em centímetros encontrada pelo sensor ultrassônico. O segundo parametro é o ID da lixeira que foi lida (que foi gerado randomicamente, um número de 1 a 4).
O ID da lixeira służyć também para identificar para qual campo será feito o upload do valor lido.
Krok 4: Recuperando Dados Czy ThingSpeak
O ThingSpeak allowe efetuar leitura dos dados do seu canal, através de um serviço retornando um JSON. Jako 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 brak linku informado previamente. Os mais Importantes para o projekto são:
- CHANNEL_ID: liczba do seu canal
- FIELD_NUMBER: o número do campo
- API_KEY: chave de API do seu canal
Esta to URL que será lida do aplicativa Android, para recuperar os dados do ThingSpeak.
Krok 5: Criando a Aplicação Android
Nie Android Studio, wołaj nowy projekt Androida. Para o correto funcionamento da aplicação, é necessário configurar as permissões abaixo no AndroidManifest.
Aby korzystać z Google Maps, konieczne jest korzystanie z serwisu Google. Siga os passos descritos no link Obter chave de API.
Uma vez com a chave, você deve também configá-la na aplicação.
Klucz API dla interfejsów API opartych na Mapach Google jest zdefiniowany jako zasób tekstowy.
(Zobacz plik „res/values/google_maps_api.xml”).
Pamiętaj, że klucz API jest powiązany z kluczem szyfrowania używanym do podpisywania APK. Potrzebujesz innego klucza API dla każdego klucza szyfrowania, w tym klucza wydania używanego do podpisywania APK do publikacji. Możesz zdefiniować klucze dla celów debugowania i wydania w src/debug/ i src/release/.
<meta-dane
android:nazwa="com.google.android.geo. API_KEY"
android:value="@string/google_maps_key" />
A configuração completa está mo arquivo AndroidManifest anexado ao projeto.
n
Krok 6: Recuperando O Feed bez Androida
Na atividade principal no Android, MainActivity, crie 4 variáveis para identificar cada um dos canais do 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";
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:
JSONOdpowiedź obiektuLixeiraA; JSONOdpowiedź obiektuLixeiraB; JSONOdpowiedź obiektuLixeiraC; JSONOdpowiedź obiektuLixeiraD;
Para brir conexão com jako adresy URL, vamos usar criar uma classe auxiliar, chamada HttpJsonParser. Esta classe será responsável por brir uma conexão com um URL, efetuar leitura dos dados encontrados, i retornar lub objeto JSON montado.
public JSONObject makeHttpRequest(String url, String method, Map params) {
próbować {
Konstruktor Uri. Builder = nowy Uri. Builder(); URL obiekt url; String encodedParams = ""; if (params != null) { for (wpis Map. Entry: params.entrySet()) { builder.appendQueryParameter(entry.getKey(), entry.getValue()); } } if (builder.build().getEncodedQuery() != null) { encodedParams = builder.build().getEncodedQuery();
}
if ("GET".equals(metoda)) { url = url + "?" + zakodowane parametry; urlObj = nowy adres URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(metoda);
} w przeciwnym razie {
urlObj = nowy URL(url); urlConnection = (HttpURLConnection) urlObj.openConnection(); urlConnection.setRequestMethod(metoda); urlConnection.setRequestProperty("Typ-treści", "aplikacja/x-www-form-urlencoded"); urlConnection.setRequestProperty("Długość treści", String.valueOf(encodedParams.getBytes().length)); urlConnection.getOutputStream().write(encodedParams.getBytes()); } //Połącz z serwerem urlConnection.connect(); //Odczytaj odpowiedź to = urlConnection.getInputStream(); Czytnik BufferedReader = nowy BufferedReader(nowy InputStreamReader(is)); StringBuilder sb = nowy StringBuilder(); Linia sznurka;
//Przeanalizuj odpowiedź
while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } jest blisko(); json = sb.toString(); //Konwertuj odpowiedź na obiekt 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 Parser", "Błąd parsowania danych " + e.toString()); } catch (Exception e) { Log.e("Wyjątek", "Błąd parsowania danych " + e.toString()); }
// zwróć obiekt JSON
zwróć jObj;
}
}
De volta a atividade principal, vamos efetuar and chamada jako adresy URL forma assíncrona, escrevendo este código dentro do metody 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);
zwróć null;}
Quando lub metody doInBackground encerrado, lub kontroli wykonywania Android passa lub metody onPostExecute. Neste método, vamos criar os objetos Lixeira, e popular com os dados recuperados do ThingSpeak:
protected void onPostExecute(String wynik) { pDialog.dismiss(); runOnUiThread(new Runnable() { public void run() {
//ListView listView =(ListView)findViewById(R.id.feedList);
Widok mainView =(Widok)findViewById(R.id.activity_main); if (success == 1) { try { //Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira(); Lixeira feedDetails2 = nowa Lixeira(); Lixeira feedDetails3 = nowa Lixeira(); Lixeira feedDetails4 = nowa 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
Kalkulator SmartBinService = nowy SmartBinService(); kalkulator.montaListaLixeiras(Lista kanałów);
//Komponenty Recupera
TextView createDate = (TextView) mainView.findViewById(R.id.date); ListView listaDeLixeiras = (ListView) findViewById(R.id.lista); adapter.addAll(feedList);
//Dane rzeczywiste
Data currentTime = Kalendarz.getInstance().getTime(); SimpleDateFormat simpleDate = new SimpleDateFormat("dd/MM/rrrr"); String currentDate = simpleDate.format(currentTime); createDate.setText(KEY_DATE + bieżąca data + " "); listDeLixeiras.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace(); }
} w przeciwnym razie {
Toast.makeText(MainActivity.this, "Wystąpił błąd podczas ładowania danych", Toast. LENGTH_LONG).show();
}
} }); }
Agora, na tela inicial do aplicativo, serão listados os dados de cada lixeira.
Krok 7: Mostrando bez mapy
Ainda na dyrektora atividade, vamos adicionar uma ação i ser relacionada z botão Mapa, tea inicial.
/** Wywoływane, gdy użytkownik naciśnie przycisk Mapa */ public void openMaps(View view) { Intent intent = new Intent(this, LixeiraMapsActivity.class);
//Przekaż listę de lixeiras
Pakiet pakietu = nowy pakiet(); bundle.putParcelableArrayList("lixeiras", feedList); intent.putDodatki(pakiet);
startActivity(zamiar);
}
Brak mapy, temos três atividades a executar:
- Marcar a posição atual do caminha de lixo
- marcar os pontos korespondentes a cada lixeira bez mapy
- Traçar a rota entre os pontos
Aby wykonać passos acima, użyj API Google Directions. Para desenhar as rotas, foram seguidos os passos do tutorial Rysowanie wskazówek dojazdu między dwoma lokalizacjami za pomocą Google Directions w Google Map Android API V2
Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:
//Lokalizacje
prąd prywatny LatLng;
prywatna LatLng lixeiraA; prywatny LatLng lixeiraB; prywatny LatLng lixeiraC; prywatny LatLng lixeiraD;.
Para adicionar a posição atual no mapa, foi criado o método:
private void checkLocationandAddToMap() { //Sprawdzenie, czy użytkownik przyznał uprawnienia 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) { //Żądanie uprawnień do lokalizacji ActivityCompat.requestPermissions(ten, nowy String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); powrót; }
//Pobieranie ostatniej znanej lokalizacji za pomocą Fus
Lokalizacja lokalizacji = LocationServices. FusedLocationApi.getLastLocation(googleApiClient);
//MarkerOptions są używane do tworzenia nowego Markera. Możesz określić lokalizację, tytuł itp. za pomocą MarkerOptions
this.current = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions().position(current).title("Pozycja rzeczywista");
//Dodanie utworzonego znacznika na mapie, przesunięcie kamery na pozycję
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_GREEN)); System.out.println("++++++++++++++ Passei aqui! ++++++++++++++"); mMap.addMarker(markerOptions);
// Natychmiast przenieś aparat do lokalizacji z 15-krotnym powiększeniem.
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(current, 15));
// Powiększanie, animowanie kamery.
mMap.animateCamera(CameraUpdateFactory.zoomTo(14), 2000, null);
}
Em seguida, para cada lixeira, foram criados métodos similares ao abaixo:
private void addBinALocation() { //Sprawdzenie, czy użytkownik przyznał uprawnienia 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) { //Żądanie uprawnień do lokalizacji ActivityCompat.requestPermissions(this, new String{android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); powrót; }
//Praca da Estação
podwójna szerokość geograficzna = -19,9159578; podwójna długość geograficzna = -43,9387856; this.lixeiraA = new LatLng(szerokość, długość geograficzna);
MarkerOptions markerOptions = nowe MarkerOptions().position(lixeiraA).title("Lixeira A");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory. HUE_RED)); mMap.addMarker(markerOptions); }
Jako 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 ważne, 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){
// Początek trasy
String str_origin = "origin="+origin.latitude+", "+origin.longitude;
// Miejsce docelowe trasy
String str_dest = "docelowa="+docelowa.szerokość geograficzna+", "+docelowa.długość geograficzna;
//Punkty na trasie
//waypoints=optimize:true|-19.9227365, -43.9473546|-19.9168006, -43.9361124 String waypoints = "waypoints=optimize:true"; for (LatLng point: waypointsList){ waypoints += "|" + punkt.szerokość + ", " + punkt.długość geograficzna; }
// Czujnik włączony
Czujnik ciągu = "czujnik=fałsz";
// Budowanie parametrów do usługi sieciowej
Parametry ciągu = str_origin+"&"+str_dest+"&"+czujnik + "&" + punkty;
// Format wyjściowy
Wyjście ciągu = "json";
// Budowanie adresu URL do usługi internetowej
String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parametry; System.out.println("++++++++++++++ "+url);
zwrotny adres URL;
}
E, por fim, juntando tudo no método principal da classe, onMapReady:
@Zastąp public void onMapReady(GoogleMap googleMap) { mMap = googleMap;
sprawdźLokalizacjaiDodajDoMapy();
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(); }
//Narysuj trasy
// Pobieranie adresu URL do interfejsu Google Directions API
Lista punktów = new ArrayList(); points.add(lixeiraB); points.add(lixeiraC); points.add(lixeiraD);
URL ciągu = getDirectionsUrl(bieżący, lixeiraA, punkty);
DownloadTask downloadTask = nowy DownloadTask(); // Rozpocznij pobieranie danych json z Google Directions API downloadTask.execute(url); }
Aqui passamos apenas pelos pontos principais. O código completo do projeto será disponibilizado para consulta.
Krok 8: Podsumowanie
Este foi um projeto trabalhando conceitos de IoT, mostrando uma das várias opções de conectar dispositivos através da nuvem, efetuar tomada de decisões sem interferência humana direta. Em anexo, segue um wideo do pełnego projektu, para ilustração, e os fontes das atividades criadas bez Androida.
Zalecana:
Licznik kroków - Micro:Bit: 12 kroków (ze zdjęciami)
Licznik kroków - Micro:Bit: Ten projekt będzie licznikiem kroków. Do pomiaru kroków użyjemy czujnika przyspieszenia wbudowanego w Micro:Bit. Za każdym razem, gdy Micro:Bit się trzęsie, dodamy 2 do licznika i wyświetlimy go na ekranie
Lewitacja akustyczna z Arduino Uno krok po kroku (8 kroków): 8 kroków
Lewitacja akustyczna z Arduino Uno Krok po kroku (8-kroków): ultradźwiękowe przetworniki dźwięku Zasilacz żeński L298N Dc z męskim pinem dc Arduino UNOBreadboardJak to działa: Najpierw wgrywasz kod do Arduino Uno (jest to mikrokontroler wyposażony w cyfrowy oraz porty analogowe do konwersji kodu (C++)
Jak używać silnika krokowego jako enkodera obrotowego i wyświetlacza OLED dla kroków: 6 kroków
Jak używać silnika krokowego jako enkodera obrotowego i wyświetlacza OLED dla kroków: W tym samouczku dowiemy się, jak śledzić kroki silnika krokowego na wyświetlaczu OLED. Obejrzyj film demonstracyjny.Kredyt samouczka oryginalnego trafia do użytkownika YouTube „sky4fly”
Bolt - DIY Wireless Charging Night Clock (6 kroków): 6 kroków (ze zdjęciami)
Bolt - DIY Wireless Charging Night Clock (6 kroków): Ładowanie indukcyjne (znane również jako ładowanie bezprzewodowe lub ładowanie bezprzewodowe) to rodzaj bezprzewodowego przesyłania energii. Wykorzystuje indukcję elektromagnetyczną do dostarczania energii elektrycznej do urządzeń przenośnych. Najpopularniejszym zastosowaniem jest stacja ładowania bezprzewodowego Qi
SmartBin: 4 kroki
SmartBin: Głównym celem tego projektu jest stworzenie urządzenia elektronicznego wykorzystującego co najmniej jedno Raspberry Pi. Zespół składa się z 5 przyszłych inżynierów mechaników i jednego automatyka. Nasz projekt polega na wykonaniu kosza na śmieci, który otwiera się i zamyka