58 Commits

Author SHA1 Message Date
Yannick van Etten
466a8659d0 Code toegevoegd voor de sgp32 sensor zodat deze wordt geïnitialiseerd 2025-01-14 17:43:27 +01:00
Yannick van Etten
523ccd87e3 Removed callback line 2024-12-18 15:07:02 +01:00
Yannick van Etten
c905bda662 Removed network information 2024-12-18 13:23:13 +01:00
Yannick van Etten
d865a50951 Kleine spellingsfouten veranderd en de callback weggehaald 2024-12-17 17:10:40 +01:00
Yannick van Etten
d7a643460c Begin gemaakt aan data verzenden via mqtt websocket 2024-12-17 16:51:50 +01:00
Yannick van Etten
f021ebebcb Merge branch '22-als-developer-wil-ik-een-weerstation-hebben-op-de-robot-waarmee-ik-data-van-de-omgeving-kan' of gitlab.fdmci.hva.nl:technische-informatica-sm3/ti-projectten/rooziinuubii79 into 22-als-developer-wil-ik-een-weerstation-hebben-op-de-robot-waarmee-ik-data-van-de-omgeving-kan 2024-12-16 14:35:28 +01:00
Yannick van Etten
32e0583c1b Documentatie gemaakt de behuizing van de sensoren 2024-12-16 14:35:05 +01:00
Yannick van Etten
c0cf6f1360 De data in een json payload gezet die vervolgens verstuurt wordt naar de raspberry pi 2024-12-12 16:40:24 +01:00
Yannick van Etten
730d2b47b8 Reconnect functie toegevoegd 2024-12-12 16:09:40 +01:00
Yannick van Etten
4c5cea71b2 Restructure want de vorige was niet goed gegaan 2024-12-10 13:59:39 +01:00
Yannick van Etten
dcd3f1006d restructure en code toegevoegd voor mqtt 2024-12-10 13:30:42 +01:00
Yannick van Etten
4f79695d9c Foto toegevoegd van het aansluitschema 2024-11-29 14:04:12 +01:00
Yannick van Etten
b2d233386c uitleg toegevoegd voor de MQ5 gassensor 2024-11-29 13:52:27 +01:00
Yannick van Etten
160b43f49e nog stukje toegevoegd aan de tvoc/eco2 sensor uitleg 2024-11-19 15:26:46 +01:00
Yannick van Etten
afe8ae3357 uitleg toegevoegd van de tvoc/eco2 sensor toegevoegd 2024-11-19 15:23:40 +01:00
Yannick van Etten
66d5444488 Uitleg van de DHT11 sensor toegevoegd aan sensoronderzoek 2024-11-19 15:07:17 +01:00
Yannick van Etten
bcbd6743fb Added comment 2024-11-18 11:16:53 +01:00
Yannick van Etten
9997bf2319 Removed double code 2024-11-18 11:12:02 +01:00
Yannick van Etten
0ae0b83e4b Merged m5 code into sensor code 2024-11-18 11:09:13 +01:00
Yannick van Etten
db8758e1e5 removed unnecessary code 2024-11-13 14:45:27 +01:00
Yannick van Etten
08dff8bbc1 changed test code for the m5stack sensor 2024-11-13 14:37:14 +01:00
Yannick van Etten
f0260c1a91 changed file location 2024-11-13 13:46:04 +01:00
Yannick van Etten
40d601a35b Name change and small changes 2024-11-13 13:02:22 +01:00
Yannick van Etten
3525479b17 Added comments 2024-11-11 10:53:10 +01:00
Yannick van Etten
2e08bf7e74 Removed baseline 2024-11-11 09:19:08 +01:00
Yannick van Etten
12c25b33a7 Added test code for M5 sensor. (work in progress) 2024-10-31 16:27:30 +01:00
Yannick van Etten
5b27974d5a Added comments 2024-10-31 15:27:17 +01:00
Yannick van Etten
f4ce50db18 Name change 2024-10-31 15:12:00 +01:00
Yannick van Etten
9bd9b6c4b2 Added code for the MQ5 gas sensor 2024-10-30 18:04:58 +01:00
Yannick van Etten
c08f1e434c rewrote DHT11 code 2024-10-30 15:35:03 +01:00
Yannick van Etten
fb35d2a84d Code toegevoegd voor de DHT11 sensor 2024-10-29 15:17:27 +01:00
Yannick van Etten
b67c51e56b Documentatie uitgebreid 2024-10-29 14:06:29 +01:00
Yannick van Etten
8b03438d47 Start Sensoronderzoek 2024-10-28 15:23:32 +01:00
ishak jmilou.ishak
c4a694e601 moved venv to the .gitignore 2024-10-24 14:07:11 +02:00
d78389992e added a comment 2024-10-22 15:33:19 +02:00
7fa04a5c35 made it so we can read indiviual buttons 2024-10-22 15:10:08 +02:00
1175444abf edited cmakelist 2024-10-21 13:09:46 +02:00
79f21f8755 testing 2024-10-21 12:34:03 +02:00
9935375a5a comment 2024-10-21 10:41:57 +02:00
d41e6432b3 fixed safety of robot and that it always drives when its told to drive 2024-10-21 10:41:48 +02:00
b5f5491222 attempt to make function so robot doenst throw itself from a cliff 2024-10-20 17:35:55 +02:00
856d60eea2 Junk removal 2024-10-18 16:22:47 +02:00
6a0024ebb8 rotation sort of works now 2024-10-16 16:43:24 +02:00
0011096977 INfrastructure update 2024-10-14 14:34:45 +02:00
5ead72c47e uitleg welke sensoren gebruiken en waarom 2024-10-14 13:57:48 +02:00
ishak jmilou.ishak
216b28d27c added template user and learning story 2024-10-14 12:10:03 +02:00
b5e619ac0a attempt to make robot rotate 2024-10-09 14:24:23 +02:00
c38491ce20 added to parser so we can read raw sensordata from cliffsensor (thanks anwar) 2024-10-08 15:05:41 +02:00
c9d128ecd1 todo commnets from ferry at expert review 2024-10-08 14:27:38 +02:00
Mees Roelofsz
927126a797 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/technische-informatica-sm3/ti-projectten/rooziinuubii79 2024-10-08 13:53:27 +02:00
Mees Roelofsz
6235af77b9 changed word 2024-10-08 13:53:25 +02:00
9a4cd473a6 added and fixed logger 2024-10-08 13:29:24 +02:00
Mees Roelofsz
acd4b9589c To Be Determined 2024-10-08 13:13:27 +02:00
Mees Roelofsz
c129ae4980 added more tabs 2024-10-08 13:09:45 +02:00
Mees Roelofsz
cdbb538238 decision written out 2024-10-08 13:05:34 +02:00
Mees Roelofsz
26cc0e2041 finished brainstorm 2024-10-08 12:59:34 +02:00
2bee0ffc25 fix nonsense errors 2024-10-08 12:53:22 +02:00
cede3689f4 cleanup and logger creation 2024-10-08 12:39:31 +02:00
20 changed files with 631 additions and 365 deletions

