This commit is contained in:
reto
2022-11-05 16:21:45 +01:00
parent 35037e2397
commit ae8492e348
2 changed files with 880 additions and 0 deletions

866
src/main.cpp Normal file
View File

@ -0,0 +1,866 @@
#include <Arduino.h>
/******************************************************************************
* Dinoi Follower Neuronal Network Version Arduino Mini Pro 5V
*
* Follower Neuronal Network
*
* Arduino NN - An artificial neural network for the Arduino
*
* Based on Neuronal Network from robotics.hobbizine.com/arduinoann.html
******************************************************************************/
#include <math.h>
//*******************************************
// Smart Debug
//*******************************************
// Debugging einschalten, zum ausschalten auskommentieren
#define _SMARTDEBUG
char f[10];
// Debug Makros
#ifdef _SMARTDEBUG
// Hilfsfunktion für WAIT - Makro
void DebugWait(String txt)
{
// buffer leeren
char ch;
while (Serial.available())
ch = Serial.read();
ch = 0;
Serial.print(txt);
Serial.println(" >press 'c' to continue...");
// auf 'c' warten
do
{
if (Serial.available() > 0)
ch = Serial.read();
} while (ch != 'c');
// buffer leeren
while (Serial.available())
ch = Serial.read();
}
#define DEBUG_INIT(speed) Serial.begin(speed)
#define DEBUG_PRINTLN(txt) Serial.println(txt)
#define DEBUG_PRINT(txt) Serial.print(txt)
#define DEBUG_PRINTLN_VALUE(txt, val) \
Serial.print(txt); \
Serial.print(": "); \
dtostrf(val, 6, 3, f); \
Serial.println(f)
#define DEBUG_PRINT_VALUE(txt, val) \
Serial.print(txt); \
Serial.print(": "); \
dtostrf(val, 6, 3, f); \
Serial.print(f)
#define DEBUG_WAIT(txt, condition) \
if (condition) \
DebugWait(txt)
#else
#define DEBUG_INIT(speed)
#define DEBUG_PRINT(txt)
#define DEBUG_PRINTLN(txt)
#define DEBUG_PRINT_VALUE(txt, val)
#define DEBUG_PRINTLN_VALUE(txt, val)
#define DEBUG_WAIT(txt, condition)
#endif
/******************************************************************************
/* Pin Configuration
/******************************************************************************/
#define MDL 4 // Motor Direction Left
#define MSL 5 // Motor Speed Left
#define MSR 6 // Motor Speed Right
#define MDR 7 // Motor Direction Right
int IrLedVr = 3;
int IrLedVl = 2;
int IrLedHr = 10;
int IrLedHl = 9;
int IrRecVr = A3;
int IrRecVl = A2;
int IrRecHr = A0;
int IrRecHl = A1;
const int ledPin = 13; // the number of the LED pin
/* MOTOR DIFFERENCE CONFIG
/******************************************************************************/
#define DIST 65 // Define Minimum Distance
// dino
/*
#define MTRF 220 // Motor Topspeed Right Forward
#define MTRB 220 // Motor Topspeed Right Backward
#define MTLF 187 // Motor Topspeed Left Forward
#define MTLB 189 // Motor Topspeed Left Backward
*/
#define MTRF 230 // Motor Topspeed Right Forward
#define MTLB 220 // Motor Topspeed Left Backward / Forw
#define MTRB 200 // Motor Topspeed Right Backward
#define MTLF 220 // Motor Topspeed Left Forward / Backw
#define minIR 20
#define maxIR 220
// normal
/*
#define MTRF 200 // Motor Topspeed Right Forward
#define MTLB 170 // Motor Topspeed Left Backward / Forw
#define MTRB 200 // Motor Topspeed Right Backward
#define MTLF 170 // Motor Topspeed Left Forward / Backw
#define minIR 0
#define maxIR 220
*/
// Variables
int lspeed = 0; // current speed of left motor
int rspeed = 0; // current speed of right motor
int spause = 1; // wait time if a whisker was touched
bool protsta = false;
bool motsta = true;
/******************************************************************
* Network Configuration - customized per network
******************************************************************/
// Logic
// Sensor -255 to 255
// Motor -255 to 255
// Normal forward => Sensor 150 => Motor 150
// Obstacle => Sensor 80 => 80
const int PatternCount = 6; // The number of training items or rows in the truth table
const int InputNodes = 2; // The number of input neurons
const int OutputNodes = 2; // The number of output neurons
const int HiddenNodes = 5; // The number of hidden neurons
const float LearningRate = 0.3; // The number of Learning Rate
const float Momentum = 0.9; // Adjusts how much the results of the previous iteration affect the current iteration
const float InitialWeightMax = 0.5; // Sets the maximum starting value for weights.
float Success = 0.101; // 0.02 0.01 // Level of minimum Success
// Obsacle Mode with return
//Success = 0.04; // Level of minimum Success
/*
float Input[PatternCount][InputNodes] = {
{1, 1}, // No Obstactle
{0.8, 0.8}, // No Obstactle
{0.4, 1}, // Obstacle on left
{1, 0.4}, // Obstacle on right
{0.3, 0.3}, // Obstacle left and right
{0, 0}, // Obstacle left and right
};
const float Target[PatternCount][OutputNodes] = {
{1, 1}, // No Obstactle
{0.8, 0.8}, // No Obstactle
{0.6, -0.3}, // Obstacle on left
{-0.3, 0.6}, // Obstacle on right
{0.1, 0.1}, // Obstacle left and right
{0, 0}, // Obstacle left and right
};
*/
// Obsacle Mode
//Success = 0.04; // Level of minimum Success
float Input[PatternCount][InputNodes] = {
{ 1, 1 }, // No Obstactle
{ 0.8, 0.8 }, // No Obstactle
{ 0.8, 1 }, // Obstacle on left
{ 1, 0.8 }, // Obstacle on right
{ 0.3, 0.3 }, // Obstacle left and right
{ 0, 0 }, // Obstacle left and right
};
const float Target[PatternCount][OutputNodes] = {
{ 1, 1 }, // No Obstactle
{ 0.8, 0.8 }, // No Obstactle
{ 0.8, 0.3 }, // Obstacle on left
{ 0.3, 0.8 }, // Obstacle on right
{ 0.1, 0.1 }, // Obstacle left and right
{ 0, 0 }, // Obstacle left and right
};
// OK NN
/*
float Input[PatternCount][InputNodes] = {
{1, 1}, // No Obstactle
{0.8, 0.8}, // No Obstactle
{0.5, 1}, // Obstacle on left
{1, 0.5}, // Obstacle on right
{0.3, 0.3}, // Obstacle left and right
{0, 0}, // Obstacle left and right
};
const float Target[PatternCount][OutputNodes] = {
{1, 1}, // No Obstactle
{0.7, 0.7}, // No Obstactle
{0.4, 1}, // Obstacle on left
{1, 0.4}, // Obstacle on right
{0.1, 0.1}, // Obstacle left and right
{0, 0}, // Obstacle left and right
};
*/
// Good NN Agressive
/*
float Input[PatternCount][InputNodes] = {
{ 1, 1 }, // No Obstactle
{ 0.8, 0.8 },// No Obstactle
{ 0.3, 1 }, // Obstacle on left
{ 1, 0.3 }, // Obstacle on right
{ 0.3, 0.3 }, // Obstacle left and right
};
const float Target[PatternCount][OutputNodes] = {
{ 1, 1 }, // No Obstactle
{ 0.7, 0.7 }, // No Obstactle
{ 0, 1 }, // Obstacle on left
{ 1, 0 }, // Obstacle on right
{ 0, 0 }, // Obstacle left and right
};
*/
// last ok
/*
float Input[PatternCount][InputNodes] = {
{ 1, 1 }, // No Obstactle
{ 0.65, 0.65 },// No Obstactle
{ 0.22, 1 }, // Obstacle on left
{ 1, 0.22 }, // Obstacle on right
{ 0.22, 0.22 }, // Obstacle left and right
{ 0.11, 0.11 }, // Obstacle left and right close
};
const float Target[PatternCount][OutputNodes] = {
{ 1, 1 }, // No Obstactle
{ 0.9, 0.9 }, // No Obstactle
{ 1, 0.2 }, // Obstacle on left
{ 0.2, 1 }, // Obstacle on right
{ 0.7, 0.7 }, // Obstacle left and right
{ 0.5, 0.5 }, // Obstacle left and right close
};
*/
/******************************************************************
* Network Variables
******************************************************************/
char mode; //(t => train,c=>check, r => run, a = analyze)
int i, j, p, q, r;
int ReportEvery1000;
int RandomizedIndex[PatternCount];
long TrainingCycle;
float Rando;
float Error;
float Accum;
float Hidden[HiddenNodes];
float Output[OutputNodes];
float HiddenWeights[InputNodes + 1][HiddenNodes];
float OutputWeights[HiddenNodes + 1][OutputNodes];
float HiddenDelta[HiddenNodes];
float OutputDelta[OutputNodes];
float ChangeHiddenWeights[InputNodes + 1][HiddenNodes];
float ChangeOutputWeights[HiddenNodes + 1][OutputNodes];
/******************************************************************************
/* Setup
/******************************************************************************/
void setup()
{
// Neuronal Setup
/******************************************************************************/
randomSeed(analogRead(3));
ReportEvery1000 = 1;
for (p = 0; p < PatternCount; p++)
{
RandomizedIndex[p] = p;
}
delay(200);
mode = 't'; // ( t = train, a = analyze sensors )
// Robo motors Setup
/******************************************************************************/
pinMode(MDL, OUTPUT);
pinMode(MSL, OUTPUT);
pinMode(MSR, OUTPUT);
pinMode(MDR, OUTPUT);
// all IR Leds / Recevier
pinMode(ledPin, OUTPUT);
pinMode(IrLedVr, OUTPUT);
pinMode(IrLedVl, OUTPUT);
pinMode(IrLedHr, OUTPUT);
pinMode(IrLedHl, OUTPUT);
pinMode(IrRecVr, INPUT);
pinMode(IrRecVl, INPUT);
pinMode(IrRecHr, INPUT);
pinMode(IrRecHl, INPUT);
// Serial Debug Interface
DEBUG_INIT(57600);
DEBUG_PRINTLN("Robot Starting with training");
}
/******************************************************************************
/* InputToOutput
/******************************************************************************/
void InputToOutput(float In1, float In2)
{
float TestInput[] = {0, 0};
TestInput[0] = In1;
TestInput[1] = In2;
/******************************************************************
Compute hidden layer activations
******************************************************************/
for (i = 0; i < HiddenNodes; i++)
{
Accum = HiddenWeights[InputNodes][i];
for (j = 0; j < InputNodes; j++)
{
Accum += TestInput[j] * HiddenWeights[j][i];
}
Hidden[i] = 1.0 / (1.0 + exp(-Accum));
}
/******************************************************************
Compute output layer activations and calculate errors
******************************************************************/
for (i = 0; i < OutputNodes; i++)
{
Accum = OutputWeights[HiddenNodes][i];
for (j = 0; j < HiddenNodes; j++)
{
Accum += Hidden[j] * OutputWeights[j][i];
}
Output[i] = 1.0 / (1.0 + exp(-Accum));
}
/* DEBUG_PRINT(" Output Nodes");
for ( i = 0 ; i < OutputNodes ; i++ ) {
DEBUG_PRINT_VALUE(" ",Output[i]);
}
*/
}
/******************************************************************************
* Funktion: irRead (a,b)
* a: Pinnummer des Ir Empfängers
* b: Pinnummer des Ir Senders
* c: modedeb: Space = Normalmodus returns HIGH if > DIST
* d = Distancemodus return Distance 0 to 100 mm
* Retourwert: HIGH = IR-Licht detektiert
* d.h. gemessener Wert unterscheidet sich zum Umgebungslicht
******************************************************************************/
int irRead(int readPin, int triggerPin, char modedeb)
{
boolean zustand;
int umgebungswert = 0;
int irwert = 0;
float uLichtzuIr;
for (int i = 0; i < 10; i++)
{
digitalWrite(triggerPin, LOW);
delay(5);
umgebungswert = umgebungswert + analogRead(readPin);
digitalWrite(triggerPin, HIGH);
delay(5);
irwert = irwert + analogRead(readPin);
}
// Remove Umgebungswert
irwert = irwert - umgebungswert;
// detect obstacle
if (irwert > DIST)
{
zustand = HIGH;
}
else
{
zustand = LOW;
}
// for Debug
if (protsta && zustand || modedeb == 'd')
{
delay(5);
if (modedeb == 'd')
{
//Serial.print(" irwert ");
//Serial.print(irwert);
irwert = map(irwert, minIR, maxIR, 100, 0);
constrain(irwert, 0, 100);
//Serial.print(" dis ");
//Serial.print(irwert);
};
return irwert;
}
else
{
return zustand;
};
}
/******************************************************************************
/* Funktion: Drive
/******************************************************************************/
void drive(int left, int right)
{
int lstate = LOW;
int rstate = LOW;
left = constrain(left, -255, 255);
right = constrain(right, -255, 255);
// invert left
left = left * -1;
// invert right
//right = right * -1;
if (left >= 0)
{
// remap the motor value to the calibrated interval
// speed is alwas handled in the range of [-255..255]
left = map(left, 0, 255, 0, MTLF);
}
else
{
lstate = HIGH;
left = 255 - map(-left, 0, 255, 0, MTLB);
}
if (right >= 0)
{
right = map(right, 0, 255, 0, MTRF);
}
else
{
rstate = HIGH;
right = 255 - map(-right, 0, 255, 0, MTRB);
}
analogWrite(MSL, left);
digitalWrite(MDL, lstate);
analogWrite(MSR, right);
digitalWrite(MDR, rstate);
}
/******************************************************************************
/* Run NN
/******************************************************************************/
void run_nn()
{
delay(30);
// Get IR Values
rspeed = irRead(IrRecVr, IrLedVr, 'd');
lspeed = irRead(IrRecVl, IrLedVl, 'd');
//DEBUG_PRINT_VALUE("R IR",rspeed);
//DEBUG_PRINT_VALUE(" L IR",lspeed);
// Convert IR to float from 0 to 1
float f_rspeed = rspeed;
float f_lspeed = lspeed;
;
f_lspeed = f_lspeed / 100;
f_rspeed = f_rspeed / 100;
DEBUG_PRINT_VALUE(" R IR", f_rspeed * 100);
DEBUG_PRINT_VALUE(" L IR", f_lspeed * 100);
// Ask solution from NN
InputToOutput(f_lspeed, f_rspeed); //INPUT to ANN to obtain OUTPUT
DEBUG_PRINT_VALUE(" NN Out R Mot", Output[1] * 100);
DEBUG_PRINTLN_VALUE(" L Mot", Output[0] * 100);
rspeed = Output[1] * 200;
lspeed = Output[0] * 200;
//DEBUG_PRINT_VALUE(" - Set Speed R MOT",rspeed);
//DEBUG_PRINTLN_VALUE(" L MOT",lspeed);
// Drive Motors
drive(lspeed, rspeed);
}
/******************************************************************************
/* Run NN
/******************************************************************************/
void analyze_sensors()
{
delay(30);
// Get IR Values
rspeed = irRead(IrRecVr, IrLedVr, 'd');
lspeed = irRead(IrRecVl, IrLedVl, 'd');
DEBUG_PRINT_VALUE("R IR", rspeed);
DEBUG_PRINT_VALUE(" L IR", lspeed);
// IR from -100 to +200
// rspeed = constrain(rspeed,-200,200);
// lspeed = constrain(lspeed,-200,200);
// Convert IR to float from 0 to 1
float f_rspeed = rspeed;
float f_lspeed = lspeed;
;
f_lspeed = (200 + f_lspeed) / 400;
f_rspeed = (200 + f_rspeed) / 400;
DEBUG_PRINT_VALUE(" - IN R FL IR", f_rspeed);
DEBUG_PRINTLN_VALUE(" L FL IR", f_lspeed);
}
/******************************************************************************
/* Check NN
/******************************************************************************/
void check_nn()
{
float TestInput[] = {0.9, 0.9};
DEBUG_PRINTLN("");
DEBUG_PRINTLN("Test Run:");
// Test 1
//********
DEBUG_PRINT_VALUE("Test Input: L IR", TestInput[0]);
DEBUG_PRINT_VALUE(" R IR", TestInput[1]);
InputToOutput(TestInput[0], TestInput[1]); //INPUT to ANN to obtain OUTPUT
DEBUG_PRINT_VALUE(" Out L Mot", Output[0]);
DEBUG_PRINTLN_VALUE(" R Mot", Output[1]);
// Test 2
//********
TestInput[0] = 0.4;
TestInput[1] = 0.9;
DEBUG_PRINT_VALUE("Test Input: L IR", TestInput[0]);
DEBUG_PRINT_VALUE(" R IR", TestInput[1]);
InputToOutput(TestInput[0], TestInput[1]); //INPUT to ANN to obtain OUTPUT
DEBUG_PRINT_VALUE(" Out L Mot", Output[0]);
DEBUG_PRINTLN_VALUE(" R Mot", Output[1]);
// Test 2
//********
TestInput[0] = 0.7;
TestInput[1] = 0.3;
DEBUG_PRINT_VALUE("Test Input: L IR", TestInput[0]);
DEBUG_PRINT_VALUE(" R IR", TestInput[1]);
InputToOutput(TestInput[0], TestInput[1]); //INPUT to ANN to obtain OUTPUT
DEBUG_PRINT_VALUE(" Out L Mot", Output[0]);
DEBUG_PRINTLN_VALUE(" R Mot", Output[1]);
// go to run
mode = 'r';
DEBUG_PRINTLN(" ");
DEBUG_PRINTLN("Go to run bot:");
}
void toTerminal()
{
for (p = 0; p < PatternCount; p++)
{
DEBUG_PRINTLN(" ");
DEBUG_PRINT_VALUE(" Training Pattern", p);
DEBUG_PRINT(" Input: ");
for (i = 0; i < InputNodes; i++)
{
DEBUG_PRINT(Input[p][i]);
DEBUG_PRINT(" ");
}
DEBUG_PRINT(" Target: ");
for (i = 0; i < OutputNodes; i++)
{
DEBUG_PRINT(Target[p][i]);
DEBUG_PRINT(" ");
}
/******************************************************************
* Compute hidden layer activations
******************************************************************/
for (i = 0; i < HiddenNodes; i++)
{
Accum = HiddenWeights[InputNodes][i];
for (j = 0; j < InputNodes; j++)
{
Accum += Input[p][j] * HiddenWeights[j][i];
}
Hidden[i] = 1.0 / (1.0 + exp(-Accum));
}
/******************************************************************
* Compute output layer activations and calculate errors
******************************************************************/
for (i = 0; i < OutputNodes; i++)
{
Accum = OutputWeights[HiddenNodes][i];
for (j = 0; j < HiddenNodes; j++)
{
Accum += Hidden[j] * OutputWeights[j][i];
}
Output[i] = 1.0 / (1.0 + exp(-Accum));
}
DEBUG_PRINT(" Output ");
for (i = 0; i < OutputNodes; i++)
{
DEBUG_PRINT(Output[i]);
DEBUG_PRINT(" ");
}
}
}
/******************************************************************************
/* Train NN
/******************************************************************************/
void train_nn()
{
/******************************************************************
* Initialize HiddenWeights and ChangeHiddenWeights
******************************************************************/
for (i = 0; i < HiddenNodes; i++)
{
for (j = 0; j <= InputNodes; j++)
{
ChangeHiddenWeights[j][i] = 0.0;
Rando = float(random(100)) / 100;
HiddenWeights[j][i] = 2.0 * (Rando - 0.5) * InitialWeightMax;
}
}
/******************************************************************
* Initialize OutputWeights and ChangeOutputWeights
******************************************************************/
for (i = 0; i < OutputNodes; i++)
{
for (j = 0; j <= HiddenNodes; j++)
{
ChangeOutputWeights[j][i] = 0.0;
Rando = float(random(100)) / 100;
OutputWeights[j][i] = 2.0 * (Rando - 0.5) * InitialWeightMax;
}
}
DEBUG_PRINTLN("Initial/Untrained Outputs: ");
toTerminal();
/******************************************************************
* Begin training
******************************************************************/
for (TrainingCycle = 1; TrainingCycle < 2147483647; TrainingCycle++)
{
/******************************************************************
* Randomize order of training patterns
******************************************************************/
for (p = 0; p < PatternCount; p++)
{
q = random(PatternCount);
r = RandomizedIndex[p];
RandomizedIndex[p] = RandomizedIndex[q];
RandomizedIndex[q] = r;
}
Error = 0.0;
/******************************************************************
* Cycle through each training pattern in the randomized order
******************************************************************/
for (q = 0; q < PatternCount; q++)
{
p = RandomizedIndex[q];
/******************************************************************
* Compute hidden layer activations
******************************************************************/
for (i = 0; i < HiddenNodes; i++)
{
Accum = HiddenWeights[InputNodes][i];
for (j = 0; j < InputNodes; j++)
{
Accum += Input[p][j] * HiddenWeights[j][i];
}
Hidden[i] = 1.0 / (1.0 + exp(-Accum));
}
/******************************************************************
* Compute output layer activations and calculate errors
******************************************************************/
for (i = 0; i < OutputNodes; i++)
{
Accum = OutputWeights[HiddenNodes][i];
for (j = 0; j < HiddenNodes; j++)
{
Accum += Hidden[j] * OutputWeights[j][i];
}
Output[i] = 1.0 / (1.0 + exp(-Accum));
OutputDelta[i] = (Target[p][i] - Output[i]) * Output[i] * (1.0 - Output[i]);
Error += 0.5 * (Target[p][i] - Output[i]) * (Target[p][i] - Output[i]);
}
/******************************************************************
* Backpropagate errors to hidden layer
******************************************************************/
for (i = 0; i < HiddenNodes; i++)
{
Accum = 0.0;
for (j = 0; j < OutputNodes; j++)
{
Accum += OutputWeights[i][j] * OutputDelta[j];
}
HiddenDelta[i] = Accum * Hidden[i] * (1.0 - Hidden[i]);
}
/******************************************************************
* Update Inner-->Hidden Weights
******************************************************************/
for (i = 0; i < HiddenNodes; i++)
{
ChangeHiddenWeights[InputNodes][i] = LearningRate * HiddenDelta[i] + Momentum * ChangeHiddenWeights[InputNodes][i];
HiddenWeights[InputNodes][i] += ChangeHiddenWeights[InputNodes][i];
for (j = 0; j < InputNodes; j++)
{
ChangeHiddenWeights[j][i] = LearningRate * Input[p][j] * HiddenDelta[i] + Momentum * ChangeHiddenWeights[j][i];
HiddenWeights[j][i] += ChangeHiddenWeights[j][i];
}
}
/******************************************************************
* Update Hidden-->Output Weights
******************************************************************/
for (i = 0; i < OutputNodes; i++)
{
ChangeOutputWeights[HiddenNodes][i] = LearningRate * OutputDelta[i] + Momentum * ChangeOutputWeights[HiddenNodes][i];
OutputWeights[HiddenNodes][i] += ChangeOutputWeights[HiddenNodes][i];
for (j = 0; j < HiddenNodes; j++)
{
ChangeOutputWeights[j][i] = LearningRate * Hidden[j] * OutputDelta[i] + Momentum * ChangeOutputWeights[j][i];
OutputWeights[j][i] += ChangeOutputWeights[j][i];
}
}
}
/******************************************************************
* Every 1000 cycles send data to terminal for display
******************************************************************/
ReportEvery1000 = ReportEvery1000 - 1;
if (ReportEvery1000 == 0)
{
// Blink Led for State Info
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
DEBUG_PRINTLN("");
DEBUG_PRINTLN("");
DEBUG_PRINT_VALUE(" TrainingCycle", TrainingCycle);
DEBUG_PRINT_VALUE(" Error Level", Error);
toTerminal();
if (TrainingCycle == 1)
{
ReportEvery1000 = 999;
}
else
{
ReportEvery1000 = 1000;
}
}
/******************************************************************
* If error rate is less than pre-determined threshold then end
******************************************************************/
if (Error < Success)
break;
}
DEBUG_PRINTLN("");
DEBUG_PRINT_VALUE(" TrainingCycle: ", TrainingCycle);
DEBUG_PRINT_VALUE(" Error Level", Error);
toTerminal();
DEBUG_PRINTLN("");
DEBUG_PRINTLN("");
DEBUG_PRINT("Training Set Solved!");
DEBUG_PRINT_VALUE("TrainingCycle: ", TrainingCycle);
DEBUG_PRINTLN_VALUE(" Error Level", Error);
DEBUG_PRINTLN("");
ReportEvery1000 = 1;
// done=> set mode to run
mode = 'c';
}
/******************************************************************************
/* Loop
/******************************************************************************/
void loop()
{
// Train NN
/******************************************************************************/
if (mode == 't')
{
train_nn();
}
// Check NN
/******************************************************************************/
if (mode == 'c')
{
check_nn();
}
// Run NN
/******************************************************************************/
if (mode == 'r')
{
run_nn();
}
// Analyze Sensors
/******************************************************************************/
if (mode == 'a')
{
analyze_sensors();
}
}

14
test/README Normal file
View File

@ -0,0 +1,14 @@
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html
1
22