10 Commits
Author SHA1 Message Date
kleiax f0f75d3fd3 - deactivate a debug print
- activate init screen
- update network config
2024-07-19 15:33:50 +02:00
kleiax a7930e2915 more refactor bug fixes 2023-10-13 14:17:51 +02:00
kleiax f0474027be remove CalcAzimuth 2023-10-12 20:58:30 +02:00
kleiax 12c338def1 fix merge bugs 2023-10-12 20:50:59 +02:00
kleiax e511afb2a5 Merge branch 'main' into projektarbeit 2023-10-12 20:35:31 +02:00
kleiax f78804d836 first build 2023-09-04 14:13:14 +02:00
kleiax 682a99ffea Merge branch 'main' into projektarbeit 2023-09-04 13:35:40 +02:00
kleiax d7a9e9cfd8 delete everthing for bachelore 2023-09-02 18:34:06 +02:00
kleiax fd946f2aa3 Merge branch 'main' into projektarbeit 2023-09-02 18:31:46 +02:00
kleiax 4e2b5bd347 delete old debug python files 2023-09-02 17:51:16 +02:00
44 changed files with 39 additions and 4124 deletions
+2
View File
@@ -129,6 +129,7 @@
"carr", "carr",
"CIPO", "CIPO",
"COPI", "COPI",
"deadzone",
"Doxygen", "Doxygen",
"Dutycycle", "Dutycycle",
"gast", "gast",
@@ -150,6 +151,7 @@
"Punica", "Punica",
"RHEDE", "RHEDE",
"Rtcm", "Rtcm",
"Sats",
"Schalke", "Schalke",
"Soln", "Soln",
"Systeminformation", "Systeminformation",
-25
View File
@@ -1,25 +0,0 @@
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe("Rover/Info")
client.subscribe("Rover/Warn")
client.subscribe("Rover/Error")
def on_message(client, userdata, msg):
print(msg.topic+" -> "+str(msg.payload)[2:-1])
if __name__ == '__main__':
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("172.22.64.216", 1883, 60)
client.loop_forever()
-23
View File
@@ -1,23 +0,0 @@
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe("Rover/Debug")
def on_message(client, userdata, msg):
print(msg.topic+" -> "+str(msg.payload)[2:-1])
if __name__ == '__main__':
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("172.22.64.216", 1883, 60)
client.loop_forever()
-27
View File
@@ -1,27 +0,0 @@
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe("Rover/Info")
client.subscribe("Rover/Warn")
client.subscribe("Rover/Error")
client.subscribe("Rover/Info")
def on_message(client, userdata, msg):
print(msg.topic+" -> "+str(msg.payload)[2:-1])
if __name__ == '__main__':
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set("kleiax", password="p?{$_~5%hBM7wrcFkr55KWr#")
client.connect("192.168.1.7", 1883, 60)
client.loop_forever()
-24
View File
@@ -1,24 +0,0 @@
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe("Rover/Debug")
def on_message(client, userdata, msg):
print(msg.topic+" -> "+str(msg.payload)[2:-1])
if __name__ == '__main__':
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set("kleiax", password="p?{$_~5%hBM7wrcFkr55KWr#")
client.connect("192.168.1.7", 1883, 60)
client.loop_forever()
-157
View File
@@ -1,157 +0,0 @@
<diagram program="umletino" version="14.4.0-SNAPSHOT"><zoom_level>10</zoom_level><element><id>UMLClass</id><coordinates><x>750</x><y>10</y><w>220</w><h>650</h></coordinates><panel_attributes>&lt;&lt;hardware&gt;&gt;
MotorControl
--
- target_power: int8_t
- power: int8_t
- direction: uint8_t
- pwm_pin: uint8_t
- pwm_channel: uint8_t
- pwm_res: uint8_t
- dutycycle_min: uint8_t
- dutycycle_max: uint8_t
- direction_1: uint8_t
- direction_2: uint8_t
- delay: uint8_t
- powersteps: uint8_t
- last_millis: uint32_t
--
+ MotorControl()
+ init(pwm_pin: uint8_t,
  pwm_channel: uint8_t,
  dir_1: uint8_t, dir_2: uint8_t)
+ loop(): uint16_t
+ runMotorControl()
+ setMinPwm(uint8_t)
+ setMaxPwm(uint8_t)
+ setPowerSteps(uint8_t): uint16_t
+ setTargetPower(uint8_t)
+ setDelay(uint8_t): uint16_t
+ stop()
+ emergencyStop()
+ toString()
+ getPower(): int8_t
+ getTargetPower(): int8_t
+ isTargetPowerReached(): bool
+ isAccelerationPositive(): bool
+ isAccelerationNegative(): bool
- setRealPower(power: int8_t)
- increasePower(power: int8_t)
</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>80</x><y>380</y><w>220</w><h>330</h></coordinates><panel_attributes>&lt;&lt;hardware&gt;&gt;
Speedometer
--
- encoder: ESP32Encoder
- debug: DebugMqtt*
- name: String
- speed: double = 0
- last_millis: uint64_t = 0;
- bufPos: uint8_t
- buf: int16_t[BUF_SIZE]
--
+ Speedometer()
+ init(pinA: uint8_t,
   pinB: uint8_t,
   name: String)
+ runSpeedometer()
+ setTargetPower(power: int8_t)
+ getSpeed(): double
+ getDirection(): uint8_t
- addValToBuf(val: int16_t)
- getAverage(): int16_t</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>70</x><y>0</y><w>270</w><h>370</h></coordinates><panel_attributes>MoveControl
--
- debug: DebugMqtt*
- left_motor: MotorControl*
- right_motor: MotorControl*
- left_speedometer: Speedometer*
- right_speedometer: Speedometer*
- driving_status: DrivingStatus = stop
- x_speed: double = 0
- rotation_speed: double = 0
- wheelspeed_left_target: double = 0
- wheelspeed_right_target: double = 0
--
+ MoveControl()
+ init(left_motor: MotorControl*,
   right_motor: MotorControl*,
   left_speedometer: Speedometer*,
   right_speedometer: Speedometer*)
+ runMoveControl()
+ setDrivingStatus(status: DrivingStatus)
+ setSpeed(speed: double)
+ setRotationspeed(speed: double)
- calcWheelSpeed()
- regulateMotors()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>370</x><y>10</y><w>220</w><h>330</h></coordinates><panel_attributes>&lt;&lt;driveModi&gt;&gt;
ManualControl
--
- encoder: ESP32Encoder
- debug: DebugMqtt*
- name: String
- speed: double = 0
- last_millis: uint64_t = 0;
- bufPos: uint8_t
- buf: int16_t[BUF_SIZE]
--
+ Speedometer()
+ init(pinA: uint8_t,
   pinB: uint8_t,
   name: String)