3
.gitignore vendored
View File

@@ -16,3 +16,6 @@ src/C++/Driver/Makefile
src/C++/Driver/vgcore*
src/C++/Driver/cmake_install.cmake
src/C++/Driver/Makefile
src/C++/Driver/log
build/
venv

View File

@@ -0,0 +1,21 @@
```
Inleiding van de learning story:
Vul hier een korte beschrijving in van de learning story.
Probeer dit direct te koppelen aan het project wat studenten gaan doen.
```
**Wat ga ik leren?**
```
Zet hier een overzicht van de vaardigheden die een student gaat leren.
Als de student alle vinkjes heeft afgevinkt, dan hebben ze dit onderwerp goed begrepen.
```
- [ ] <- Maak op deze manier afvinklijstjes
**Hoe ga ik dit leren?**
```
Zet hier de bronnenlijst.
```
- [ ] <- Maak op deze manier afvinklijstjes

View File

@@ -0,0 +1,32 @@
Als gebruiker wil ik ..., zodat ... (verwijder deze regel, plaats de tekst in de titel)
[beschrijving van de user story en context]
**Taken**
Deze user story is opgedeeld in een aantal taken. Vul onderstaande lijst zelf aan.
- [ ] Taak 1.
- [ ] Taak 2.
- [ ] ...
**Acceptatie criteria**
Acceptatie criteria zijn specifieke eisen waaraan de User Story moet voldoen. Deze zijn meestal uniek per User Story.
- [ ] Acceptatiecriterium 1
- [ ] Acceptatiecriterium 2
- [ ] ...
**Definition of Done**
- [ ] Alle acceptatiecriteria van de user story zijn afgevinkt.
- [ ] Je hebt volgens de HBO-ICT werkstandaarden gewerkt (Agile, GitLab, sprint boards, sprint planning, HBO-ICT conventions etc.)
- [ ] Het werk is technisch gedocumenteerd in het Engels en relevant voor collega-ontwikkelaars. Denk o.a. aan ERD, UML, testen en testresultaten.
- [ ] Het leerproces is beschreven in Standaardnederlands.
- [ ] Het werk is gereviewd door een peer.
- [ ] Het UX/UI gedeelte van de applicatie voldoet aan het Think-Make-Check (TMC) principe.
- [ ] De code is functioneel getest op fouten.
- [ ] De code werkt zonder fouten bij normaal gebruik.
- [ ] De webapplicatie dient zowel op mobiele- als desktop-apparaten gebruikt te kunnen worden.

View File

@@ -2,35 +2,51 @@
```mermaid
classDiagram
Apache <--> Flask
Flask <--> MariaDB
ESP32 --> RPI : Wired communication
RPI <--> Wireguard : MQTT with a VPN connection
Wireguard <--> Flask
VirtualMachine <--> RPI
Kobuki <--> RPI
namespace Server {
class VirtualMachine {
+Apache()
+Flask()
+SocketServer()
+MariaDB()
Python/C++
Database
Website
class Wireguard {
+VPN()
}
class Apache {
+ReverseProxy()
}
class MariaDB {
+Database()
}
class Flask {
Python
+Webserver()
+endpoints communication()
}
}
}
namespace robot {
namespace Kobuki {
class RPI {
Receiver
Sensors
+KobukiCommunication()
+ESP32Communication()
C++
+SocketClient()
+Kobuki()
}
class Kobuki {
+data
class ESP32 {
+TVOC()
+ECO2()
+Temperature()
+LDR()
+Camera()
+GPS()
+ToF()
}
}
```

View File

@@ -22,3 +22,32 @@ The ideas we came up with where:
- A mobile scarecrow that will ride around a farm scaring birds, checking for optimal growing conditions using sensors, and checking (and possibly fighting) pests.
- A robot that would be sent into buildings with a gasleak and check where the leak is the strongest and thus where it would most likely be coming from. (also possible lighting mechanic for controlled explosions in case of preventable disasters without loss of a human life)
- A mobile fire extinguisher placed in buildings or terrains that are prone to fires. The robot would be able to detect fires and extinguish them before they get out of hand. Or control the fire before the fire department arrives.
- A mobile solar panel that moves to the spot with the harshest sunlight (without a certain area). After which it would plug itself into a battery and charge it. This battery could then be used to power a building or a car.
- A robot that is dropped in dangerous environments to scout the area and report back to the people who sent it. This could be used in warzones, dangerous buildings, or other dangerous environments.
It scouts for stuff in the air using air sensors, it scouts for stuff on the ground using cameras, and it scouts for possible hazards like fire using infrared and other sensors.
### Decision
In the end we decided to go with the final idea. This was partially due to the fact that it merges some of the most interresting aspect of the other ideas. We think that this is the most fitting with our goal oof minimizing the loss of human life because it can be used in not just fires or gasleaks but also in warzones and other dangerous environments. This makes it so that it has way more usecases than the other ideas and the buyer has enough with just these robots to cover a lot of dangerous situations.
## Realization & Plan
### Hardware
#### Sensors
placeholder
#### IC's
placeholder
#### Motors
placeholder
#### Batteries
placeholder
### Software

View File

@@ -0,0 +1,28 @@
# Sensor behuizing
Voor de sensoren op onze Kobuki wouden wij graag een behuizing zodat deze sensoren niet los liggen op de Kobuki.
Deze behuizing had een paar eisen en die eisen waren als volgt
- Hij moet klein zijn zodat hij niet veel ruimte in neemt op de Kobuki.
- De behuizing moet makkelijk vast te maken zijn aan de Kobuki.
- In de behuizing moet een esp32 passen en de 3 sensoren.
- De behuizing moet makkelijk uit elkaar te halen zijn zodat als we onderhoud moeten plegen dit makkelijk kan.
Met deze eisen zijn we uiteindelijk een behuizing gaan maken in onshape.
Onshape is gratis ontwerp software wat te gebruiken is via je browser.
Hierdoor hoef je dus geen applicatie te runnen op je computer en kan je op elk apparaat inloggen om zo gemakkelijk door te gaan aan je ontwerp.
Ik (Yannick) heb voor deze software gekozen omdat ik deze software al veel vaker heb gebruikt en hier dus al bekend mee ben.
Uiteindelijk zijn we op het volgende design uitgekomen.
![Afbeelding van de behuizing](images/Behuizingfoto1.png)
![Afbeelding van de behuizing van bovenaf](images/Behuizingfoto2.png)
Wij hebben gekozen voor dit design omdat dit de breedte en lengte heeft van een esp32 dus de esp past precies waardoor wij hem niet nog extra vast hoeven te zetten.
Er zitten gaten in de zijkant van het bakje voor de kabel en voor een 5 volt kabel voor de MQ5 sensor.
De dht11 sensor past er precies in en deze blijft daardoor precies vast zitten.
Voor de M5stack sensor is er een gat gemaakt zodat deze kabel erdoorheen past en vervolgens wordt deze sensor op de bovenkant van de behuizing vastgeplakt.
Voor de MQ5 sensor is een gat gemaakt waar de sensor door heen kan en het printplaatje wordt aan de onderkant vast gemaakt met stevige M3 tape.
In de onderkant van de behuizing zitten 2 gaten hiermee kan de behuizing goed vastgemaakt worden aan de kobuki.
De onderkant en de bovenkant van de behuizing zijn makkelijk uit elkaar te halen omdat deze doormiddel van 4 sterke magneten aan elkaar vast zitten.
Hierdoor is het ook makkelijk om onderhoud te plegen omdat het bakje door de magneten makkelijk uit elkaar te halen is maar niet zo makkelijk dat hij door trillingen los kan komen.

View File