+ runSpeedometer()
+ setTargetPower(power: int8_t)
+ getSpeed(): double
+ getDirection(): uint8_t
- addValToBuf(val: int16_t)
- getAverage(): int16_t</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1270</x><y>10</y><w>210</w><h>240</h></coordinates><panel_attributes>MenuControl
--
# parentMenu: MenuControl*
# lcd: LiquidCrystal_I2C*
--
/+down()/
/+up()/
/+right()/
/+left()/
/+yes()/
/+no()/
/+update()/
/+printMenu()/
+ setParentMenu(MenuControl*)
+ setLcd(LiquidCrystal_I2C*)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>980</x><y>10</y><w>280</w><h>270</h></coordinates><panel_attributes>MenuAction
--
- name: char*
- *function: void
- *callback: void
- isMenu: bool
- menu: MenuControl
--
+ MenuAction(const char*, (*function), (*callback))
+ MenuAction(const char*, (*function))
+ MenuAction(const char*, MenuControl* menu)
+ runAction()
+ getName(): const char*
+ getIsMenu(): bool
+ getMenu(): MenuControl*
</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1220</x><y>360</y><w>280</w><h>160</h></coordinates><panel_attributes>Menu
--
- inSubmenu: bool
- entrys: list&lt;MenuAction*&gt;
- selectedEntry: list&lt;MenuAction*&gt;::iterator
- isMenu: bool
- menu: MenuControl
--
+ addEntry(MenuAction* entry)
</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1350</x><y>240</y><w>30</w><h>140</h></coordinates><panel_attributes>lt=&lt;&lt;-</panel_attributes><additional_attributes>10;10;10;120</additional_attributes></element><element><id>Relation</id><coordinates><x>1080</x><y>270</y><w>160</w><h>190</h></coordinates><panel_attributes>lt=-
m1=*
m2=0..1</panel_attributes><additional_attributes>10;10;10;160;140;160</additional_attributes></element></diagram>
-390
View File
@@ -1,390 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<diagram program="umlet" version="14.3.0">
<zoom_level>10</zoom_level>
<element>
<id>UMLSpecialState</id>
<coordinates>
<x>40</x>
<y>20</y>
<w>20</w>
<h>20</h>
</coordinates>
<panel_attributes>type=initial</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>40</x>
<y>20</y>
<w>130</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>110.0;10.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>150</x>
<y>10</y>
<w>100</w>
<h>40</h>
</coordinates>
<panel_attributes>search next point
bg=green</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLSpecialState</id>
<coordinates>
<x>180</x>
<y>90</y>
<w>40</w>
<h>40</h>
</coordinates>
<panel_attributes>bg=green
type=decision</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>190</x>
<y>40</y>
<w>30</w>
<h>70</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;50.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>150</x>
<y>180</y>
<w>100</w>
<h>40</h>
</coordinates>
<panel_attributes>detect alignment
bg=green</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>190</x>
<y>120</y>
<w>130</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-
[distance &lt;= 5m]</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>UMLObject</id>
<coordinates>
<x>20</x>
<y>0</y>
<w>840</w>
<h>590</h>
</coordinates>
<panel_attributes>Autopilot
valign=top</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>210</x>
<y>90</y>
<w>140</w>
<h>40</h>
</coordinates>
<panel_attributes>lt=&lt;-
[distance &gt; 5m]</panel_attributes>
<additional_attributes>120.0;20.0;10.0;20.0</additional_attributes>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>330</x>
<y>90</y>
<w>100</w>
<h>40</h>
</coordinates>
<panel_attributes>Error
bg=red</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>150</x>
<y>270</y>
<w>100</w>
<h>40</h>
</coordinates>
<panel_attributes>correct alignment
bg=green</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>150</x>
<y>360</y>
<w>100</w>
<h>40</h>
</coordinates>
<panel_attributes>drive to point
bg=green</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>190</x>
<y>210</y>
<w>30</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>190</x>
<y>300</y>
<w>30</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>90</x>
<y>280</y>
<w>80</w>
<h>120</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>60.0;10.0;10.0;10.0;10.0;100.0;60.0;100.0</additional_attributes>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>440</x>
<y>10</y>
<w>410</w>
<h>300</h>
</coordinates>
<panel_attributes>detect alignment
valign=top</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLSpecialState</id>
<coordinates>
<x>460</x>
<y>60</y>
<w>20</w>
<h>20</h>
</coordinates>
<panel_attributes>type=final</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>60</y>
<w>90</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;</panel_attributes>
<additional_attributes>10.0;10.0;70.0;10.0</additional_attributes>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>540</x>
<y>50</y>
<w>110</w>
<h>40</h>
</coordinates>
<panel_attributes>drive 1m forward</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>540</x>
<y>140</y>
<w>110</w>
<h>40</h>
</coordinates>
<panel_attributes>drive 2m backward</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>540</x>
<y>230</y>
<w>110</w>
<h>40</h>
</coordinates>
<panel_attributes>drive 1m forward</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>700</x>
<y>230</y>
<w>120</w>
<h>40</h>
</coordinates>
<panel_attributes>calculate straight line</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>580</x>
<y>80</y>
<w>30</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>580</x>
<y>170</y>
<w>30</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>UMLSpecialState</id>
<coordinates>
<x>750</x>
<y>150</y>
<w>20</w>
<h>20</h>
</coordinates>
<panel_attributes>type=termination</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>750</x>
<y>160</y>
<w>30</w>
<h>90</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;10.0;10.0;70.0</additional_attributes>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>440</x>
<y>320</y>
<w>410</w>
<h>260</h>
</coordinates>
<panel_attributes>correct alignment
valign=top</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>540</x>
<y>370</y>
<w>190</w>
<h>40</h>
</coordinates>
<panel_attributes>calculate relativ target position</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>380</y>
<w>90</w>
<h>30</h>
</coordinates>
<panel_attributes>lt=-&gt;</panel_attributes>
<additional_attributes>10.0;10.0;70.0;10.0</additional_attributes>
</element>
<element>
<id>UMLSpecialState</id>
<coordinates>
<x>460</x>
<y>380</y>
<w>20</w>
<h>20</h>
</coordinates>
<panel_attributes>type=final</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLState</id>
<coordinates>
<x>580</x>
<y>460</y>
<w>120</w>
<h>40</h>
</coordinates>
<panel_attributes>rotate x degree</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>630</x>
<y>400</y>
<w>30</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>630</x>
<y>490</y>
<w>30</w>
<h>80</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;60.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>UMLSpecialState</id>
<coordinates>
<x>630</x>
<y>550</y>
<w>20</w>
<h>20</h>
</coordinates>
<panel_attributes>type=termination</panel_attributes>
<additional_attributes/>
</element>
</diagram>
-39
View File
@@ -1,45 +1,6 @@
Maybe:
-> Time Measurement in component interface
-> Time warnings
Do later:
-> Program underfloorLighting
-> Add an beeper
-> Program the beeper
-> Engine slow down without curve in motorControl
-> Network clean up (Mqtt remove?)
-> Extra class for maneuver, autopilot should inherit from int16_t
-> Remote Control
- Leds for gnss rtk etc
- what happens exactly when no data is arriving
-> Test Menu for big curve driving
-> Api with Names and show on Maps in Browser
-> Menu structure mit add functions for each menu mit pointer return to config (additional not replace)
-> Menu Display from parent as run() to make Menu as Component
-> Racing Mode
-> ConsolControl
-> Menü für Einstellungen
- WiFi (save in Flash)
-> Battery
- tabelle mit eigenen Werten übergeben und nicht in header (wiederverwendbarkeit)
- kalibrierungsmethode mit Menü
- Daten in flash speichern können
-> Check speration between Ui and Route (RouteMenu)
-> update sparkfun gnss auf v3 für SPI korrekturdatenüvbetragung
-> Rover Objekt mit Error zustand freeze, damit das wenn möglich auch auf dem Display angezeigt wird.
-> ESP und Sensoren in den DeepSleep für Auschalten oder Akkuschutz
-> Doxygen comments
- navigation
- autopilot
Do now: Do now:
Code: Code:
Fernbedienung!
Latex: Latex:
Anhang: Liste mit allen Komponenten und Kurzbeschreibung
Unterschied funktionale und nicht funktionale Anforderungen
Overfull H-Boxen Overfull H-Boxen
Test Motor, Zeiten kontrolieren. Wenn einfach so dann bezug auf fehler bei Timing und freeRtos Test Motor, Zeiten kontrolieren. Wenn einfach so dann bezug auf fehler bei Timing und freeRtos
Was mit den nicht erfüllten Anforderungen machen? Was mit den nicht erfüllten Anforderungen machen?
+1
View File
@@ -87,6 +87,7 @@ public:
* @param status * @param status
*/ */
void setDrivingStatus(Status status); void setDrivingStatus(Status status);
Status getDrivingStatus() const { return this->driving_status; }
/** /**
* @brief Stops the engine immediately * @brief Stops the engine immediately
+4 -4
View File
@@ -14,16 +14,16 @@
#include <stdint.h> #include <stdint.h>
#define HW1 #define HOTSPOT
#ifdef HOTSPOT #ifdef HOTSPOT
namespace NetworkConfig namespace NetworkConfig
{ {
const char ssid[] = "Kleiax Handy"; const char ssid[] = "Nubsi";
const char password[] = "12345677"; const char password[] = "12345677";
const char ip[] = "192.168.43.4"; const char ip[] = "192.168.72.7";
const char subnet[] = "255.255.255.0"; const char subnet[] = "255.255.255.0";
const char gateway[] = "192.168.43.1"; const char gateway[] = "192.168.72.228";
const char dns[] = "8.8.8.8"; const char dns[] = "8.8.8.8";
const bool mqtt = false; const bool mqtt = false;
} }
-121
View File
@@ -1,121 +0,0 @@
/**
* @file calcAzimuth.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief
* @version 0.1
* @date 2023-09-03
*
* @copyright Copyright (c) 2023
*
*/
#include "calcAzimuth.h"
CalcAzimuth::CalcAzimuth(Point point)
: lastChangePoint{point}, currentPosition{point}
{
Component::loopDelay = CalcAzimuth::loopDelay;
}
void CalcAzimuth::drivingDirectionChange(Point point)
{
if (point.isInit() && point.isValid())
{
this->directionChangeMode = true;
this->lastChangePoint = point;
this->state = State::Invalid;
}
}
void CalcAzimuth::updateCurrentPosition(Point point)
{
this->currentPosition = point;
this->positionChanged = true;
}
String CalcAzimuth::stateToString(State state)
{
switch (state)
{
case State::Invalid:
return "Invalid";
case State::Bad:
return "Bad";
case State::Ok:
return "Ok";
case State::Good:
return "Good";
case State::Super:
return "Super";
default:
return "UNKOWN";
}
}
void CalcAzimuth::run()
{
if (!this->positionChanged)
{
return;
}
this->positionChanged = false;
this->updateAzimuth();
}
void CalcAzimuth::updateAzimuth()
{
if (!this->directionChangeMode || this->lastChangePoint.distanceTo(this->currentPosition) < 1.0)
{
this->state = State::Invalid;
this->calcAzimuth = INT16_MIN;
return;
}
this->calcAzimuth = this->lastChangePoint.courseTo(this->currentPosition);
// Map point accuracy to State
if (this->lastChangePoint.getAccuracy() == Point::Accuracy::oneDigOfCM || this->currentPosition.getAccuracy() == Point::Accuracy::oneDigOfCM)
{
this->state = State::Good;
}
else if (this->lastChangePoint.getAccuracy() == Point::Accuracy::twoDigOfCM || this->currentPosition.getAccuracy() == Point::Accuracy::twoDigOfCM)
{
this->state = State::Ok;
}
else if (this->lastChangePoint.getAccuracy() == Point::Accuracy::threeDigOfCM || this->currentPosition.getAccuracy() == Point::Accuracy::threeDigOfCM)
{
this->state = State::Bad;
}
else
{
this->state = State::Invalid;
}
// Upgrade quality if the range grows up
if (this->lastChangePoint.distanceTo(this->currentPosition) > this->minDistanceForBetterQuality)
{
switch (this->state)
{
case State::Bad:
this->state = State::Ok;
break;
case State::Ok:
this->state = State::Good;
break;
case State::Good:
this->state = State::Super;
break;
default:
break;
}
}
}
-93
View File
@@ -1,93 +0,0 @@
/**
* @file calcAzimuth.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a class that calculates the azimuth from a last and a current position
* @version 0.1
* @date 2023-09-03
*
* @copyright Copyright (c) 2023
*
*/
#ifndef CALC_AZIMUTH_H
#define CALC_AZIMUTH_H
#include "component.h"
#include "point.h"
/**
* @brief A class to calculate an azimuth
*
* This class calculates the current Azimuth with the last position
* where the rover has been rotated and the current position
*/
class CalcAzimuth : public Component
{
public:
/**
* @brief States which represent the quality of the current calculated azimuth
*/
enum State
{
Invalid,
Bad,
Ok,
Good,
Super
};
/**
* @brief Construct a new Calc Azimuth object
*
* @param point current position
*/
CalcAzimuth(Point point);
/**
* @brief Have to be called if the rover rotates
*
* @param point current position
*/
void drivingDirectionChange(Point point);
/**
* @brief update the current position
*
* This function should be called if the rover has moved in
* a straight direction, to calculated the current Azimuth.
* More distance to the point given to drivingDirectionChange()
* increase the accuracy of the calculation.
*
* @param point current position
*/
void updateCurrentPosition(Point point);
void disableCalcAzimuth() { this->directionChangeMode = false; }
int16_t getAzimuth() const { return this->calcAzimuth; }
/**
* @brief Get the State struct
*
* @return State current quality of the calculation
*/
State getState() const { return this->state; }
static String stateToString(State state);
private:
void run() override;
void updateAzimuth();
State state = State::Invalid;
Point lastChangePoint;
Point currentPosition;
bool positionChanged = false;
bool directionChangeMode = false;
int16_t calcAzimuth = INT16_MAX;
double minDistanceForBetterQuality = 2;
static constexpr uint8_t loopDelay = 50;
};
#endif // CALC_AZIMUTH_H
+1 -1
View File
@@ -19,7 +19,7 @@ void Component::loop()
(*it)->loop(); (*it)->loop();
} }
} }
this->runAsChild();F this->runAsChild();
if (this->onlyChilds) if (this->onlyChilds)
{ {
+1 -1
View File
@@ -14,7 +14,7 @@
LcdWrapper::LcdWrapper(LiquidCrystal_I2C *lcd) LcdWrapper::LcdWrapper(LiquidCrystal_I2C *lcd)
: lcd{lcd}, changed{false} : lcd{lcd}, changed{false}
{ {
this->clear(); // this->clear();
} }
void LcdWrapper::run() void LcdWrapper::run()
Submodule
+1
Submodule lib/Menu added at 35b1478666
+5 -27
View File
@@ -33,6 +33,7 @@ void MotorControl::init(uint8_t pwmPin, uint8_t pwmChannel, uint8_t dir_1, uint8
ledcSetup(this->pwmChannel, MotorControl::pwmFreq, MotorControl::pwmRes); ledcSetup(this->pwmChannel, MotorControl::pwmFreq, MotorControl::pwmRes);
ledcAttachPin(this->pwmPin, this->pwmChannel); ledcAttachPin(this->pwmPin, this->pwmChannel);
ledcWrite(this->pwmChannel, 0); ledcWrite(this->pwmChannel, 0);
std::cout << "Init pwm" << std::endl;
} }
void MotorControl::run() void MotorControl::run()
@@ -56,7 +57,7 @@ void MotorControl::run()
return; return;
} }
// Positive or negative tagret speed // Positive or negative target speed
if (this->targetPower >= 0) if (this->targetPower >= 0)
{ {
// Positive or negative speed // Positive or negative speed
@@ -97,28 +98,6 @@ void MotorControl::run()
} }
} }
void MotorControl::setMinPwm(uint8_t min)
{
if (min > MotorControl::maxPwmMin)
{
min = MotorControl::maxPwmMin;
}
// transform percentage to real pwm value
min = static_cast<uint8_t>(((static_cast<uint8_t>(1) << pwmRes) - 1) * (min / 100.0));
this->dutycycleMin = min;
}
void MotorControl::setMaxPwm(uint8_t max)
{
if (max > 100)
{
max = 100;
}
// transform percentage to real pwm value
max = static_cast<uint8_t>(((static_cast<uint8_t>(1) << pwmRes) - 1) * (max / 100.0));
this->dutycycleMax = max;
}
void MotorControl::setTargetPower(int8_t power) void MotorControl::setTargetPower(int8_t power)
{ {
if (power <= 100 && power >= -100) if (power <= 100 && power >= -100)
@@ -158,7 +137,6 @@ bool MotorControl::isAccelerationNegative() const
void MotorControl::setRealPower(int8_t power) void MotorControl::setRealPower(int8_t power)
{ {
// TODO: Exceptionhandling
if (power <= 100 && power >= -100) if (power <= 100 && power >= -100)
{ {
this->power = power; this->power = power;
@@ -175,10 +153,11 @@ void MotorControl::setRealPower(int8_t power)
digitalWrite(this->dir_2, LOW); digitalWrite(this->dir_2, LOW);
ledcWrite(this->pwmChannel, 0); ledcWrite(this->pwmChannel, 0);
this->dutycycle = 0; this->dutycycle = 0;
// std::cout << "abort" << std::endl;
return; return;
} }
const uint8_t pwm_val = map(abs(power), 0, 100, this->dutycycleMin, this->dutycycleMax); const uint8_t pwm_val = map(abs(power), 0, 100, MotorControl::minPwmVal, MotorControl::maxPwmVal);
if ((this->direction == 1 || this->direction == 0) && power < 0) if ((this->direction == 1 || this->direction == 0) && power < 0)
{ // new direction backward { // new direction backward
@@ -193,14 +172,13 @@ void MotorControl::setRealPower(int8_t power)
digitalWrite(this->dir_2, LOW); digitalWrite(this->dir_2, LOW);
} }
std::cout << "MotorControl::setRealPower pwm_val: " << (int) pwm_val << " channel:" << (int) this->pwmChannel << std::endl;
ledcWrite(this->pwmChannel, pwm_val); ledcWrite(this->pwmChannel, pwm_val);
this->dutycycle = pwm_val; this->dutycycle = pwm_val;
} }
void MotorControl::increasePower(int8_t power) void MotorControl::increasePower(int8_t power)
{ {
// TODO: Exceptionhandling
// TODO: make a stop befor a direction change
if (abs(power) > 2 * MotorControl::powerSteps) if (abs(power) > 2 * MotorControl::powerSteps)
{ {
Serial.println("Invalid Argument in MotorControl::increasePower"); Serial.println("Invalid Argument in MotorControl::increasePower");
+2 -16
View File
@@ -38,20 +38,6 @@ public:
*/ */
void init(uint8_t pwmPin, uint8_t pwmChannel, uint8_t dir_1, uint8_t dir_2); void init(uint8_t pwmPin, uint8_t pwmChannel, uint8_t dir_1, uint8_t dir_2);
/**
* @brief Set the minimum duty cycle
*
* @param min duty cycle in percent
*/
void setMinPwm(uint8_t min);
/**
* @brief Set the maximum duty cycle
*
* @param max duty cycle in percent
*/
void setMaxPwm(uint8_t max);
/** /**
* @brief Set the Target Power * @brief Set the Target Power
* *
@@ -103,6 +89,8 @@ private:
static constexpr uint8_t pwmRes = 8; static constexpr uint8_t pwmRes = 8;
static constexpr uint8_t powerSteps = 2; // A total of 20 levels ( 100 / SPEED_STEPS ) * RUN_MOTOR_CONTROL_DELAY = 500ms static constexpr uint8_t powerSteps = 2; // A total of 20 levels ( 100 / SPEED_STEPS ) * RUN_MOTOR_CONTROL_DELAY = 500ms
static constexpr uint8_t maxPwmMin = 80; static constexpr uint8_t maxPwmMin = 80;
static constexpr uint8_t maxPwmVal = 250;
static constexpr uint8_t minPwmVal = 55; // Max 98% of 2^PWM_RES
int8_t targetPower = 0; int8_t targetPower = 0;
int8_t power = 0; int8_t power = 0;
@@ -111,8 +99,6 @@ private:
uint8_t pwmPin = 0; uint8_t pwmPin = 0;
uint8_t pwmChannel = 0; uint8_t pwmChannel = 0;
uint16_t dutycycle = 0; uint16_t dutycycle = 0;
uint8_t dutycycleMin = 55;
uint8_t dutycycleMax = 98; // Max 98% of 2^PWM_RES
uint8_t dir_1 = 0; uint8_t dir_1 = 0;
uint8_t dir_2 = 0; uint8_t dir_2 = 0;
}; };
-178
View File
@@ -1,178 +0,0 @@
/**
* @file navigation.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the implementation of the class Navigation
* @version 0.1
* @date 2022-01-31
*
* @copyright Copyright (c) 2022
*
*/
#include "navigation.h"
Navigation::Navigation(const SensorData *sensorData, Route *route)
: sensorData{sensorData}
{
this->init(route);
}
void Navigation::init(Route *route)
{
if (static_cast<bool>(route))
{
this->route = route;
}
else
{
this->route = new Route();
}
Component::loopDelay = Navigation::loopDelay;
}
Navigation::~Navigation()
{
delete this->route;
}
void Navigation::run() {}
void Navigation::newRoute()
{
delete this->route;
this->route = new Route();
}
bool Navigation::startNavigation()
{
const Point newTargetPoint = this->route->startRoute();
this->navigationStarted = this->setTargetPoint(newTargetPoint);
if (this->navigationStarted)
{
this->navigationFinished = false;
}
return this->navigationStarted;
}
Navigation::Status Navigation::getCourseCorrection(CourseCorrection &correction, bool forceUpdate)
{
if (this->navigationFinished)
{
return Status::Complete;
}
if (this->currentPosition.getAccuracy() <= this->minAccuracy)
{
return Status::InsufficientAccuracy;
}
// Check if the Rover has moved, if the Rover hasnt moved this function will be return.
if (this->currentPosition.distanceTo(this->lastPointCalcCorrection) < (this->minDistanceToReachPoint) / 2 && !forceUpdate)
{
correction.correction = this->calculateCourseCorrection(this->lastPointCalcCorrection);
correction.distance = this->lastPointCalcCorrection.distanceTo(this->targetPoint);
return Status::Unchanged;
}
double distance = this->currentPosition.distanceTo(this->targetPoint);
// Check if I need a new Point
if (distance < this->minDistanceToReachPoint && this->preventNextPoint == false)
{
if (!this->nextPoint())
{
this->navigationFinished = true;
this->navigationStarted = false;
return Status::Complete; // End of navigation
}
distance = this->currentPosition.distanceTo(this->targetPoint);
}
correction.correction = this->calculateCourseCorrection(this->currentPosition);
correction.distance = distance;
this->lastPointCalcCorrection = this->currentPosition;
return Status::Updated;
}
Navigation::Status Navigation::addCurrentPosToRoute()
{
if (this->currentPosition.getAccuracy() <= this->minAccuracy)
{
return Status::InsufficientAccuracy;
}
// First Point
if (this->route->getRouteInfo().totalPoints == 0)
{
this->route->addPointToRoute(this->currentPosition);
this->lastPointRouteInsert = this->currentPosition;
return Status::Updated;
}
// Every Point after the first
const double distance = this->currentPosition.distanceTo(this->lastPointRouteInsert);
if (Navigation::minDisBetweenPoints <= distance && Navigation::maxDisBetweenPoints >= distance)
{
this->route->addPointToRoute(this->currentPosition);
this->lastPointRouteInsert = this->currentPosition;
return Status::Updated;
}
return Status::Unchanged;
}
int16_t Navigation::calculateCourseCorrection(Point &point)
{
const int16_t targetCourse = point.courseTo(this->targetPoint);
int16_t correctionCourse = 0;
if (this->sensorData->getCalcAzimuthState() == CalcAzimuth::State::Good || this->sensorData->getCalcAzimuthState() == CalcAzimuth::State::Super)
{
correctionCourse = targetCourse - this->sensorData->getCalcAzimuth();
this->lastUsedCalcAzimuth = true;
}
else
{
correctionCourse = targetCourse - this->sensorData->getRealAzimuth();
this->lastUsedCalcAzimuth = false;
}
return Navigation::fixDegree(correctionCourse);
}
bool Navigation::nextPoint()
{
if (!this->navigationStarted)
{
return false;
}
return this->setTargetPoint(this->route->getNextPoint());
}
bool Navigation::setTargetPoint(Point target)
{
if (target.isInit())
{
this->targetPoint = target;
return true;
}
return false;
}
int16_t Navigation::fixDegree(int16_t degree)
{
static constexpr uint16_t fullCircle = 360;
while (degree < -fullCircle / 2 || degree > fullCircle / 2)
{
if (degree > fullCircle / 2)
{
degree -= fullCircle;
}
else if (degree < -fullCircle / 2)
{
degree += fullCircle;
}
}
return degree;
}
-163
View File
@@ -1,163 +0,0 @@
/**
* @file navigation.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a class which navigate an object by the given route
* @version 0.1
* @date 2022-01-10
*
* @copyright Copyright (c) 2022
*
*/
#ifndef NAVIGATION_H
#define NAVIGATION_H
#include <Arduino.h>
#include <iostream>
#include "route.h"
#include "sensorData.h"
#include "component.h"
/**
* @brief This struct inherits the result of the navigation
*
* The drive get objects of this struct and should
* correct the direction in dependency on this.
*
*/
struct CourseCorrection
{
int16_t correction;
double distance;
};
/**
* @brief This class navigate an object
*
* The class use the given Route and the gps device
* to tell the driver in which direction he have to
* be drive and the distance to the next checkpoint.
*
*/
class Navigation : public Component
{
public:
enum Status
{
InsufficientAccuracy,
Unchanged,
Updated,
Complete
};
/**
* @brief Construct a new Navigation object
*
* @param sensorData
* @param route
*/
Navigation(const SensorData *sensorData, Route *route = nullptr);
/**
* @brief Destroy the Navigation object
*
*/
~Navigation();
/**
* @brief creates a new empty route
*
*/
void newRoute();
/**
* @brief Tries to start the route
*
* For example the route can not be started
* if there are no Points or wrong Points.
*
* @return true route is started
* @return false route can not be started
*/
bool startNavigation();
void freezeTargetPoint(bool val = true) { this->preventNextPoint = val; };
double increaseMinDistanceToReachPoint() { return this->minDistanceToReachPoint += 0.1; }
double decreaseMinDistanceToReachPoint() { return this->minDistanceToReachPoint -= 0.1; }
// TODO: Dokumentation korrigieren.
/**
* @brief Get the Course Correction object
*
* @param correction
* @param forceUpdate
* @return Status
*/
Status getCourseCorrection(CourseCorrection &correction, bool forceUpdate = false);
// TODO: Dokumentation korrigieren.
/**
* @brief Tries to add the current Position to the route
*
* This can be go wrong if there is no valid GPS signal
*
* @return true successful added point
* @return false no point added to route
*/
Status addCurrentPosToRoute();
/**
* @brief Get the Route Info object
*
* This object contains information about the route.
* For example the stored points.
*
* @return RouteInfo
*/
RouteInfo getRouteInfo() const { return this->route->getRouteInfo(); }
Route *getRoute() const { return this->route; }
Point getCurrentPosition() const { return this->currentPosition; }
Point::Accuracy getMinAccuracy() const { return this->minAccuracy; }
void setMinAccuracy(Point::Accuracy accuracy) { this->minAccuracy = accuracy; }
// map input in range from -180 to 180 degree
static int16_t fixDegree(int16_t degree);
private:
void run() override;
void init(Route *route);
bool nextPoint();
bool setTargetPoint(Point target);
int16_t calculateCourseCorrection(Point &point);
static constexpr uint8_t loopDelay = 20;
static constexpr uint8_t maxDisBetweenPoints = 10;
static constexpr float minDisBetweenPoints = 0.3;
const SensorData *sensorData;
Route *route = nullptr;
Point lastPointRouteInsert;
Point lastPointCalcCorrection;
Point lastPointDrivingDirectionChange;
Point targetPoint;
Point currentPosition;
Point::Accuracy minAccuracy = Point::Accuracy::twoDigOfCM;
bool navigationStarted = false;
bool navigationFinished = false;
bool isNtripInit = false;
bool preventNextPoint = false;
bool directionChangeMode = false;
bool lastUsedCalcAzimuth = false;
uint8_t timeToWait = 200;
uint32_t lastMillis = 0;
uint32_t ubxUpdateTime = 0;
double minDistanceToReachPoint = 0.5;
};
#endif // NAVIGATION_H
-348
View File
@@ -1,348 +0,0 @@
/**
* @file NTRIPClient.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the implementation of the class NTRIPClient.
* @version 0.1
* @date 2022-09-18
*
* @copyright Copyright (c) 2022
*
*/
#include "ntripClient.h"
NTRIPClient::NTRIPClient(SFE_UBLOX_GNSS *gps, const char *host, uint16_t port, const char *mountPoint, const char *user, const char *password)
: gps{gps}, port{port}, host{host}, mountPoint{mountPoint}, user{user}, password{password}, ntripClient{new WiFiClient}, state{NTRIPClientStates::closeConnection}
{
Component::loopDelay = NTRIPClient::loopDelay;
}
NTRIPClient::~NTRIPClient()
{
delete this->ntripClient;
}
void NTRIPClient::run()
{
switch (this->state)
{
case NTRIPClientStates::openConnection:
if (!this->activated)
{
this->state = NTRIPClientStates::closeConnection;
break;
}
std::cout << "Connecting to the NTRIP caster..." << std::endl;
if (this->beginClient())
{
std::cout << "Connected to the NTRIP caster!" << std::endl;
this->state = NTRIPClientStates::pushData;
}
else
{
std::cout << "Failed!" << std::endl;
this->state = NTRIPClientStates::wait;
this->activated = false;
}
break;
case NTRIPClientStates::pushData:
if (!processConnection() || !this->activated)
{
this->state = NTRIPClientStates::closeConnection;
}
break;
case NTRIPClientStates::closeConnection:
std::cout << "Closing the connection to the NTRIP caster..." << std::endl;
this->closeConnection();
state = NTRIPClientStates::wait;
break;
case NTRIPClientStates::wait:
if (this->activated)
{
this->state = NTRIPClientStates::openConnection;
}
else
{
this->checkAutoReconnect();
}
break;
case NTRIPClientStates::notAvailable:
break;
default:
std::cout << "Wrong state in NTRIPClient.cpp..." << std::endl;
this->state = NTRIPClientStates::closeConnection;
break;
}
}
void NTRIPClient::runAsChild()
{
this->pushGPGGA();
}
void NTRIPClient::gpsConfiguration()
{
this->gps->setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA);
this->gps->setPortInput(COM_PORT_SPI, COM_TYPE_UBX | COM_TYPE_NMEA | COM_TYPE_RTCM3);
// Set the differential mode - ambiguities are fixed whenever possible
this->gps->setDGNSSConfiguration(SFE_UBLOX_DGNSS_MODE_FIXED);
this->gps->setMainTalkerID(SFE_UBLOX_MAIN_TALKER_ID_GP);
this->gps->enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI, 10);
}
bool NTRIPClient::setActivated(bool state)
{
if (state && this->state != NTRIPClientStates::notAvailable)
{
this->activated = true;
}
else if (state)
{
return false;
}
else
{
this->activated = false;
this->autoReconnect = false;
}
return true;
}
void NTRIPClient::setAutoReconnect(bool state)
{
if (state)
{
this->reconnectAttemps = 0;
this->autoReconnect = true;
return;
}
this->autoReconnect = false;
}
bool NTRIPClient::beginClient()
{
static constexpr uint16_t httpError = 401;
static constexpr uint16_t httpCheck = 200;
std::cout << "Opening socket to " << this->host << std::endl;
char serverRequest[this->bufferSize];
char credentials[this->bufferSize];
if (!static_cast<bool>(this->ntripClient->connect(static_cast<const char *>(this->host), this->port)))
{
std::cout << "Connection to caster failed" << std::endl;
return false;
}
std::cout << "Connected to " << this->host << " : " << this->port << std::endl;
std::cout << "Requesting NTRIP Data from mount point " << this->mountPoint << std::endl;
// Generate the server request (GET)
snprintf(static_cast<char *>(serverRequest),
this->bufferSize,
static_cast<const char *>("GET /%s HTTP/1.0\r\nUser-Agent: NTRIP SparkFun u-blox Client v1.0\r\n"),
this->mountPoint);
// Credentials
const uint8_t userCredentialsLength = strlen(this->user) + strlen(this->password) + 2;
auto *userCredentials = new char[userCredentialsLength];
snprintf(static_cast<char *>(userCredentials), userCredentialsLength, static_cast<const char *>("%s:%s"), this->user, this->password);
std::cout << "Sending credentials: " << userCredentials << std::endl;
// Encode
const base64 base;
const String strEncodedCredentials = base64::encode(userCredentials);
delete userCredentials;
char encodedCredentials[strEncodedCredentials.length() + 1];
strEncodedCredentials.toCharArray(static_cast<char *>(encodedCredentials), sizeof(encodedCredentials));
snprintf(credentials, sizeof(credentials), static_cast<const char *>("Authorization: Basic %s\r\n"), static_cast<const char *>(encodedCredentials));
// Add the encoded credentials to the server request
strncat(static_cast<char *>(serverRequest), static_cast<const char *>(credentials), this->bufferSize);
strncat(static_cast<char *>(serverRequest), static_cast<const char *>("\r\n"), this->bufferSize);
std::cout << static_cast<const char *>("serverRequest size: ")
<< strlen(serverRequest)
<< static_cast<const char *>(" of ")
<< this->bufferSize
<< static_cast<const char *>(" bytes available")
<< std::endl;
// Send the server request
std::cout << "Sending server request: " << serverRequest << std::endl;
this->ntripClient->write(serverRequest, strlen(serverRequest));
// Wait up to 5 seconds for response
const uint32_t lastMillis = millis();
while (static_cast<bool>(!ntripClient->available()))
{
if (millis() - lastMillis > this->timeOut)
{
std::cout << "Caster timed out!" << std::endl;
this->ntripClient->stop();
return false;
}
delay(10);
}
// Check reply
uint16_t httpStatusCode = 0;
char response[this->bufferSize];
uint16_t responseIndex = 0;
while (static_cast<bool>(this->ntripClient->available()))
{
if (responseIndex == sizeof(response))
{
break;
}
response[responseIndex++] = ntripClient->read();
if (httpStatusCode == 0)
{
if (strstr(response, static_cast<const char *>("200")) != nullptr)
{
httpStatusCode = httpCheck;
}
if (strstr(response, static_cast<const char *>("401")) != nullptr)
{
httpStatusCode = httpError;
}
}
}
response[responseIndex] = '\0';
// std::cout << "Caster response: " << response << std::endl;
if (httpStatusCode != httpCheck)
{
std::cout << "Failed to connect to " << this->host << " - HTTP Code: " << (int)httpStatusCode
<< " Length of Response: " << responseIndex << std::endl;
if (httpStatusCode == 0)
{
std::cout << "Response: " << response << std::endl;
}
else if (httpStatusCode == httpError)
{
std::cout << "Statuscode 401 - Unauthorized" << std::endl;
}
return false;
}
std::cout << "Connected to: " << this->host << std::endl;
this->lastReceivedRtcmTime = millis();
return true;
}
void NTRIPClient::closeConnection()
{
if (static_cast<bool>(this->ntripClient->connected()))
{
this->ntripClient->stop();
}
this->activated = false;
std::cout << "NtripClient disconnected from: " << this->host << std::endl;
}
bool NTRIPClient::processConnection()
{
if (static_cast<bool>(this->ntripClient->connected()))
{
uint8_t rtcmData[this->bufferSize * 8];
uint16_t rtcmCount = 0;
while (static_cast<bool>(this->ntripClient->available()))
{
rtcmData[rtcmCount++] = ntripClient->read();
if (rtcmCount == sizeof(rtcmData))
{
break;
}
}
if (rtcmCount > 0)
{
this->lastReceivedRtcmTime = millis();
this->gps->pushRawData(static_cast<uint8_t *>(rtcmData), rtcmCount);
// std::cout << "Pushed " << rtcmCount << " RTCM bytes to ZED." << std::endl;
}
}
else
{
std::cout << "Connection to " << this->host << " dropped!" << std::endl;
return false;
}
if (millis() - this->lastReceivedRtcmTime > this->timeOut)
{
std::cout << "RTCM timeout!" << std::endl;
return false;
}
return true;
}
void NTRIPClient::checkAutoReconnect()
{
if (!this->autoReconnect)
{
return;
}
if (millis() - this->lastReconnectTime < this->reconnectDelayTime)
{
return;
}
this->lastReconnectTime = millis();
if (this->reconnectAttemps >= this->maxReconnectAttemps)
{
this->autoReconnect = false;
return;
}
this->activated = true;
this->reconnectAttemps++;
}
void NTRIPClient::pushGPGGA()
{
if (!this->transmitLocation && !this->activated)
{
return;
}
if (millis() - this->lastGPGGAPushTime < this->pushGPGGATime)
{
return;
}
this->lastGPGGAPushTime = millis();
if (!this->ntripClient->connected())
{
std::cout << "Failed to pushing GGA to server: " << std::endl;
}
auto *data = new NMEA_GGA_data_t;
const uint8_t res = this->gps->getLatestNMEAGPGGA(data);
if (res == 2)
{
this->ntripClient->print(reinterpret_cast<const char *>(data));
}
delete data;
}
bool NTRIPClient::isConnected()
{
return this->state == NTRIPClientStates::pushData;
}
-134
View File
@@ -1,134 +0,0 @@
/**
* @file ntripClient.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the class NTRIPClient
* @version 0.1
* @date 2023-02-13
*
* @copyright Copyright (c) 2023
*
*/
#ifndef NTRIP_CLIENT
#define NTRIP_CLIENT
#include <WiFiClient.h>
#include <Arduino.h>
#include <base64.h>
#include <iostream>
#include <SparkFun_u-blox_GNSS_Arduino_Library.h>
#include "debugTimes.h"
#include "component.h"
/**
* @brief States for the state machine.
*
*/
enum NTRIPClientStates
{
openConnection,
pushData,
closeConnection,
wait,
notAvailable
};
/**
* @brief Ntrip Client
*
* This class can connect to a ntrip server to pull correction
* data and push it to a given gnss module. This module have to be compatible
* with the SparkFun u-blox GNSS Arduino Library.
*/
class NTRIPClient : public Component
{
public:
/**
* @brief Construct a new NTRIPClient object
*
* @param gps The Gnss module
* @param host
* @param port
* @param mountPoint
* @param user
* @param password
*/
NTRIPClient(SFE_UBLOX_GNSS *gps, const char *host, uint16_t port, const char *mountPoint, const char *user, const char *password);
~NTRIPClient();
/**
* @brief Configure the Gnss module to accept correction data
*
*/
void gpsConfiguration();
/**
* @brief Activate or deactivate the location transmission
*
* Some server need the position of the Gnss module to send the
* right correction data.
*
* @param b
*/
void setTransmitLocation(bool b) { this->transmitLocation = b; }
/**
* @brief Activate or deactivate the connection to the server.
*
* @param state
* @return true success
* @return false failure
*/
bool setActivated(bool state);
void setAutoReconnect(bool state);
bool isConnected();
/**
* @brief Get the Client State object
*
* Returns the state of the State machine
*
* @return NTRIPClientStates
*/
NTRIPClientStates getClientState() { return this->state; }
private:
void run() override;
void runAsChild() override;
void pushGPGGA();
bool beginClient();
void closeConnection();
bool processConnection();
void checkAutoReconnect();
SFE_UBLOX_GNSS *gps;
WiFiClient *ntripClient;
NTRIPClientStates state = NTRIPClientStates::notAvailable;
bool transmitLocation = false;
bool activated = true;
bool autoReconnect = false;
uint8_t reconnectAttemps = 0;
uint16_t port;
uint32_t lastReceivedRtcmTime = 0;
// uint32_t lastNtripConnectTime = 0; // can deleted?
uint32_t lastGPGGAPushTime = 0;
uint32_t lastReconnectTime = 0;
const char *host;
const char *mountPoint;
const char *user;
const char *password;
const uint8_t maxReconnectAttemps = 10;
const uint16_t reconnectDelayTime = 1000;
const uint16_t timeOut = 10000;
const uint16_t bufferSize = 512;
const uint16_t pushGPGGATime = 10000;
static constexpr uint8_t loopDelay = 20;
};
#endif
-100
View File
@@ -1,100 +0,0 @@
/**
* @file route.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Implements the class Route and Point
* @version 0.1
* @date 2022-01-31
*
* @copyright Copyright (c) 2022
*
*/
#include "route.h"
void Route::addPointToRoute(Point point)
{
this->points.push_back(point);
}
void Route::clear()
{
this->points.clear();
this->currentPoint = 0;
this->started = false;
}
Point Route::startRoute()
{
if (this->points.empty())
{
this->started = false;
return Point();
}
this->it = this->points.begin();
this->currentPoint = 1;
this->started = true;
return *this->it;
}
Point Route::endRoute()
{
if (this->points.empty())
{
this->started = false;
return Point();
}
this->it = this->points.end();
// TODO: Understand why i have to decrement the iterator first to get realy the last element.
this->it--;
this->currentPoint = this->points.size();
this->started = true;
return *this->it;
}
Point Route::getNextPoint()
{
Point point;
if (!this->started)
{
return point;
}
if (this->it != --this->points.end())
{
this->it++;
this->currentPoint++;
return *this->it;
// } else if (this->it == this->points.end() && this->currentPoint != this->points.size()) {
// this->currentPoint++;
// return *this->it;
}
return point;
}
Point Route::getPreviousPoint()
{
Point point;
if (!this->started)
{
return point;
}
if (this->it != this->points.begin())
{
this->it--;
this->currentPoint--;
return *this->it;
}
return point;
}
RouteInfo Route::getRouteInfo()
{
RouteInfo info{0, 0};
info.totalPoints = this->points.size();
info.currentPoint = this->currentPoint;
return info;
}
-111
View File
@@ -1,111 +0,0 @@
/**
* @file route.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the class Route
* @version 0.1
* @date 2022-01-31
*
* @copyright Copyright (c) 2022
*
*/
#ifndef ROUTE_H
#define ROUTE_H
#include <cstdint>
#include <list>
#include "point.h"
/**
* @brief Holds some route information
*
*/
struct RouteInfo
{
/**
* @brief Selected number of Points
*/
uint16_t currentPoint;
/**
* @brief Total points stored in route
*/
uint16_t totalPoints;
};
/**
* @brief A class to manage multiple points
*
* The list of point presents a route which can be driven
*/
class Route
{
public:
/**
* @brief Adds a point to the list.
*
* @param point
*/
void addPointToRoute(Point point);
/**
* @brief Delete all points
*/
void clear();
/**
* @brief Select the first point as target.
*
* @return Point
*/
Point startRoute();
/**
* @brief Select the last point as target.
*
* @return Point
*/
Point endRoute();
/**
* @brief Get the next point and set it as target.
*
* @return Point is zero if there are no more Points.
*/
Point getNextPoint();
/**
* @brief Get the previous point and set it as target.
*
* @return Point
*/
Point getPreviousPoint();
/**
* @brief Get the Route Info object
*
* @return RouteInfo
*/
RouteInfo getRouteInfo();
/**
* @brief Get the Started object
*
* The Route will be marked as started when startRoute or
* endRoute has been called.
*
* @return true
* @return false
*/
bool getStarted() const { return this->started; }
private:
uint16_t currentPoint = 0;
bool started = false;
std::list<Point> points;
std::list<Point>::iterator it;
};
#endif // ROUTE_H
-86
View File
@@ -20,21 +20,6 @@ SensorData::SensorData()
Component::loopDelay = SensorData::loopDelay; Component::loopDelay = SensorData::loopDelay;
} }
SensorData::~SensorData()
{
delete this->ntripClient;
}
void SensorData::enableNtrip(String host, uint16_t port, String mountPoint, String user, String password)
{
this->ntripClient = new NTRIPClient(this->gnss, host.c_str(), port, mountPoint.c_str(), user.c_str(), password.c_str());
this->ntripClient->gpsConfiguration();
this->ntripClient->loop();
this->ntripClient->setActivated(false);
this->isNtripInit = true;
this->addChildComponent(this->ntripClient);
}
void SensorData::enableGnss(SPIClass *spiPort, uint8_t csPin) void SensorData::enableGnss(SPIClass *spiPort, uint8_t csPin)
{ {
this->gnss = new SFE_UBLOX_GNSS(); this->gnss = new SFE_UBLOX_GNSS();
@@ -68,7 +53,6 @@ void SensorData::enableRealCompass()
this->realCompass = new QMC5883LCompass(); this->realCompass = new QMC5883LCompass();
// Init Compass // Init Compass
Wire.beginTransmission(address); Wire.beginTransmission(address);
// TODO: describe Bytes !!!
Wire.write(0x0b); Wire.write(0x0b);
Wire.write(0x01); Wire.write(0x01);
Wire.endTransmission(); Wire.endTransmission();
@@ -78,69 +62,6 @@ void SensorData::enableRealCompass()
caliCompass.useData(); caliCompass.useData();
} }
void SensorData::enableCalcCompass()
{
// TODO: !!! implementieren
}
void SensorData::enableGyroscope()
{
this->gyroscope = new MPU6050();
this->gyroscope->initialize();
if (!this->gyroscope->testConnection())
{
std::cout << "SensorData::enableGyroscope: Gyroskop is not conntected. Freeze!" << std::endl;
while (true)
{
}
}
const uint8_t deviceStatus = this->gyroscope->dmpInitialize();
// TODO: !!! MagicNumer 6x
this->gyroscope->setXGyroOffset(220);
this->gyroscope->setYGyroOffset(76);
this->gyroscope->setZGyroOffset(-85);
this->gyroscope->setZAccelOffset(1788);
if (deviceStatus == 0)
{
this->gyroscope->CalibrateAccel(6);
this->gyroscope->CalibrateGyro(6);
this->gyroscope->PrintActiveOffsets();
this->gyroscope->setDMPEnabled(true);
}
else
{
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
std::cout << "SensorData::enableGyroscope: DMP Initialization failed (code" << static_cast<int>(deviceStatus) << "). Freeze!" << std::endl;
while (true)
{
}
}
}
CalcAzimuth::State SensorData::getCalcAzimuthState() const
{
if (static_cast<bool>(this->calcCompass))
{
return this->calcCompass->getState();
}
return CalcAzimuth::State::Invalid;
}
NTRIPClientStates SensorData::getNtripState() const
{
if (static_cast<bool>(this->ntripClient))
{
return this->ntripClient->getClientState();
}
return NTRIPClientStates::notAvailable;
}
void SensorData::printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct) void SensorData::printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{ {
static constexpr uint8_t stringSize = 32; static constexpr uint8_t stringSize = 32;
@@ -235,13 +156,6 @@ void SensorData::run()
this->realCompass->read(); this->realCompass->read();
this->realAzimuth = this->realCompass->getAzimuth(); this->realAzimuth = this->realCompass->getAzimuth();
} }
if (static_cast<bool>(this->gyroscope) && this->gyroscope->dmpGetCurrentFIFOPacket(static_cast<uint8_t *>(this->gyroBuffer)))
{
this->gyroscope->dmpGetQuaternion(&this->quaternion, static_cast<uint8_t *>(this->gyroBuffer));
this->gyroscope->dmpGetGravity(&this->gravity, &this->quaternion);
this->gyroscope->dmpGetYawPitchRoll(static_cast<float *>(this->yawPitchRoll), &this->quaternion, &this->gravity);
}
} }
void SensorData::runAsChild() void SensorData::runAsChild()
-73
View File
@@ -13,7 +13,6 @@
#define SENSOR_DATA_H #define SENSOR_DATA_H
#include <SPI.h> #include <SPI.h>
#include <I2Cdev.h>
#include <iostream> #include <iostream>
#include "component.h" #include "component.h"
@@ -21,9 +20,6 @@
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> #include <SparkFun_u-blox_GNSS_Arduino_Library.h>
#include <QMC5883LCompass.h> #include <QMC5883LCompass.h>
#include <MPU6050_6Axis_MotionApps20.h>
#include "calcAzimuth.h"
#include "ntripClient.h"
#include "point.h" #include "point.h"
@@ -38,8 +34,6 @@ public:
SensorData(); SensorData();
~SensorData(); ~SensorData();
void enableNtrip(String host, uint16_t port, String mountPoint, String user, String password);
/** /**
* @brief Enable the gnss module over spi * @brief Enable the gnss module over spi
* *
@@ -55,7 +49,6 @@ public:
void enableRealCompass(); void enableRealCompass();
void enableCalcCompass(); void enableCalcCompass();
void enableGyroscope();
// Interface Const // Interface Const
/** /**
@@ -65,45 +58,8 @@ public:
*/ */
int16_t getRealAzimuth() const { return this->realAzimuth; } int16_t getRealAzimuth() const { return this->realAzimuth; }
/**
* @brief Get the azimuth calculated by CalcAzimuth
*
* Consider to call getCalcAzimuthState() to check, if the data is valid.
*
* @return int16_t
*/
int16_t getCalcAzimuth() const { return this->calcAzimuth; }
/**
* @brief Get the CalcAzimuth::State object
*
* Needed to check the quality of calculated azimuth
*
* @return CalcAzimuth::State
*/
CalcAzimuth::State getCalcAzimuthState() const;
Point getCurrentPos() const { return this->currentPosition; } Point getCurrentPos() const { return this->currentPosition; }
const UBX_NAV_PVT_data_t *getGnssData() const { return this->gnssData; }; const UBX_NAV_PVT_data_t *getGnssData() const { return this->gnssData; };
NTRIPClientStates getNtripState() const;
/**
* @brief Get the data from the gyroscope
*
* The returned float pointer is an array of 3 floats
* - Yaw
* - Pitch
* - Roll
*
* @return const float*
*/
const float *getGyroData() const { return this->yawPitchRoll; }
/**
* @brief Get the CalcCompass object
* @return CalcAzimuth*
*/
CalcAzimuth *getCalcCompass() const { return this->calcCompass; }
/** /**
* @brief Get the RealCompass object * @brief Get the RealCompass object
@@ -111,18 +67,6 @@ public:
*/ */
QMC5883LCompass *getRealCompass() const { return this->realCompass; } QMC5883LCompass *getRealCompass() const { return this->realCompass; }
/**
* @brief Get the NTRIPClient object
* @return NTRIPClient*
*/
NTRIPClient *getNtripClient() const { return this->ntripClient; }
/**
* @brief Get the Gyroscope object
* @return MPU6050*
*/
MPU6050 *getGyroscope() const { return this->gyroscope; }
// static // static
/** /**
* @brief Set the output status for PVTdata. * @brief Set the output status for PVTdata.
@@ -141,31 +85,14 @@ private:
void updateUbxData(); void updateUbxData();
QMC5883LCompass *realCompass = nullptr; QMC5883LCompass *realCompass = nullptr;
CalcAzimuth *calcCompass = nullptr;
SFE_UBLOX_GNSS *gnss = nullptr; SFE_UBLOX_GNSS *gnss = nullptr;
NTRIPClient *ntripClient = nullptr;
MPU6050 *gyroscope = nullptr;
UBX_NAV_PVT_data_t *gnssData = nullptr; UBX_NAV_PVT_data_t *gnssData = nullptr;
Point currentPosition; Point currentPosition;
Quaternion quaternion;
VectorFloat gravity;
char *host = nullptr;
char *mountPoint = nullptr;
char *user = nullptr;
char *password = nullptr;
bool isNtripInit = false;
uint8_t gyroBuffer[64];
uint16_t port = 0;
int16_t realAzimuth = INT16_MAX; int16_t realAzimuth = INT16_MAX;
int16_t calcAzimuth = INT16_MAX;
uint32_t lastUbxUpdate = 0; uint32_t lastUbxUpdate = 0;
float yawPitchRoll[3]{0, 0, 0};
// static // static
static void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct); static void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct);
static void savePVTdata(UBX_NAV_PVT_data_t *ubxDataStruct); static void savePVTdata(UBX_NAV_PVT_data_t *ubxDataStruct);
+1 -20
View File
@@ -18,12 +18,11 @@ upload_speed = 921600
; monitor_port = COM6 ; monitor_port = COM6
lib_deps = lib_deps =
https://git.kleiax.de/PlatformIO-Libs/SparkFunGNSS.git https://git.kleiax.de/PlatformIO-Libs/SparkFunGNSS.git
https://git.kleiax.de/PlatformIO-Libs/Menu.git
knolleary/PubSubClient@^2.8 knolleary/PubSubClient@^2.8
br3ttb/PID@^1.2.1 br3ttb/PID@^1.2.1
marcoschwartz/LiquidCrystal_I2C@^1.1.4 marcoschwartz/LiquidCrystal_I2C@^1.1.4
bblanchon/ArduinoJson@^6.20.0
mprograms/QMC5883LCompass@^1.2.0 mprograms/QMC5883LCompass@^1.2.0
jrowberg/I2Cdevlib-MPU6050@^1.0.0
; upload_port = COM6 ; upload_port = COM6
test_ignore = test_desktop test_ignore = test_desktop
build_type = debug build_type = debug
@@ -42,21 +41,3 @@ test_ignore = test_embedded
[platformio] [platformio]
description = A Rover who should be drive a route by gps. description = A Rover who should be drive a route by gps.
; Bei Möglichkeit folgendes aus clang tidy entfernen
; cppcoreguidelines-owning-memory
;
;
;
;
;
;
;
;
;
;
;
;
;
#
-375
View File
@@ -1,375 +0,0 @@
/**
* @file menuRoute.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the implementation of the classes MenuActionRoute, MenuRoute and MenuRouteWrapper.
* @version 0.1
* @date 2022-12-28
*
* @copyright Copyright (c) 2022
*
*/
#include "menuRoute.h"
MenuActionRoute::MenuActionRoute(MenuRoute *menuRoute, DataFunction dataFunction)
: menuRoute{menuRoute}, dataFunction{dataFunction}
{
}
void MenuActionRoute::action()
{
(this->menuRoute->*this->dataFunction)(0);
}
MenuRoute::MenuRoute(Route *route)
: route{route}
{
}
MenuRoute::~MenuRoute()
{
if (isInit)
{
delete this->mainMenu;
}
}
void MenuRoute::printMenu()
{
if (!this->isInit)
{
this->isInit = true;
this->init();
}
this->mainMenu->printMenu();
}
void MenuRoute::down()
{
if (blockInput)
{
return;
}
this->mainMenu->down();
}
void MenuRoute::up()
{
if (blockInput)
{
return;
}
this->mainMenu->up();
}
void MenuRoute::right()
{
if (blockInput)
{
return;
}
this->mainMenu->right();
}
void MenuRoute::left()
{
if (blockInput)
{
return;
}
if (this->mainMenu->isInSubmenu())
{
this->mainMenu->left();
}
else
{
this->parentMenu->printMenu();
}
}
void MenuRoute::yes()
{
if (blockInput)
{
return;
}
this->mainMenu->yes();
}
void MenuRoute::no()
{
if (blockInput)
{
return;
}
if (this->mainMenu->isInSubmenu())
{
this->mainMenu->no();
}
else
{
this->left();
}
}
void MenuRoute::init()
{
// auto dummy = []() {
// std::cout << "Dummy in Action" <<std::endl;
// };
this->mainMenu = new Menu;
auto *pointsMenu = new MenuRoutePoints(this->route);
this->mainMenu->setLcd(this->lcd);
pointsMenu->setLcd(this->lcd);
auto *importWrapper = new MenuIntInput(1, new MenuRouteWrapper(this, &MenuRoute::importRoute));
auto *exportWrapper = new MenuIntInput(1, new MenuRouteWrapper(this, &MenuRoute::exportRoute));
auto *deleteWrapper = new MenuIntInput(1, new MenuRouteWrapper(this, &MenuRoute::deleteRoute));
auto *clearWrapper = new MenuActionRoute(this, &MenuRoute::clearRoute);
importWrapper->setLcd(this->lcd);
importWrapper->setMinMax(0, MenuRoute::maxRouteNumber);
importWrapper->setPrintParentMenu(false);
importWrapper->setEntry(0, "Import Route");
exportWrapper->setLcd(this->lcd);
exportWrapper->setMinMax(0, MenuRoute::maxRouteNumber);
exportWrapper->setPrintParentMenu(false);
exportWrapper->setEntry(0, "Export Route");
deleteWrapper->setLcd(this->lcd);
deleteWrapper->setMinMax(0, MenuRoute::maxRouteNumber);
deleteWrapper->setPrintParentMenu(false);
deleteWrapper->setEntry(0, "Delete Route");
this->mainMenu->addEntry(new MenuAction("Points", pointsMenu));
this->mainMenu->addEntry(new MenuAction("Clear", clearWrapper));
this->mainMenu->addEntry(new MenuAction("Import", importWrapper));
this->mainMenu->addEntry(new MenuAction("Export", exportWrapper));
this->mainMenu->addEntry(new MenuAction("Delete", deleteWrapper));
}
void MenuRoute::importRoute(uint8_t routeNumber)
{
this->blockInput = true;
String lineOne = "";
String lineTwo = "";
if (WiFi.status() != WL_CONNECTED)
{
lineOne = "Not connected to";
lineTwo = "the WiFi.";
this->print(lineOne, lineTwo);
this->blockInput = false;
return;
}
if (ESP.getMaxAllocHeap() < JSON_DOCUMENT_SIZE_ROUTE)
{
lineOne = "Not enough mem";
lineTwo = "for Json obj";
this->print(lineOne, lineTwo);
this->blockInput = false;
return;
}
WiFiClient client;
HTTPClient http;
DynamicJsonDocument doc(JSON_DOCUMENT_SIZE_ROUTE);
String host = "http://rover.kleiax.de/api/";
host.concat(routeNumber);
http.begin(client, host);
const int httpResponseCode = http.GET();
lineOne = "Import complete";
lineTwo = "Code: ";
if (httpResponseCode == MenuRoute::httpValidImport)
{
deserializeJson(doc, http.getStream());
}
else
{
lineOne = "HTTP Error";
}
lineTwo.concat(httpResponseCode);
this->print(lineOne, lineTwo);
if (httpResponseCode <= 0)
{
this->blockInput = false;
return;
}
uint16_t totalPoints = doc["amountPoints"];
this->route->clear();
for (uint16_t i = 0; i < totalPoints; i++)
{
Point::Coordinates coords;
coords.lat = doc["points"][i][0].as<double>();
coords.lon = doc["points"][i][1].as<double>();
this->route->addPointToRoute(Point(coords, true));
}
this->blockInput = false;
http.end();
}
void MenuRoute::exportRoute(uint8_t routeNumber)
{
this->blockInput = true;
uint16_t totalPoints = this->route->getRouteInfo().totalPoints;
String lineOne = "";
String lineTwo = "";
if (WiFiSTAClass::status() != WL_CONNECTED)
{
lineOne = "Not connected to";
lineTwo = "the WiFi.";
this->print(lineOne, lineTwo);
this->blockInput = false;
return;
}
if (ESP.getMaxAllocHeap() < JSON_DOCUMENT_SIZE_ROUTE)
{
lineOne = "Not enough mem";
lineTwo = "for Json obj";
this->print(lineOne, lineTwo);
this->blockInput = false;
return;
}
DynamicJsonDocument doc(JSON_DOCUMENT_SIZE_ROUTE);
doc["number"] = routeNumber;
doc["amountPoints"] = totalPoints;
Point::Coordinates coords = this->route->startRoute().getCoordinates();
doc["points"][0][0] = coords.lat;
doc["points"][0][1] = coords.lon;
for (uint16_t i = 1; i < totalPoints; i++)
{
coords = this->route->getNextPoint().getCoordinates();
doc["points"][i][0] = coords.lat;
doc["points"][i][1] = coords.lon;
}
String jsonData;
serializeJson(doc, jsonData);
WiFiClient client;
HTTPClient http;
http.begin(client, "http://rover.kleiax.de/api/");
http.addHeader("Content-Type", "application/json");
const int httpResponseCode = http.POST(jsonData);
if (httpResponseCode == MenuRoute::httpValidExport)
{
lineOne = "Export complete";
}
else
{
lineOne = "HTTP Error";
}
lineTwo = "Code: ";
lineTwo.concat(httpResponseCode);
this->print(lineOne, lineTwo);
this->blockInput = false;
http.end();
}
void MenuRoute::deleteRoute(uint8_t routeNumber)
{
this->blockInput = true;
String lineOne = "";
String lineTwo = "";
if (WiFiSTAClass::status() != WL_CONNECTED)
{
lineOne = "Not connected to";
lineTwo = "the WiFi.";
this->print(lineOne, lineTwo);
this->blockInput = false;
return;
}
if (ESP.getMaxAllocHeap() < JSON_DOCUMENT_SIZE_ROUTE)
{
lineOne = "Not enough mem";
lineTwo = "for Json obj";
this->print(lineOne, lineTwo);
this->blockInput = false;
return;
}
WiFiClient client;
HTTPClient http;
DynamicJsonDocument doc(JSON_DOCUMENT_SIZE_ROUTE);
String host = "http://rover.kleiax.de/api/";
host.concat(routeNumber);
http.begin(client, host);
const int httpResponseCode = http.sendRequest("DELETE");
lineOne = "Delete complete";
lineTwo = "Code: ";
if (httpResponseCode == MenuRoute::httpValidDelete)
{
deserializeJson(doc, http.getStream());
}
else
{
lineOne = "HTTP Error";
}
lineTwo.concat(httpResponseCode);
this->print(lineOne, lineTwo);
this->blockInput = false;
http.end();
}
void MenuRoute::clearRoute(uint8_t none)
{
// The parameter exist only for compability
none;
this->route->clear();
this->print("Currente route", "deleted...");
}
MenuRouteWrapper::MenuRouteWrapper(MenuRoute *menuRoute, DataFunction dataFunction)
: menuRoute{menuRoute}, dataFunction{dataFunction}
{
}
void MenuRouteWrapper::action(int16_t *values, uint8_t length)
{
if (length < 1)
{
std::cout << "Error in MenuRouteWrapper::action" << std::endl;
return;
}
if (values[0] < 0)
{
values[0] = 0;
}
if (values[0] > UINT8_MAX)
{
values[0] = UINT8_MAX;
}
(this->menuRoute->*this->dataFunction)(values[0]);
}
-173
View File
@@ -1,173 +0,0 @@
/**
* @file menuRoute.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a classes to handles routes with the user input.
* @version 0.1
* @date 2022-12-28
*
* @copyright Copyright (c) 2022
*
*/
#ifndef MENU_ROUTE_H
#define MENU_ROUTE_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include "route.h"
#include "menu.h"
#include "menuControl.h"
#include "menuIntInput.h"
#include "menuRoutePoints.h"
#define JSON_DOCUMENT_SIZE_ROUTE 4096
class MenuRoute;
typedef void (MenuRoute::*DataFunction)(uint8_t);
/**
* @brief MenuActionWrapper to call DataFunctions
*
* This class should be used to call importRoute,
* exportRoute and clearRoute over the Menu.
*/
class MenuActionRoute : public MenuActionWrapper
{
public:
/**
* @brief Construct a new Menu Action Route object
*
* @param menuRoute
* @param dataFunction like exportRoute
*/
MenuActionRoute(MenuRoute *menuRoute, DataFunction dataFunction);
/**
* @brief Runs the given DataFunction
*/
void action() override;
private:
MenuRoute *menuRoute;
DataFunction dataFunction;
};
/**
* @brief Handles routes
*
* With this menu the user can import, export and delete routes.
*/
class MenuRoute : public MenuControl
{
public:
/**
* @brief Construct a new Menu Route object
*
* @param route
*/
MenuRoute(Route *route);
~MenuRoute();
/**
* @brief Prints the last informations
*
* On first call this function calls the init function.
* On every call this functions call the printMenu function from
* the mainMenu of this class.
*/
void printMenu() override;
/**
* @name User Inputs
* @brief Inputs given by the parentMenu
*/
///@{
void down() override;
void up() override;
void right() override;
void left() override;
void yes() override;
void no() override;
///@}
/**
* @brief Import a Route.
*
* The functions tries to pull the given route id from the RoverApi.
*
* @param routeNumber id
*/
void importRoute(uint8_t routeNumber);
/**
* @brief Export a Route.
*
* The functions tries to push the current route to the RoverApi.
*
* @param routeNumber id
*/
void exportRoute(uint8_t routeNumber);
/**
* @brief Delete a Route
*
* The functions tries to delete the current route from the RoverApi.
*
* @param routeNumber
*/
void deleteRoute(uint8_t routeNumber);
/**
* @brief Delete the current Route.
*
* @param none this param is not be used.
*/
void clearRoute(uint8_t none);
private:
void init();
Route *route;
Menu *mainMenu = nullptr;
bool isInit = false;
bool blockInput = false;
static constexpr uint8_t maxRouteNumber = 100;
static constexpr uint16_t httpValidExport = 201;
static constexpr uint16_t httpValidImport = 202;
static constexpr uint16_t httpValidDelete = 202;
};
/**
* @brief MenuRouteWrapper to call DataFunctions with numeric user input
*
*/
class MenuRouteWrapper : public MenuIntInputWrapper
{
public:
/**
* @brief Construct a new Menu Route Wrapper object.
*
* @param menuRoute
* @param dataFunction
*/
MenuRouteWrapper(MenuRoute *menuRoute, DataFunction dataFunction);
/**
* @brief Calls the given DataFunction.
*
* @param values The value to be given to the DataFunction.
* @param length Number of values, should be 1.
*/
void action(int16_t *values, uint8_t length) override;
private:
MenuRoute *menuRoute;
DataFunction dataFunction = nullptr;
};
#endif // MENU_ROUTE_H
-101
View File
@@ -1,101 +0,0 @@
/**
* @file menuRoutePoints.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the implementation of the class MenuRoutePoints.
* @version 0.1
* @date 2022-12-28
*
* @copyright Copyright (c) 2022
*
*/
#include "menuRoutePoints.h"
MenuRoutePoints::MenuRoutePoints(Route *route)
: route{route}
{
}
void MenuRoutePoints::init()
{
const uint16_t amountPoints = this->route->getRouteInfo().totalPoints;
if (amountPoints > UINT8_MAX)
{
this->error = true;
}
else
{
this->setCountPages(amountPoints);
}
}
void MenuRoutePoints::printPage() const
{
static constexpr int8_t width = 9;
static constexpr int8_t prec = 7;
static constexpr int8_t bufSize = 20;
const uint8_t currentPage = this->getCurrentPage();
if (this->lastPageNumber == currentPage)
{
return;
}
String lineOne = "N ";
String lineTwo = "E ";
if (this->error)
{
lineOne = "Error: To much";
lineTwo = "points are given";
this->print(lineOne, lineTwo);
return;
}
RouteInfo info = this->route->getRouteInfo();
if (info.totalPoints == 0)
{
lineOne = "No Points are";
lineTwo = "available";
this->print(lineOne, lineTwo);
return;
}
Point point;
if (currentPage == 0)
{
point = this->route->startRoute();
}
else if (this->lastPageNumber - 1 == currentPage)
{
point = this->route->getPreviousPoint();
}
else if (this->lastPageNumber + 1 == currentPage)
{
point = this->route->getNextPoint();
}
else if (currentPage == this->getCountPages() - 1)
{
point = this->route->endRoute();
}
else
{
std::cout << "Error in: MenuRoutePoints::printPage()" << std::endl;
}
char buf[bufSize];
char *string;
info = this->route->getRouteInfo();
string = dtostrf(point.getLatitude(), width, prec, static_cast<char *>(buf));
lineOne.concat(string);
lineOne.concat(" ");
lineOne.concat(info.currentPoint);
// lineOne.concat(currentPage);
string = dtostrf(point.getLongitude(), width, prec, static_cast<char *>(buf));
lineTwo.concat(string);
lineTwo.concat(" ");
lineTwo.concat(info.totalPoints);
// std::cout << "MenuRoutePoints::printPage currentPage: " << (int) currentPage << std::endl;
this->print(lineOne, lineTwo);
}
-50
View File
@@ -1,50 +0,0 @@
/**
* @file menuRoutePoints.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a class to print the coordinates of a Route.
* @version 0.1
* @date 2022-12-28
*
* @copyright Copyright (c) 2022
*
*/
#ifndef MENU_ROUTE_POINTS_H
#define MENU_ROUTE_POINTS_H
#include "navigation.h"
#include "route.h"
#include "menuInformationSites.h"
/**
* @brief Prints coordinates of Route side by side.
*
*/
class MenuRoutePoints : public MenuInformationSites
{
public:
/**
* @brief Construct a new Menu Route Points object
*
* @param route
*/
MenuRoutePoints(Route *route);
/**
* @brief Configure the base class MenuInformationSites
*
* Set the amount of pages.
*/
void init() override;
/**
* @brief Prints the the coordinates of the current Point.
*/
void printPage() const override;
private:
Route *route;
bool error = false;
};
#endif // MENU_ROUTE_POINTS_H
+3 -56
View File
@@ -31,27 +31,11 @@ void MenuSensorData::printPage() const
switch (this->getCurrentPage()) switch (this->getCurrentPage())
{ {
case 0: case 0:
lineOne = " Y P R :";
lineTwo.concat(this->sensorData->getGyroData()[0]);
lineTwo.concat(" ");
lineTwo.concat(this->sensorData->getGyroData()[1]);
lineTwo.concat(" ");
lineTwo.concat(this->sensorData->getGyroData()[2]);
break;
case 1:
lineOne = "Real Azimuth:"; lineOne = "Real Azimuth:";
lineTwo.concat(this->sensorData->getRealAzimuth()); lineTwo.concat(this->sensorData->getRealAzimuth());
break; break;
case 2: case 1:
lineOne = "Calc Azimuth:";
lineTwo.concat(this->sensorData->getCalcAzimuth());
lineTwo.concat(" ");
lineTwo.concat(CalcAzimuth::stateToString(this->sensorData->getCalcAzimuthState()));
break;
case 3:
{ {
lineOne = "Lat:"; lineOne = "Lat:";
lineTwo = "Lon:"; lineTwo = "Lon:";
@@ -61,7 +45,7 @@ void MenuSensorData::printPage() const
} }
break; break;
case 4: case 2:
lineOne = "Time: "; lineOne = "Time: ";
lineTwo = ""; lineTwo = "";
if (static_cast<bool>(fixType)) if (static_cast<bool>(fixType))
@@ -91,44 +75,7 @@ void MenuSensorData::printPage() const
break; break;
case 5: case 3:
{
lineOne = "CarSol: ";
lineTwo = "Ntrip: ";
const uint8_t carrSoln = gpsData->flags.bits.carrSoln;
if (carrSoln == 0)
{
lineOne.concat("None");
}
else if (carrSoln == 1)
{
lineOne.concat("Floating");
}
else if (carrSoln == 2)
{
lineOne.concat("Fixed");
}
else
{
lineOne = "UNKNOWN";
}
const NTRIPClientStates status = this->sensorData->getNtripState();
if (status == NTRIPClientStates::pushData)
{
lineTwo.concat("enabled");
}
else if (status == NTRIPClientStates::notAvailable)
{
lineTwo.concat(" N/A");
}
else
{
lineTwo.concat("disabled");
}
}
break;
case 6:
lineOne = "HAcc: "; lineOne = "HAcc: ";
lineTwo = "Sats: "; lineTwo = "Sats: ";
if (static_cast<bool>(fixType)) if (static_cast<bool>(fixType))
@@ -1,308 +0,0 @@
/**
* @file menuAutopilot.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains an implementation of the class MenuAutopilot
* @version 0.1
* @date 2022-02-03
*
* @copyright Copyright (c) 2022
*
*/
#include "menuAutopilot.h"
void MenuAutopilot::printPage() const
{
const CourseCorrection correction = this->autopilot->getCourseCorrection();
const UBX_NAV_PVT_data_t *gpsData = this->autopilot->getSensorData()->getGnssData();
const bool navigationStarted = this->autopilot->getState() >= Autopilot::State::NavigationStarted;
String distanceString = "";
if (navigationStarted)
{
uint16_t distance = 0;
if (correction.distance < 1)
{
distance = static_cast<uint16_t>(correction.distance * 100);
distanceString.concat(distance);
distanceString.concat("cm");
}
else if (correction.distance < 1000)
{
distance = static_cast<uint16_t>(correction.distance);
distanceString.concat(distance);
distanceString.concat("m");
}
else
{
distance = static_cast<uint16_t>(correction.distance / 1000);
distanceString.concat(distance);
distanceString.concat("km");
}
}
String lineOne = "No information";
String lineTwo = "available";
switch (this->getCurrentPage())
{
case 0:
{
lineOne = "Status: ";
lineTwo = "";
switch (this->autopilot->getState())
{
case Autopilot::State::InsufficientAccuracy:
lineTwo = "Err: LowAccuracy";
break;
case Autopilot::State::NoRoute:
lineTwo = "Err: No route";
break;
case Autopilot::State::NavigationStarted:
lineTwo = "Nav started";
break;
case Autopilot::State::GetToStartPoint:
lineTwo = "Drive to start";
break;
case Autopilot::State::SelfDrivingAvailable:
lineTwo = "Autopilot ready";
break;
case Autopilot::State::SelfDriving:
lineTwo = "Autopilot active";
break;
case Autopilot::State::SelfDrivingRotate:
lineTwo = "Rotating";
break;
case Autopilot::State::TargetReached:
lineTwo = "Target reached";
break;
default:
lineTwo = "UNKOWN - ";
lineTwo.concat(static_cast<int>(this->autopilot->getState()));
break;
}
break;
}
case 1:
if (!navigationStarted)
{
lineOne = "Navigation is";
lineTwo = "not started";
break;
}
lineOne = "Distance: ";
lineOne.concat(distanceString);
lineTwo = "Turn: ";
lineTwo.concat(correction.correction);
break;
case 2:
lineOne = "Target waypoint";
lineTwo = "";
lineTwo.concat(this->autopilot->getRouteInfo().currentPoint);
lineTwo.concat(" from ");
lineTwo.concat(this->autopilot->getRouteInfo().totalPoints);
break;
case 3:
{
NTRIPClientStates status = this->autopilot->getSensorData()->getNtripClient()->getClientState();
const uint8_t carrSoln = gpsData->flags.bits.carrSoln;
lineOne = "GNSS: ";
if (status == NTRIPClientStates::pushData)
{
if (carrSoln == 0)
{
lineOne.concat("None");
}
else if (carrSoln == 1)
{
lineOne.concat("Floating");
}
else if (carrSoln == 2)
{
lineOne.concat("Fixed");
}
else
{
lineOne.concat("UNKNOWN");
}
}
else if (status == NTRIPClientStates::notAvailable)
lineOne.concat("No WiFi");
else
{
lineOne.concat("Offline");
}
lineTwo = "hAcc: ";
if (static_cast<bool>(gpsData->fixType))
{
lineTwo.concat(gpsData->hAcc);
}
else
{
lineTwo.concat("0");
}
break;
}
case 4:
if (this->autopilot->getSensorData()->getCalcAzimuth() == CalcAzimuth::State::Good || this->autopilot->getSensorData()->getCalcAzimuth() == CalcAzimuth::State::Super)
{
lineOne = "Calc Azi: ";
lineTwo = "State: ";
lineOne.concat(this->autopilot->getSensorData()->getCalcAzimuth());
switch (this->autopilot->getSensorData()->getCalcAzimuthState())
{
case CalcAzimuth::State::Bad:
lineTwo.concat("Bad");
break;
case CalcAzimuth::State::Good:
lineTwo.concat("Good");
break;
case CalcAzimuth::State::Invalid:
lineTwo.concat("Invalid");
break;
case CalcAzimuth::State::Ok:
lineTwo.concat("Ok");
break;
case CalcAzimuth::State::Super:
lineTwo.concat("Super");
break;
default:
lineTwo.concat("Unkown");
break;
}
}
else
{
lineOne = "Real Azi: ";
lineTwo = "";
lineOne.concat(this->autopilot->getSensorData()->getRealAzimuth());
}
break;
case 5:
lineOne = "Loop mode is";
if (this->autopilot->getLoopMode())
{
lineTwo = "enabled";
}
else
{
lineTwo = "disabled";
}
break;
case 6:
lineOne = "Freeze target is";
if (this->targetFreezed)
{
lineTwo = "activated";
}
else
{
lineTwo = "deactivated";
}
break;
case 7:
lineOne = "MinDisToPoint:";
lineTwo = "<- ";
lineTwo.concat(this->minDistance);
lineTwo.concat(" ->");
break;
default:
this->printDefault();
return;
}
this->print(lineOne, lineTwo);
}
void MenuAutopilot::runCommand()
{
switch (this->getCurrentPage())
{
case 5:
this->autopilot->switchLoopMode();
break;
case 6:
if (this->targetFreezed)
{
this->targetFreezed = false;
this->autopilot->getNavigation()->freezeTargetPoint(false);
}
else
{
this->targetFreezed = true;
this->autopilot->getNavigation()->freezeTargetPoint();
}
break;
case 7:
this->minDistance = this->autopilot->getNavigation()->increaseMinDistanceToReachPoint();
break;
default:
break;
}
}
void MenuAutopilot::runCommandNo()
{
switch (this->getCurrentPage())
{
case 7:
this->minDistance = this->autopilot->getNavigation()->decreaseMinDistanceToReachPoint();
break;
default:
break;
}
}
void MenuAutopilot::update()
{
if (!this->autopilot->shouldUpdate())
{
return;
}
this->routeInfo = this->autopilot->getRouteInfo();
this->printMenu();
}
void MenuAutopilot::init()
{
this->setCountPages(8);
this->autopilot = new Autopilot();
this->driveManager->changeModus(this->autopilot);
this->routeInfo = this->autopilot->getRouteInfo();
// dirty hack to get the val, can be better!!! TODO
this->autopilot->getNavigation()->increaseMinDistanceToReachPoint();
this->minDistance = this->autopilot->getNavigation()->decreaseMinDistanceToReachPoint();
MenuDriveMode::init();
}
@@ -1,60 +0,0 @@
/**
* @file menuAutopilot.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a class to print informations about the Autopilot
* @version 0.1
* @date 2022-02-03
*
* @copyright Copyright (c) 2022
*
*/
#ifndef MENU_AUTOPILOT_DRIVE_H
#define MENU_AUTOPILOT_DRIVE_H
#include "SpecialMenus/driveModi/menuDriveMode.h"
#include "driveModi/Modi/Autopilot/autopilot.h"
/**
* @brief A class to print informations about the Autopilot
*
*/
class MenuAutopilot : public MenuDriveMode
{
public:
/**
* @brief Construct a new Menu Autopilot object
*
* @param driveManager for MenuDriveMode
*/
MenuAutopilot(DriveManager *driveManager) : MenuDriveMode(driveManager) {}
/**
* @brief Prints the Information to display and console
*
* The informations are only printed to the display if it
* set.
*
* Changes the DriveModi to Autopilot if it is the first time called
* and save the Autopilot object.
*/
void printPage() const override;
/**
* @brief can be called to update shown data
*/
void update() override;
private:
void init() override;
void runCommand() override;
void runCommandNo() override;
bool mutable targetFreezed = false;
double mutable minDistance;
Autopilot *autopilot;
RouteInfo routeInfo;
};
#endif // MENU_AUTOPILOT_DRIVE_H
@@ -1,174 +0,0 @@
/**
* @file menuCaptureRoute.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains an implementation of the class MenuCaptureRoute
* @version 0.1
* @date 2022-01-31
*
* @copyright Copyright (c) 2022
*
*/
#include "menuCaptureRoute.h"
void MenuCaptureRoute::printPage() const
{
const RouteInfo routeInfo = this->captureRoute->getRouteInfo();
const UBX_NAV_PVT_data_t *gpsData = this->captureRoute->getSensorData()->getGnssData();
String lineOne = "";
String lineTwo = "";
switch (this->getCurrentPage())
{
case 0:
lineOne = "Capture Route";
lineTwo = "You can drive";
break;
case 1:
lineOne = "Saved waypoints";
lineTwo.concat(routeInfo.totalPoints);
break;
case 2:
lineOne = "Last status:";
switch (this->captureRoute->getLastStatus())
{
case Navigation::Status::InsufficientAccuracy:
lineTwo = "Poor Accuracy";
break;
case Navigation::Status::Updated:
lineTwo = "Point added";
break;
case Navigation::Status::Unchanged:
lineTwo = "Point too close";
break;
default:
lineTwo = "---";
break;
}
break;
case 3:
lineOne = "Distance to last";
lineTwo = "point: ";
lineTwo.concat(this->captureRoute->getDistanceToLastPoint());
break;
case 4:
{
NTRIPClientStates status = this->captureRoute->getSensorData()->getNtripClient()->getClientState();
lineOne = "NTRIP Client is";
if (status == NTRIPClientStates::pushData)
{
lineTwo = "enabled";
}
else if (status == NTRIPClientStates::notAvailable)
{
lineTwo = "not available";
}
else
{
lineTwo = "disabled";
}
break;
}
case 5:
{
lineOne = "Carrier Solution";
uint8_t carrSoln = gpsData->flags.bits.carrSoln;
if (carrSoln == 0)
{
lineTwo = "None";
}
else if (carrSoln == 1)
{
lineTwo = "Floating";
}
else if (carrSoln == 2)
{
lineTwo = "Fixed";
}
else
{
lineTwo = "UNKNOWN";
}
break;
}
case 6:
lineOne = "hAccuracy: ";
lineTwo = "Azimuth: ";
lineTwo.concat(this->captureRoute->getSensorData()->getRealAzimuth());
if (gpsData->fixType)
{
lineOne.concat(gpsData->hAcc);
}
else
{
lineOne.concat("0");
}
break;
case 7:
lineOne = "Current minimal";
if (this->captureRoute->getNavigation()->getMinAccuracy() >= Point::Accuracy::twoDigOfCM)
{
lineTwo = "accuracy is high";
}
else
{
lineTwo = "accuracy is low";
}
break;
default:
this->printDefault();
return;
}
this->print(lineOne, lineTwo);
}
void MenuCaptureRoute::update()
{
if (!this->captureRoute->shouldUpdate())
{
return;
}
this->printMenu();
}
void MenuCaptureRoute::runCommand()
{
switch (this->getCurrentPage())
{
case 7:
if (this->captureRoute->getNavigation()->getMinAccuracy() >= Point::Accuracy::twoDigOfCM)
{
this->captureRoute->getNavigation()->setMinAccuracy(Point::Accuracy::none);
}
else
{
this->captureRoute->getNavigation()->setMinAccuracy(Point::Accuracy::twoDigOfCM);
}
break;
default:
break;
}
}
void MenuCaptureRoute::init()
{
this->setCountPages(8);
MenuDriveMode::updateDelay = MenuCaptureRoute::updateDelay;
this->captureRoute = new CaptureRoute();
this->driveManager->changeModus(this->captureRoute);
MenuDriveMode::init();
}
@@ -1,56 +0,0 @@
/**
* @file menuCaptureRoute.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a class to print informations about CaptureRoute
* @version 0.1
* @date 2022-01-31
*
* @copyright Copyright (c) 2022
*
*/
#ifndef MENU_CAPTURE_ROUTE_H
#define MENU_MANUAL_DRIVE_H
#include "SpecialMenus/driveModi/menuDriveMode.h"
#include "driveModi/Modi/CaptureRoute/captureRoute.h"
/**
* @brief A class to print informations about the Autopilot
*
*/
class MenuCaptureRoute : public MenuDriveMode
{
public:
/**
* @brief Construct a new Menu Capture Route object
*
* @param driveManager
*/
MenuCaptureRoute(DriveManager *driveManager) : MenuDriveMode(driveManager) {}
/**
* @brief Prints the Information to display and console
*
* The informations are only printed to the display if it
* set.
*
* Changes the DriveModi to CaptureRoute if it is the first time called
* and save the CaptureRoute object.
*/
void printPage() const override;
/**
* @brief can be called to update shown data
*/
void update() override;
private:
void runCommand() override;
void init() override;
CaptureRoute *captureRoute = nullptr;
static constexpr uint16_t updateDelay = 500;
};
#endif // MENU_MANUAL_DRIVE_H
@@ -48,7 +48,6 @@ void MenuDriveMode::left()
this->firstPrint = true; this->firstPrint = true;
this->configureOnLeave(); this->configureOnLeave();
delete this->menuSpeed;
this->driveManager->changeModus(); this->driveManager->changeModus();
MenuInformationSites::left(); MenuInformationSites::left();
} }
-304
View File
@@ -1,304 +0,0 @@
/**
* @file autopilot.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the implementation of the class Autopilot
* @version 0.1
* @date 2022-02-02
*
* @copyright Copyright (c) 2022
*
*/
#include "driveModi/Modi/Autopilot/autopilot.h"
#include "autopilot.h"
DirectionChangeSignal::DirectionChangeSignal(Autopilot *pilot)
: pilot {pilot}
{
this->action();
}
DirectionChangeSignal::~DirectionChangeSignal()
{
CalcAzimuth *calcAzimuth = pilot->getSensorData()->getCalcCompass();
if (static_cast<bool>(calcAzimuth))
{
calcAzimuth->disableCalcAzimuth();
}
}
void DirectionChangeSignal::action()
{
CalcAzimuth *calcAzimuth = pilot->getSensorData()->getCalcCompass();
if (static_cast<bool>(calcAzimuth))
{
calcAzimuth->drivingDirectionChange(pilot->getSensorData()->getCurrentPos());
}
}
Autopilot::~Autopilot()
{
delete this->directionChangeSignal;
// this->navigation->getNTRIPClient()->setActivated(false);
}
void Autopilot::run()
{
this->routeInfo = this->navigation->getRouteInfo();
switch (this->state)
{
case State::InsufficientAccuracy:
this->askNavigationForOrder();
return;
case State::NoRoute:
return;
case State::None:
return;
case State::NavigationStarted:
this->askNavigationForOrder();
this->checkButtonInput();
break;
case State::GetToStartPoint:
ManualControl::run();
this->askNavigationForOrder();
if (this->routeInfo.currentPoint >= 2){
this->state = State::SelfDrivingAvailable;
}
break;
case State::SelfDrivingAvailable:
ManualControl::run();
this->askNavigationForOrder();
this->checkButtonInput();
break;
case State::SelfDriving:
this->askNavigationForOrder();
this->checkButtonInput();
this->selfDriving();
break;
case SelfDrivingRotate:
this->checkButtonInput();
this->rotate();
break;
case State::TargetReached:
if (this->loopMode){
this->restartLoop();
}
break;
default:
break;
}
}
void Autopilot::restart()
{
this->init();
}
bool Autopilot::shouldUpdate()
{
if (this->updateDisplay)
{
this->updateDisplay = false;
return true;
}
return false;
}
void Autopilot::testRotate(int16_t degree)
{
if (!static_cast<bool>(degree))
{
return;
}
this->courseCorrection.correction = degree;
this->beginRotate();
}
void Autopilot::init()
{
if (this->navigation->startNavigation())
{
this->state = State::NavigationStarted;
}
else
{
this->state = State::NoRoute;
}
this->routeInfo = this->navigation->getRouteInfo();
this->sensorData->getNtripClient()->setAutoReconnect(true);
this->lastOrderStatus = this->navigation->getCourseCorrection(this->courseCorrection, true);
this->courseCorrection.correction = 0;
this->courseCorrection.distance = 0;
this->updateDisplay = true;
}
void Autopilot::drive()
{
DrivingSpeeds speeds = {0, 0};
if (this->courseCorrection.distance >= this->minRemainingDistance)
{
speeds.x = this->maxSpeeds.x;
}
this->moveControl->setSpeeds(speeds);
}
void Autopilot::beginRotate()
{
if (this->state != State::SelfDrivingRotate)
{
this->lastState = this->state;
this->state = State::SelfDrivingRotate;
this->rotationAimAzimuth = this->getSensorData()->getRealAzimuth() + this->courseCorrection.correction;
this->rotationAimAzimuth = Navigation::fixDegree(this->rotationAimAzimuth);
DrivingSpeeds speeds = {0, 0};
if (this->courseCorrection.correction > 0)
{
speeds.rot = -this->maxSpeeds.rot;
}
else
{
speeds.rot = this->maxSpeeds.rot;
}
this->moveControl->setSpeeds(speeds);
}
}
void Autopilot::rotate()
{
if (abs(this->getSensorData()->getRealAzimuth() - this->rotationAimAzimuth) < this->maxCourseDeviationBeforeAct)
{
this->endRotate();
return;
}
if ((abs(this->getSensorData()->getRealAzimuth() - this->rotationAimAzimuth) < this->maxCourseDeviationBeforeAct * 3) &&
((this->courseCorrection.correction > 0 && this->rotationAimAzimuth < this->getSensorData()->getRealAzimuth()) || (this->courseCorrection.correction < 0 && this->rotationAimAzimuth > this->getSensorData()->getRealAzimuth())))
{
this->endRotate();
std::cout << "Autopilot::rotate: Rover rotated too far" << std::endl;
}
}
void Autopilot::endRotate()
{
if (this->state != State::SelfDrivingRotate)
{
return;
}
this->state = this->lastState;
this->sensorData->getCalcCompass()->drivingDirectionChange(this->sensorData->getCurrentPos());
this->moveControl->setRotationSpeed(0);
this->moveControl->emergencyStop();
this->moveControl->setDrivingStatus(MoveControl::Status::Drive);
}
void Autopilot::checkButtonInput()
{
if (ControlPadButton::isControlPadButtonPressed(this->input, ControlPadButton::PadButton::Action) && millis() - this->lastAutopilotChangeMillis > this->autopilotChangeDelayMillis)
{
if (this->state == State::SelfDrivingAvailable)
{
this->state = State::SelfDriving;
}
else if (this->state == State::SelfDriving || this->state == State::SelfDrivingRotate)
{
this->state = State::SelfDrivingAvailable;
}
else if (this->state == State::NavigationStarted)
{
this->state = State::GetToStartPoint;
}
this->updateDisplay = true;
this->lastAutopilotChangeMillis = millis();
}
}
void Autopilot::askNavigationForOrder()
{
this->lastOrderStatus = this->navigation->getCourseCorrection(this->courseCorrection);
switch (this->lastOrderStatus)
{
case Navigation::Status::Complete:
this->state = State::TargetReached;
this->moveControl->setSpeed(0);
this->moveControl->setRotationSpeed(0);
break;
case Navigation::Status::InsufficientAccuracy:
if (this->state == State::InsufficientAccuracy){
break;
}
this->lastState = this->state;
this->state = State::InsufficientAccuracy;
this->moveControl->setSpeed(0);
this->moveControl->setRotationSpeed(0);
break;
case Navigation::Status::Unchanged:
if (this->state == State::InsufficientAccuracy){
this->state = this->lastState;
}
break;
case Navigation::Status::Updated:
if (this->state == State::InsufficientAccuracy){
this->state = this->lastState;
}
break;
default:
break;
}
}
void Autopilot::selfDriving()
{
if (this->state != State::SelfDriving)
{
return;
}
if (abs(this->courseCorrection.correction) >= this->maxCourseDeviationBeforeAct)
{
this->beginRotate();
}
else
{
this->drive();
}
}
void Autopilot::restartLoop()
{
this->navigation->startNavigation();
this->state = State::SelfDriving;
this->routeInfo = this->navigation->getRouteInfo();
this->lastOrderStatus = this->navigation->getCourseCorrection(this->courseCorrection, true);
this->updateDisplay = true;
}
void Autopilot::afterActivate()
{
this->setInputMode(ManualControl::InputMode::Digital);
this->directionChangeSignal = new DirectionChangeSignal(this);
this->setDirectionChangeCallback(this->directionChangeSignal);
this->navigation = new Navigation(this->sensorData);
this->init();
}
-131
View File
@@ -1,131 +0,0 @@
/**
* @file autopilot.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a class which use the navigate class to drive automaticaly
* @version 0.1
* @date 2022-02-02
*
* @copyright Copyright (c) 2022
*
*/
#ifndef AUTOPILOT_H
#define AUTOPILOT_H
#include "navigation.h"
#include "driveModi/Modi/ManualControl/manualControl.h"
class DirectionChangeSignal;
/**
* @brief This class use the navigate class to drive automaticaly
*
* This class get the information from the navigate class. When an
* object of this class is constructed the rover can be driven manually.
* When the Rover is near to the first position of the Route, you can
* switch to automatic drive.
*
*/
class Autopilot : public ManualControl
{
public:
enum State
{
InsufficientAccuracy = -2,
NoRoute = -1,
None = 0,
NavigationStarted,
GetToStartPoint,
SelfDrivingAvailable,
SelfDriving,
SelfDrivingRotate,
TargetReached
};
/**
* @brief Destroy the Autopilot object
*
* Disconnect the NTRIP-Client
*/
~Autopilot();
void restart();
/**
* @brief Get the Route Info object
*
* @return RouteInfo
*/
RouteInfo getRouteInfo() const { return this->routeInfo; }
/**
* @brief Get the Course Correction object
*
* @return CourseCorrection
*/
CourseCorrection getCourseCorrection() const { return this->courseCorrection; }
/**
* @brief Get the State object
*
* @return State
*/
State getState() const { return this->state; }
Navigation *getNavigation() const { return this->navigation; }
/**
* @brief Tells if there are new informations to display
*
* @return true
* @return false
*/
bool shouldUpdate();
void testRotate(int16_t degree);
void endRotate();
void switchLoopMode() { this->loopMode = !this->loopMode; }
bool getLoopMode() const { return this->loopMode; }
private:
void init();
void drive();
void beginRotate();
void rotate();
void run() override;
void checkButtonInput();
void askNavigationForOrder();
void selfDriving();
void restartLoop();
void afterActivate() override;
Navigation *navigation = nullptr;
CourseCorrection courseCorrection{0, 0};
RouteInfo routeInfo{0, 0};
State state = State::None;
State lastState = State::None;
Navigation::Status lastOrderStatus;
DirectionChangeSignal *directionChangeSignal = nullptr;
bool updateDisplay = false;
bool loopMode = false;
uint8_t maxCourseDeviationBeforeAct = 5;
uint16_t autopilotChangeDelayMillis = 500;
uint32_t lastAutopilotChangeMillis = 0;
int16_t rotationAimAzimuth = 0;
double minRemainingDistance = 0.25;
};
class DirectionChangeSignal : public DirectionChangeWrapper
{
public:
DirectionChangeSignal(Autopilot *pilot);
~DirectionChangeSignal();
void action() override;
private:
Autopilot *pilot;
};
#endif // AUTOPILOT_H
@@ -1,65 +0,0 @@
/**
* @file captureRoute.cpp
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains the implementation of the class CaptureRoute
* @version 0.1
* @date 2022-02-15
*
* @copyright Copyright (c) 2022
*
*/
#include "driveModi/Modi/CaptureRoute/captureRoute.h"
#include "captureRoute.h"
CaptureRoute::~CaptureRoute()
{
delete this->navigation;
if (static_cast<bool>(this->sensorData->getNtripClient()))
{
this->sensorData->getNtripClient()->setActivated(false);
}
}
void CaptureRoute::run()
{
ManualControl::run();
if (ControlPadButton::isControlPadButtonPressed(this->input, ControlPadButton::PadButton::Action))
{
this->status = this->navigation->addCurrentPosToRoute();
if (this->status == Navigation::Status::Updated)
{
this->lastSavedPoint = this->navigation->getCurrentPosition();
this->routeInfo = navigation->getRouteInfo();
this->updateDisplay = true;
}
}
}
void CaptureRoute::afterActivate()
{
this->navigation = new Navigation(this->sensorData);
this->navigation->getRoute()->clear();
this->sensorData->getNtripClient()->setAutoReconnect(true);
this->routeInfo = navigation->getRouteInfo();
}
double CaptureRoute::getDistanceToLastPoint() const
{
if (!this->lastSavedPoint.isInit())
{
return 0;
}
return this->lastSavedPoint.distanceTo(this->navigation->getCurrentPosition());
}
bool CaptureRoute::shouldUpdate()
{
if (this->updateDisplay)
{
this->updateDisplay = false;
return true;
}
return false;
}
@@ -1,75 +0,0 @@
/**
* @file captureRoute.h
* @author Alexander Klein (alex@kleiax.de)
* @brief Contains a class to capture a driven route
* @version 0.1
* @date 2022-02-15
*
* @copyright Copyright (c) 2022
*
*/
#ifndef CAPTURE_ROUTE_H
#define CAPTURE_ROUTE_H
#include <iostream>
#include "driveModi/Modi/ManualControl/manualControl.h"
#include "navigation.h"
/**
* @brief A class to capture a driven class
*
* This class inherits ManualControl so you can drive
* normally as in ManualControl. If GPS signal is valid
* you can add a Point everytime you want.
*
*/
class CaptureRoute : public ManualControl
{
public:
/**
* @brief Destroy the Capture Route object
*
* Disconnect the NTRIP-Client
*/
~CaptureRoute();
/**
* @brief Get the Route Info object
*
* @return RouteInfo
*/
RouteInfo getRouteInfo() const { return this->routeInfo; }
Navigation::Status getLastStatus() const { return this->status; }
Navigation *getNavigation() const { return this->navigation; }
/**
* @brief Get the distance to the last saved oint
*
* @return double in meters
*/
double getDistanceToLastPoint() const;
/**
* @brief Tells if there are new informations to display
*
* @return true
* @return false
*/
bool shouldUpdate();
private:
void run() override;
void afterActivate() override;
Navigation *navigation = nullptr;
RouteInfo routeInfo;
Point lastSavedPoint;
Navigation::Status status = Navigation::Status::Complete;
bool updateDisplay = false;
};
#endif // CAPTURE_ROUTE_H
@@ -47,7 +47,7 @@ void ManualControl::analogControl()
void ManualControl::digitalControl() void ManualControl::digitalControl()
{ {
static constexpr uint8_t deadzone = 120; static constexpr uint8_t deadzone = 110;
const int16_t yAxis = this->input->x - 127; const int16_t yAxis = this->input->x - 127;
const int16_t xAxis = this->input->y - 127; const int16_t xAxis = this->input->y - 127;
-2
View File
@@ -82,8 +82,6 @@ bool TestMode::drive(int16_t cmDistance, int16_t degree)
} }
else else
{ {
// forward or backward and left or right
// TODO: Calculate roationspeed
if (cmDistance < 0) if (cmDistance < 0)
{ {
this->moveControl->setSpeed(-this->maxSpeeds.x); this->moveControl->setSpeed(-this->maxSpeeds.x);
-1
View File
@@ -14,7 +14,6 @@
#include "moveControl.h" #include "moveControl.h"
#include "driveModi/driveModi.h" #include "driveModi/driveModi.h"
#include "navigation.h"
#include "config.h" #include "config.h"
#include "controlPadInput.h" #include "controlPadInput.h"
#include "component.h" #include "component.h"
+17 -30
View File
@@ -39,13 +39,10 @@
#include "menu.h" #include "menu.h"
#include "menuAction.h" #include "menuAction.h"
#include "SpecialMenus/driveModi/ManualDrive/menuManualDrive.h" #include "SpecialMenus/driveModi/ManualDrive/menuManualDrive.h"
#include "SpecialMenus/driveModi/CaptureRoute/menuCaptureRoute.h"
#include "SpecialMenus/driveModi/Autopilot/menuAutopilot.h"
#include "SpecialMenus/driveModi/TestMode/menuTestMode.h" #include "SpecialMenus/driveModi/TestMode/menuTestMode.h"
#include "SpecialMenus/driveModi/CalibrateCompass/menuCalibrateCompass.h" #include "SpecialMenus/driveModi/CalibrateCompass/menuCalibrateCompass.h"
#include "SpecialMenus/Systeminformation/menuSysteminformation.h" #include "SpecialMenus/Systeminformation/menuSysteminformation.h"
#include "SpecialMenus/PID/menuPidSettings.h" #include "SpecialMenus/PID/menuPidSettings.h"
#include "SpecialMenus/Route/menuRoute.h"
#include "SpecialMenus/SensorData/menuSensorData.h" #include "SpecialMenus/SensorData/menuSensorData.h"
#include "SpecialMenus/CalibrateBattery/menuCalibrateBattery.h" #include "SpecialMenus/CalibrateBattery/menuCalibrateBattery.h"
@@ -125,12 +122,6 @@ void setup()
sensorData = new SensorData(); sensorData = new SensorData();
sensorData->enableGnss(spiPort, PinNumbers::gnssSpiCs); sensorData->enableGnss(spiPort, PinNumbers::gnssSpiCs);
sensorData->enableRealCompass(); sensorData->enableRealCompass();
sensorData->enableNtrip(static_cast<const char *>(NtripConfig::host),
NtripConfig::port,
static_cast<const char *>(NtripConfig::mountPoint),
static_cast<const char *>(NtripConfig::user),
static_cast<const char *>(NtripConfig::password));
// sensorData->enableGyroscope();
driveManager = new DriveManager(&moveController, sensorData, controlPad->getControlPadDataPtr()); driveManager = new DriveManager(&moveController, sensorData, controlPad->getControlPadDataPtr());
char wifiIndicator = 'X'; char wifiIndicator = 'X';
@@ -138,12 +129,16 @@ void setup()
{ {
wifiIndicator = '-'; wifiIndicator = '-';
} }
lcdWrapper = new LcdWrapper(lcd);
lcdWrapper->setCallback(lcdWrapperCallback);
lcdWrapper->loop();
lcd->backlight(); lcd->backlight();
lcd->setCursor(0, 0);
lcd->printf("%c Kleiax-Rover %c", wifiIndicator, wifiIndicator); lcd->printf("%c Kleiax-Rover %c", wifiIndicator, wifiIndicator);
lcd->setCursor(0, 1); lcd->setCursor(0, 1);
lcd->printf("WiFi channel %u", Network::getCurrentChannel()); lcd->printf("WiFi channel %u", Network::getCurrentChannel());
lcdWrapper = new LcdWrapper(lcd);
lcdWrapper->setCallback(lcdWrapperCallback);
makeMenu(); makeMenu();
@@ -160,7 +155,7 @@ void loop()
lcdWrapper->loop(); lcdWrapper->loop();
mainBattery->loop(); mainBattery->loop();
// new Value ervery 0.5s // new Value every 0.5s
if (mainBattery->isNewValue()) if (mainBattery->isNewValue())
{ {
static uint8_t batteryLowCounter = 0; static uint8_t batteryLowCounter = 0;
@@ -193,14 +188,14 @@ void loop()
void i2cScanner() void i2cScanner()
{ {
constexpr uint8_t checkForLength = 16; constexpr uint8_t checkForLength = 16;
constexpr uint8_t maxAdresses = UINT8_MAX / 2; constexpr uint8_t maxAddresses = UINT8_MAX / 2;
std::cout << "\nI2C Scanner" << std::endl; std::cout << "\nI2C Scanner" << std::endl;
byte error = 0; byte error = 0;
byte address = 0; byte address = 0;
int nDevices = 0; int nDevices = 0;
std::cout << "Scanning..." << std::endl; std::cout << "Scanning..." << std::endl;
for (address = 1; address < maxAdresses; address++) for (address = 1; address < maxAddresses; address++)
{ {
Wire.beginTransmission(address); Wire.beginTransmission(address);
error = Wire.endTransmission(); error = Wire.endTransmission();
@@ -254,32 +249,24 @@ void makeMenu()
auto *pidr_m = new MenuIntInput(3, new MenuPidSettings(moveController.getPID(1))); auto *pidr_m = new MenuIntInput(3, new MenuPidSettings(moveController.getPID(1)));
auto *speed_m = new MenuIntInput(2, new MenuSpeed(driveManager->getDrivingSpeedsRef())); auto *speed_m = new MenuIntInput(2, new MenuSpeed(driveManager->getDrivingSpeedsRef()));
auto *man_m = new MenuManualControl(driveManager); auto *man_m = new MenuManualControl(driveManager);
auto *cap_m = new MenuCaptureRoute(driveManager);
auto *auto_m = new MenuAutopilot(driveManager);
auto *testM_m = new MenuTestMode(driveManager); auto *testM_m = new MenuTestMode(driveManager);
auto *comp_m = new MenuCalibrateCompass(driveManager); auto *comp_m = new MenuCalibrateCompass(driveManager);
auto *sys_m = new MenuSysteminformation(mainBattery); auto *sys_m = new MenuSysteminformation(mainBattery);
auto *sen_m = new MenuSensorData(sensorData); auto *sen_m = new MenuSensorData(sensorData);
// TODO: Wie bekommt jeder die dumme Route?
auto *rout_m = new MenuRoute(new Route());
auto *bat_m = new MenuCalibrateBattery(mainBattery); auto *bat_m = new MenuCalibrateBattery(mainBattery);
auto_m->setUpdateDelay(displayUpdateDelay);
sys_m->setUpdateDelay(displayUpdateDelay); sys_m->setUpdateDelay(displayUpdateDelay);
sen_m->setUpdateDelay(displayUpdateDelay); sen_m->setUpdateDelay(displayUpdateDelay);
// Entry for the main menu // Entry for the main menu
main_m->addEntry(new MenuAction("Mode", mode_m)); main_m->addEntry(new MenuAction("Mode", mode_m));
main_m->addEntry(new MenuAction("Sensor", sen_m)); main_m->addEntry(new MenuAction("Sensor", sen_m));
main_m->addEntry(new MenuAction("Route", rout_m));
main_m->addEntry(new MenuAction("Settings", set_m)); main_m->addEntry(new MenuAction("Settings", set_m));
main_m->addEntry(new MenuAction("Systeminfo", sys_m)); main_m->addEntry(new MenuAction("Systeminfo", sys_m));
main_m->addEntry(new MenuAction("Restart", restart)); main_m->addEntry(new MenuAction("Restart", restart));
// Entry for the mode Menu // Entry for the mode Menu
mode_m->addEntry(new MenuAction("Manual Control", man_m)); mode_m->addEntry(new MenuAction("Manual Control", man_m));
mode_m->addEntry(new MenuAction("Capture Route", cap_m));
mode_m->addEntry(new MenuAction("Autopilot", auto_m));
mode_m->addEntry(new MenuAction("Gauge Compass", comp_m)); mode_m->addEntry(new MenuAction("Gauge Compass", comp_m));
mode_m->addEntry(new MenuAction("Test Mode", testM_m)); mode_m->addEntry(new MenuAction("Test Mode", testM_m));
mode_m->addEntry(new MenuAction("Consol Control", dummy)); mode_m->addEntry(new MenuAction("Consol Control", dummy));
@@ -357,16 +344,16 @@ void lcdWrapperCallback(const char data[][LcdWrapper::totalRows], uint8_t lines,
NetworkAddresses setIPs() NetworkAddresses setIPs()
{ {
NetworkAddresses adresses; NetworkAddresses addresses;
adresses.localIP.fromString(static_cast<const char *>(NetworkConfig::ip)); addresses.localIP.fromString(static_cast<const char *>(NetworkConfig::ip));
adresses.subnet.fromString(static_cast<const char *>(NetworkConfig::subnet)); addresses.subnet.fromString(static_cast<const char *>(NetworkConfig::subnet));
adresses.gateway.fromString(static_cast<const char *>(NetworkConfig::gateway)); addresses.gateway.fromString(static_cast<const char *>(NetworkConfig::gateway));
adresses.dnsServer.fromString(static_cast<const char *>(NetworkConfig::dns)); addresses.dnsServer.fromString(static_cast<const char *>(NetworkConfig::dns));
if (NetworkConfig::mqtt) if (NetworkConfig::mqtt)
{ {
adresses.mqttServer.fromString(static_cast<const char *>(MqttConfig::server)); addresses.mqttServer.fromString(static_cast<const char *>(MqttConfig::server));
adresses.mqttPort = MqttConfig::port; addresses.mqttPort = MqttConfig::port;
} }
return adresses; return addresses;
} }