@@ -0,0 +1,79 @@
# Sensor onderzoek
In dit bestand gaan we onderzoek doen naar de sensoren die we willen gebruiken op de Kobuki.
Hierin gaan we meerdere sensoren vergelijken met elkaar en kijken welke wij het beste kunnen gebruiken voor ons project.
## Probleem
Voor ons project moeten wij een manier vinden om gassen/stoffen te detecteren zodat je in een gebouw weet waar je niet veilig naartoe kan.
## De vraag
> Welke sensoren kunnen wij het beste gebruiken om schadelijke gassen/stoffen te vinden in een gebouw ?
## Voorwaarden
De voorwaarden waar de sensors aan moeten voldoen zijn:
- De sensoren moeten op de kobuki passen.
- We moeten zo weining mogelijk sensoren gebruiken zodat we genoeg plek over houden voor andere onderdelen van de Kobuki.
## Hoe aansluiten
Wij gaan deze sensoren aansluiten op een esp32 en deze laten wij via MQTT de gegevens doorsturen naar de raspberry pi.
## De sensoren.
Wij zijn uitgekomen op 3 sensoren.
- De dht11 sensor
- De tvoc/eC02 Gas Unit.
- Gravity: Elektrochemische zuurstof-/O2-sensor (0-25%Vol, I2C) SEN0322
- Gassensor MQ-5 module (OT2018-D55)
Wij hebben voor de Dht11 en de tvoc/eC02 gas unit gekozen omdat wij deze bij james konden lenen. En wij hebben gekozen voor de Gassensor MQ-5 module (OT2018-D55) Omdat dit een mooie kleine sensor is die wij makkelijk kwijt kunnen op de kobuki.
Voor de o2 sensor hebben wij gekozen voor de Gravity: Elektrochemische zuurstof-/O2-sensor (0-25%Vol, I2C) SEN0322. Deze sensor is helaas op het moment van schrijven (29-10-2024) niet op voorraad dus deze sensor kunnen wij helaas nog niet toevoegen. Zodra deze sensor op voorraad is zal ik deze bestellen en aan de esp toevoegen.
## Sensor uitleg
#### Dht11
De dht11 is een eenvoudige en goedkope sensor die wordt gebruikt om de temperatuur en luchtvochtigheid te meten.
De sensor bevat de volgende onderdelen om te werken:
- Een thermistor : Dit is een component die temperatuur meet door variaties in elektronische weerstand.
- Een capacitieve vochtigheidssensor : Deze meet de relatieve luchtvochtigheid door de verandering in het materiaal tussen de condensatorplaten te meten. Deze verandering gebeurt door de waterdamp in de lucht.
- Een geïntegreerde microcontroller : Deze microcontroller verwerkt de gegevens van de sensoren en zet deze om in een digitaal signaal.
Het meetbereik van de sensor is 0 tot 50 graden voor temperatuur en voor de luchtvochtigheid is het 20 tot 90%
Hierbij is de temperatuur tot ±2 graden nauwkeurig en de luchtvochtigheid ±5 procent.
De DHT11 kan aangesloten worden op een 3.3 of 5 volt voeding.
Wij kunnen deze sensor dus zonder problemen compleet aansluiten op de esp32s3
#### Tvoc/eC02 Gas Unit
De M5Stack TVOC/eCO2-Gassensensor-eenheid (SGP30) is een compacte sensor ontwikkeld om vluchtige organische stoffen (TVOC) en schijnbare CO₂-concentraties (eCO2) te meten.
Deze component maakt gebruik van de SGP30-sensor van Adafruit
De SGP30 is gebaseerd op een metal-oxide (MOX) halfgeleidertechnologie.
Deze technologie detecteert veranderingen in elektrische weerstand bij blootstelling aan vluchtige organische stoffen (VOC's),
zoals ethanol en aceton.
De sensor bevat ingebouwde algoritmes om de gemeten VOC waarden om te zetten in tvoc en eco2.
- TVOC : Dit is de totale concentratie vluchtige organische stoffen.
- ECO2 : Dit is een geschatte koolstofdioxideconcentratie.
Dit is een schatting op basis van de VOC metingen.
Deze sensor werkt op 3.3 en 5 volt dus ook voor deze sensor kunnen wij de esp32s3 gebruiken.
#### MQ5 Gassensor
De MQ5-gassensor is een veelgebruikte sensor voor het detecteren van brandbare gassen, zoals aardgas (methaan), vloeibaar petroleumgas (LPG), waterstof en koolmonoxide. Het werkt op basis van veranderingen in elektrische weerstand van het sensorelement wanneer het wordt blootgesteld aan specifieke gassen.
De kern van de MQ5 sensor is een chemisch gecoat metalen oxide (meestal tinoxide).
Dit materiaal reageert op de aanwezigheid van brandbare gassen.
Wanneer de sensor gasdeeltjes detecteert, reageren deze met zuurstofionen op het oppervlak van het tinoxide. Deze reactie veroorzaakt een verandering in de elektrische geleidbaarheid (weerstand) van het materiaal.
De verandering in weerstand wordt door een elektronisch circuit omgezet in een elektrisch signaal dat de concentratie van gas vertegenwoordigt.
De MQ5 sensor heeft ook een ingebouwde verwarmingsspiraal die het sensorelement op een hoge temperatuur houdt (ongeveer 300-500°C). Deze temperatuur zorgt ervoor dat gassen efficiënt reageren met het tinoxide-oppervlak.
Het enige nadeel van deze sensor is dat hij niet selectief is dus de sensor kan geen onderscheid maken tussen bijvoorbeeld methaan en lpg.
## Aansluitschema
![Afbeelding aansluitschema](images/Aansluitschema_sensors.png)
Hierboven is te zien hoe wij de sensoren hebben aangesloten op de esp32.

BIN
docs/explanation/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,33 @@
# Wat gaan we maken
## Sensoren
* Camera
* GPS module
* Temparatuur sensor
* TVOC sensor
* ECO2 sensor
* LDR sensor
* Time of Flight sensor
## Wat gaan we met de sensoren doen?
### Camera
De camera word gebruikt om foto's te maken in de omgeving in het geval van informatie verkrijgen voor als de robot bijvoorbeeld vast zit, geeft ook optie om informatie te krijgen zonder op de plek zelf te zijn.
### GPS module
De GPS module word gebruikt om de locatie van de robot te bepalen en aan te geven waar bijzonderheden bevinden.
### Temparatuur, TVOC en ECO2 sensor
Deze sensoren zijn bedoeld om de omgeving te meten en te kijken of de omgeving veilig is voor mensen om in te gaan.
### LDR sensor
De LDR sensor word gebruikt om de lichtsterkte te meten en te kijken of er een lamp op de robot aan moet gaan voor de camera.
### Time of Flight sensor
De Time of Flight sensor word gebruikt om de afstand te meten tussen de robot en de muur, zodat de robot niet tegen de muur aan botst.
## Het project
Bij brand of op fabrieksterreinen met gevaarlijke stoffen kan het nodig zijn om een verkenning te
doen van een verdachte omgeving. Het is dan niet verstandig om mensen naar binnen te sturen, in
die gevallen vallen de hulpdiensten terug om een verkenningsrobot. Het doel van het project is het
realiseren van een verkenningsrobot die zelfstandig een gevaarlijke omgeving in kaart kan brengen.

View File

@@ -0,0 +1,123 @@
#include <DHT.h>
#include <Wire.h>
#include "Adafruit_SGP30.h"
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoWebsockets.h>
using namespace websockets;
Adafruit_SGP30 sgp;
// Definieert de pins voor de sensoren
#define DHTPIN 4
#define DHTTYPE DHT11
#define MQ5_PIN 2
#define SDA_PIN 10
#define SCL_PIN 11
DHT dht(DHTPIN, DHTTYPE);
// WiFi en MQTT instellingen
const char* ssid = "";
const char* password = "";
const char* mqtt_server = "192.168.68.104";
const int mqtt_port = 8080; //websocket-poort
const char* mqtt_topic = "sensors/data";
// MQTT client
WiFiClient espClient;
WebsocketsClient websocket;
PubSubClient client(espClient);
// Functie om verbinding te maken met WiFi
void setup_wifi() {
Serial.print("Verbinden met WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Verbonden!");
}
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("Verbinding maken met MQTT via WebSockets...");
if (client.connect("ESP32Client")) {
Serial.println("Verbonden!");
} else {
Serial.print("Fout: ");
Serial.print(client.state());
delay(5000);
}
}
}
void setup() {
// Start de seriële monitor
Serial.begin(9600);
dht.begin();
pinMode(MQ5_PIN, INPUT);
Wire.begin(SDA_PIN, SCL_PIN);
Serial.println("SGP30 test");
// SGP30 initialiseren
if (!sgp.begin()) {
Serial.println("SGP30 sensor niet gevonden :(");
while (1);
}
if (!sgp.IAQinit()) {
Serial.println("SGP30 IAQ-initialisatie mislukt!");
while (1);
}
// Verbind met WiFi en MQTT-broker
setup_wifi();
// Stel MQTT-broker in met websockets
client.setServer(mqtt_server, mqtt_port);
reconnectMQTT();
}
void loop() {
// Zorgt ervoor dat MQTT verbonden blijft
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
float h = dht.readHumidity();
float t = dht.readTemperature();
int mq5Value = analogRead(MQ5_PIN);
// Check of de sensorwaarden geldig zijn
if (isnan(h) || isnan(t) || mq5Value < 0) {
Serial.println("Fout bij het lezen van de sensors!");
return;
}
// Maak een JSON-payload
String payload = "{";
payload += "\"humidity\":" + String(h) + ",";
payload += "\"temperature\":" + String(t) + ",";
payload += "\"mq5\":" + String(mq5Value) + ",";
payload += "\"tvoc\":" + String(sgp.TVOC) + ",";
payload += "\"eco2\":" + String(sgp.eCO2);
payload += "}";
// Verzend de payload via MQTT
if (client.publish(mqtt_topic, payload.c_str())) {
Serial.println("Bericht verzonden: " + payload);
} else {
Serial.println("Fout bij verzenden van bericht!");
}
// Wacht 5 seconden voor de volgende meting
delay(5000);
}

View File

@@ -0,0 +1,40 @@
// Test code is merged to main sensor code os this file is not needed anymore
#include <Wire.h>
#include "Adafruit_SGP30.h"
Adafruit_SGP30 sgp;
#define SDA_PIN 10
#define SCL_PIN 11
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); }
Wire.begin(SDA_PIN, SCL_PIN);
Serial.println("SGP30 test");
if (!sgp.begin()) {
Serial.println("SGP30 sensor not found :(");
while (1);
}
// Start measurements (initialize baseline)
if (! sgp.IAQinit()) {
Serial.println("SGP30 IAQinit failed!");
while (1);
}
}
void loop() {
if (! sgp.IAQmeasure()) {
Serial.println("Measurement failed");
return;
}
Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");
delay(1000); // 1 second delay
}

View File

@@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.9)
project(kobuki_control)
set(CMAKE_CXX_STANDARD 23)
set(SOURCE_FILES
src/KobukiParser.cpp
src/KobukiParser.h
src/CKobuki.cpp
src/CKobuki.h
src/test.cpp)
src/main.cpp)
add_executable(kobuki_control ${SOURCE_FILES})
#target_link_libraries(kobuki_control )

View File

@@ -3,6 +3,7 @@
#include "termios.h"
#include <cstddef>
#include <iostream>
#include <thread>
// plot p;
@@ -302,203 +303,6 @@ int CKobuki::measure()
return 0;
}
// int CKobuki::parseKobukiMessage(TKobukiData &output, unsigned char *data)
// {
// int rtrnvalue = checkChecksum(data);
// // ak je zly checksum,tak kaslat na to
// if (rtrnvalue != 0)
// return -2;
// int checkedValue = 1;
// // kym neprejdeme celu dlzku
// while (checkedValue < data[0])
// {
// // basic data subload
// if (data[checkedValue] == 0x01)
// {
// checkedValue++;
// if (data[checkedValue] != 0x0F)
// return -1;
// checkedValue++;
// output.timestamp = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.BumperCenter = data[checkedValue] && 0x02;
// output.BumperLeft = data[checkedValue] && 0x04;
// output.BumperRight = data[checkedValue] && 0x01;
// checkedValue++;
// output.WheelDropLeft = data[checkedValue] && 0x02;
// output.WheelDropRight = data[checkedValue] && 0x01;
// checkedValue++;
// output.CliffCenter = data[checkedValue] && 0x02;
// output.CliffLeft = data[checkedValue] && 0x04;
// output.CliffRight = data[checkedValue] && 0x01;
// checkedValue++;
// output.EncoderLeft = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.EncoderRight = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.PWMleft = data[checkedValue];
// checkedValue++;
// output.PWMright = data[checkedValue];
// checkedValue++;
// output.ButtonPress = data[checkedValue];
// checkedValue++;
// output.Charger = data[checkedValue];
// checkedValue++;
// output.Battery = data[checkedValue];
// checkedValue++;
// output.overCurrent = data[checkedValue];
// checkedValue++;
// }
// else if (data[checkedValue] == 0x03)
// {
// checkedValue++;
// if (data[checkedValue] != 0x03)
// return -3;
// checkedValue++;
// output.IRSensorRight = data[checkedValue];
// checkedValue++;
// output.IRSensorCenter = data[checkedValue];
// checkedValue++;
// output.IRSensorLeft = data[checkedValue];
// checkedValue++;
// }
// else if (data[checkedValue] == 0x04)
// {
// checkedValue++;
// if (data[checkedValue] != 0x07)
// return -4;
// checkedValue++;
// output.GyroAngle = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.GyroAngleRate = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 5; // 3 unsued
// }
// else if (data[checkedValue] == 0x05)
// {
// checkedValue++;
// if (data[checkedValue] != 0x06)
// return -5;
// checkedValue++;
// output.CliffSensorRight =
// data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.CliffSensorCenter =
// data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.CliffSensorLeft =
// data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// }
// else if (data[checkedValue] == 0x06)
// {
// checkedValue++;
// if (data[checkedValue] != 0x02)
// return -6;
// checkedValue++;
// output.wheelCurrentLeft = data[checkedValue];
// checkedValue++;
// output.wheelCurrentRight = data[checkedValue];
// checkedValue++;
// }
// else if (data[checkedValue] == 0x0A)
// {
// checkedValue++;
// if (data[checkedValue] != 0x04)
// return -7;
// checkedValue++;
// output.extraInfo.HardwareVersionPatch = data[checkedValue];
// checkedValue++;
// output.extraInfo.HardwareVersionMinor = data[checkedValue];
// checkedValue++;
// output.extraInfo.HardwareVersionMajor = data[checkedValue];
// checkedValue += 2;
// }
// else if (data[checkedValue] == 0x0B)
// {
// checkedValue++;
// if (data[checkedValue] != 0x04)
// return -8;
// checkedValue++;
// output.extraInfo.FirmwareVersionPatch = data[checkedValue];
// checkedValue++;
// output.extraInfo.FirmwareVersionMinor = data[checkedValue];
// checkedValue++;
// output.extraInfo.FirmwareVersionMajor = data[checkedValue];
// checkedValue += 2;
// }
// else if (data[checkedValue] == 0x0D)
// {
// checkedValue++;
// if (data[checkedValue] % 2 != 0)
// return -9;
// checkedValue++;
// output.frameId = data[checkedValue];
// checkedValue++;
// int howmanyFrames = data[checkedValue] / 3;
// checkedValue++;
// output.gyroData.reserve(howmanyFrames);
// output.gyroData.clear();
// for (int hk = 0; hk < howmanyFrames; hk++)
// {
// TRawGyroData temp;
// temp.x = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// temp.y = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// temp.z = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.gyroData.push_back(temp);
// }
// }
// else if (data[checkedValue] == 0x10)
// {
// checkedValue++;
// if (data[checkedValue] != 0x10)
// return -10;
// checkedValue++;
// output.digitalInput = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.analogInputCh0 = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.analogInputCh1 = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.analogInputCh2 = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 2;
// output.analogInputCh3 = data[checkedValue + 1] * 256 + data[checkedValue];
// checkedValue += 8; // 2+6
// }
// else if (data[checkedValue] == 0x13)
// {
// checkedValue++;
// if (data[checkedValue] != 0x0C)
// return -11;
// checkedValue++;
// output.extraInfo.UDID0 = data[checkedValue + 3] * 256 * 256 * 256 +
// data[checkedValue + 2] * 256 * 256 +
// data[checkedValue + 1] * 256 +
// data[checkedValue];
// checkedValue += 4;
// output.extraInfo.UDID1 = data[checkedValue + 3] * 256 * 256 * 256 +
// data[checkedValue + 2] * 256 * 256 +
// data[checkedValue + 1] * 256 +
// data[checkedValue];
// checkedValue += 4;
// output.extraInfo.UDID2 = data[checkedValue + 3] * 256 * 256 * 256 +
// data[checkedValue + 2] * 256 * 256 +
// data[checkedValue + 1] * 256 +
// data[checkedValue];
// checkedValue += 4;
// }
// else
// {
// checkedValue++;
// checkedValue += data[checkedValue] + 1;
// }
// }
// return 0;
// }
long double CKobuki::gyroToRad(signed short GyroAngle)
{
@@ -607,6 +411,7 @@ long CKobuki::loop(void *user_data, TKobukiData &Kobuki_data)
static long counter = 0;
//vector for data plotting
vectorX.push_back(gx);
vectorY.push_back(gy);
vectorGyroTheta.push_back(gyroTheta);
@@ -782,7 +587,10 @@ void CKobuki::goToXy(long double xx, long double yy)
return;
}
void CKobuki::forward(int speedvalue, long double distance) {
/// @brief Makes the Kobuki go forward
/// @param speedvalue speed of robot in mm/s
/// @param distance distance in meters
void CKobuki::forward(int speedvalue) {
// Use the goStraight logic to determine the speed and distance
// Calculate the actual speed and radius values based on the conversion table
@@ -803,6 +611,69 @@ unsigned char message[11] = {
};
// Calculate checksum
message[10] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^
message[7] ^ message[8] ^ message[9];
// Send the message
uint32_t pocet;
pocet = write(HCom, &message, 11);
pocet = write(HCom, &message, 11);
}
/// @brief Makes the kobuki rotate
/// @param degrees Rotation in degrees
void CKobuki::Rotate(int degrees) {
// convert raidans to degrees
float radians = degrees * PI / 180.0;
// Calculate the rotation speed in radians per second
double radpersec = 1;
// calculator rotation time and give absolute value
float rotation_time = std::abs(radians / radpersec);
// Use original function to set the rotation speed in mm/s
setRotationSpeed(radians);
// Sleep for the calculated rotation time
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(rotation_time * 1000)));
// Stop the robot after the rotation
setRotationSpeed(0);
}
void CKobuki::robotSafety() {
while (true) {
if (parser.data.BumperCenter || parser.data.BumperLeft || parser.data.BumperRight ||
parser.data.CliffLeft || parser.data.CliffCenter || parser.data.CliffRight) {
std::cout << "Safety condition triggered!" << std::endl; // Debug print
forward(-100); // reverse the robot
}
}
}
void CKobuki::sendNullMessage(){
unsigned char message[11] = {
0xaa, // Start byte 1
0x55, // Start byte 2
0x08, // Payload length (the first 2 bytes dont count)
0x01, // payload type (0x01 = control command)
0x04, // Control byte or additional identifier
0x00, // Lower byte of speed value
0x00, // Upper byte of speed value
0x00, // Placeholder for radius
0x00, // Placeholder for radius
0x00 // Placeholder for checksum
};
message[10] = message[2] ^ message[3] ^ message[4] ^ message[5] ^ message[6] ^
message[7] ^ message[8] ^ message[9];

View File

@@ -35,91 +35,6 @@
using namespace std;
// typedef struct
// {
// unsigned short x;
// unsigned short y;
// unsigned short z;
// }TRawGyroData;
// typedef struct
// {
// //Hardware Version
// unsigned char HardwareVersionMajor;
// unsigned char HardwareVersionMinor;
// unsigned char HardwareVersionPatch;
// //Firmware Version
// unsigned char FirmwareVersionMajor;
// unsigned char FirmwareVersionMinor;
// unsigned char FirmwareVersionPatch;
// //Unique Device IDentifier(UDID)
// unsigned int UDID0;
// unsigned int UDID1;
// unsigned int UDID2;
// //Controller Info
// unsigned char PIDtype;
// unsigned int PIDgainP;
// unsigned int PIDgainI;
// unsigned int PIDgainD;
// }TExtraRequestData;
// typedef struct
// {
// //---basic package
// unsigned short timestamp;
// //bumpers
// bool BumperLeft;
// bool BumperCenter;
// bool BumperRight;
// //cliff
// bool CliffLeft;
// bool CliffCenter;
// bool CliffRight;
// // wheel drop
// bool WheelDropLeft;
// bool WheelDropRight;
// //wheel rotation
// unsigned short EncoderRight;
// unsigned short EncoderLeft;
// unsigned char PWMright;
// unsigned char PWMleft;
// //buttons
// unsigned char ButtonPress;// 0 no, 1 2 4 for button 0 1 2 (7 is all three)
// //power
// unsigned char Charger;
// unsigned char Battery;
// unsigned char overCurrent;
// //---docking ir
// unsigned char IRSensorRight;
// unsigned char IRSensorCenter;
// unsigned char IRSensorLeft;
// //---Inertial Sensor Data
// signed short GyroAngle;
// unsigned short GyroAngleRate;
// //---Cliff Sensor Data
// unsigned short CliffSensorRight;
// unsigned short CliffSensorCenter;
// unsigned short CliffSensorLeft;
// //---Current
// unsigned char wheelCurrentLeft;
// unsigned char wheelCurrentRight;
// //---Raw Data Of 3D Gyro
// unsigned char frameId;
// std::vector<TRawGyroData> gyroData;
// //---General Purpose Input
// unsigned short digitalInput;
// unsigned short analogInputCh0;
// unsigned short analogInputCh1;
// unsigned short analogInputCh2;
// unsigned short analogInputCh3;
// //---structure with data that appears only on request
// TExtraRequestData extraInfo;
// }TKobukiData;
typedef long(*src_callback_kobuki_data) (void *user_data, TKobukiData &Kobuki_data);
class CKobuki
@@ -156,10 +71,13 @@ public:
// control functions
void goStraight(long double distance);
void forward(int speedvalue, long double distance);
void forward(int speedvalue);
void doRotation(long double th);
void goToXy(long double xx, long double yy);
void Rotate(int degrees);
std::ofstream odometry_log;
void robotSafety();
void sendNullMessage();
KobukiParser parser;

View File

@@ -1,6 +1,6 @@
#include "KobukiParser.h"
#include <iostream>
//moet checkenvalue gebruiken of moet kijken naar de payloadlength welke dingen er extra zijn
int KobukiParser::parseKobukiMessage(TKobukiData &output, unsigned char *data) {
int rtrnvalue = checkChecksum(data);
if (rtrnvalue != 0) {
@@ -96,7 +96,6 @@ int KobukiParser::parseKobukiMessage(TKobukiData &output, unsigned char *data) {
break;
default:
std::cerr << "Unknown data type: " << std::hex << static_cast<int>(dataType) << std::dec << std::endl;
checkedValue += dataLength;
break;
}
@@ -126,7 +125,9 @@ void KobukiParser::parseBasicData(TKobukiData &output, unsigned char *data, int
checkedValue++;
output.PWMright = data[checkedValue];
checkedValue++;
output.ButtonPress = data[checkedValue];
output.ButtonPress1 = data[checkedValue] & 0x01;
output.ButtonPress2 = data[checkedValue] & 0x02;
output.ButtonPress3 = data[checkedValue] & 0x04;
checkedValue++;
output.Charger = data[checkedValue];
checkedValue++;
@@ -153,12 +154,12 @@ void KobukiParser::parseGyroData(TKobukiData &output, unsigned char *data, int &
}
void KobukiParser::parseCliffSensorData(TKobukiData &output, unsigned char *data, int &checkedValue) {
output.CliffSensorRight = data[checkedValue];
checkedValue++;
output.CliffSensorCenter = data[checkedValue];
checkedValue++;
output.CliffSensorLeft = data[checkedValue];
checkedValue++;
output.CliffSensorRight = (data[checkedValue] << 8) | data[checkedValue + 1];
checkedValue += 2;
output.CliffSensorCenter = (data[checkedValue] << 8) | data[checkedValue + 1];
checkedValue += 2;
output.CliffSensorLeft = (data[checkedValue] << 8) | data[checkedValue + 1];
checkedValue += 2;
}
void KobukiParser::parseWheelCurrentData(TKobukiData &output, unsigned char *data, int &checkedValue){

View File

@@ -19,7 +19,8 @@ struct TKobukiData {
int CliffCenter, CliffLeft, CliffRight;
int EncoderLeft, EncoderRight;
int PWMleft, PWMright;
int ButtonPress, Charger, Battery, overCurrent;
int ButtonPress1, ButtonPress2, ButtonPress3;
int Charger, Battery, overCurrent;
int IRSensorRight, IRSensorCenter, IRSensorLeft;
int GyroAngle, GyroAngleRate;
int CliffSensorRight, CliffSensorCenter, CliffSensorLeft;

View File

@@ -8,42 +8,46 @@ using namespace std;
CKobuki robot;
int movement();
int checkCenterCliff();
void logToFile();
int main()
{
unsigned char *null_ptr(0);
robot.startCommunication("/dev/ttyUSB0", true, null_ptr);
// thread mv(movement);
// mv.join(); //only exit once thread one is done running
checkCenterCliff();
std::thread safety([&robot]()
{ robot.robotSafety(); }); // use a lambda function to call the member function
safety.detach();
thread movementThread(movement);
movementThread.join(); // so the program doesnt quit
return 0;
}
int checkCenterCliff()
{
while(true){
std::cout << robot.parser.data.CliffSensorCenter << endl;
while (true)
{
std::cout << robot.parser.data.CliffSensorRight << endl;
}
}
int movement()
{
int text;
while (true)
{
cout << "gimme input: ";
cin >> text;
if (text == 1)
{
robot.forward(1024, 1);
robot.forward(400);
}
else if (text == 2)
{
// 1 is full circle
robot.doRotation(0.25);
robot.Rotate(90);
}
else if (text == 3)
{
@@ -63,3 +67,70 @@ int movement()
}
}
}
void logToFile()
{
while (true)
{
TKobukiData robotData = robot.parser.data;
std::ofstream outputFile("log", std::ios_base::app); // Open file in append mode to not overwrite own content
if (outputFile.is_open())
{ // check if the file was opened successfully
// Get current time
std::time_t now = std::time(nullptr);
outputFile << "Timestamp: " << std::ctime(&now);
// Write data to the file
outputFile << "analogInputCh0: " << robotData.analogInputCh0 << "\n";
outputFile << "analogInputCh1: " << robotData.analogInputCh1 << "\n";
outputFile << "analogInputCh2: " << robotData.analogInputCh2 << "\n";
outputFile << "analogInputCh3: " << robotData.analogInputCh3 << "\n";
outputFile << "digitalInput: " << robotData.digitalInput << "\n";
outputFile << "timestamp: " << robotData.timestamp << "\n";
outputFile << "BumperCenter: " << robotData.BumperCenter << "\n";
outputFile << "BumperLeft: " << robotData.BumperLeft << "\n";
outputFile << "BumperRight: " << robotData.BumperRight << "\n";
outputFile << "WheelDropLeft: " << robotData.WheelDropLeft << "\n";
outputFile << "WheelDropRight: " << robotData.WheelDropRight << "\n";
outputFile << "CliffCenter: " << robotData.CliffCenter << "\n";
outputFile << "CliffLeft: " << robotData.CliffLeft << "\n";
outputFile << "CliffRight: " << robotData.CliffRight << "\n";
outputFile << "EncoderLeft: " << robotData.EncoderLeft << "\n";
outputFile << "EncoderRight: " << robotData.EncoderRight << "\n";
outputFile << "PWMleft: " << robotData.PWMleft << "\n";
outputFile << "PWMright: " << robotData.PWMright << "\n";
outputFile << "ButtonPress: " << robotData.ButtonPress1 << "\n";
outputFile << "ButtonPress: " << robotData.ButtonPress2 << "\n";
outputFile << "ButtonPress: " << robotData.ButtonPress3 << "\n";
outputFile << "Charger: " << robotData.Charger << "\n";
outputFile << "Battery: " << robotData.Battery << "\n";
outputFile << "overCurrent: " << robotData.overCurrent << "\n";
outputFile << "IRSensorRight: " << robotData.IRSensorRight << "\n";
outputFile << "IRSensorCenter: " << robotData.IRSensorCenter << "\n";
outputFile << "IRSensorLeft: " << robotData.IRSensorLeft << "\n";
outputFile << "GyroAngle: " << robotData.GyroAngle << "\n";
outputFile << "GyroAngleRate: " << robotData.GyroAngleRate << "\n";
outputFile << "CliffSensorRight: " << robotData.CliffSensorRight << "\n";
outputFile << "CliffSensorCenter: " << robotData.CliffSensorCenter << "\n";
outputFile << "CliffSensorLeft: " << robotData.CliffSensorLeft << "\n";
outputFile << "wheelCurrentLeft: " << robotData.wheelCurrentLeft << "\n";
outputFile << "wheelCurrentRight: " << robotData.wheelCurrentRight << "\n";
outputFile << "frameId: " << robotData.frameId << "\n";
outputFile << "HardwareVersionPatch: " << robotData.extraInfo.HardwareVersionPatch << "\n";
outputFile << "HardwareVersionMinor: " << robotData.extraInfo.HardwareVersionMinor << "\n";
outputFile << "HardwareVersionMajor: " << robotData.extraInfo.HardwareVersionMajor << "\n";
outputFile << "FirmwareVersionPatch: " << robotData.extraInfo.FirmwareVersionPatch << "\n";
outputFile << "FirmwareVersionMinor: " << robotData.extraInfo.FirmwareVersionMinor << "\n";
outputFile << "FirmwareVersionMajor: " << robotData.extraInfo.FirmwareVersionMajor << "\n";
outputFile << "UDID0: " << robotData.extraInfo.UDID0 << "\n";
outputFile << "UDID1: " << robotData.extraInfo.UDID1 << "\n";
outputFile << "UDID2: " << robotData.extraInfo.UDID2 << "\n";
outputFile.close();
}
else
{
std::cerr << "Error opening file\n";
}
std::this_thread::sleep_for(std::chrono::seconds(2)); // Sleep for 2 seconds
}
}