2022-03-28 17:52:20 +00:00
# include <Arduino.h>
2022-03-28 19:50:00 +00:00
# define SERIAL_BAUD 115200 // [-] Baud rate for built-in Serial (used for the Serial Monitor)
2022-05-22 19:02:18 +00:00
unsigned long loopmillis ;
unsigned long last_loopmillis ;
2022-06-19 13:20:49 +00:00
# include <TimeLib.h> //for teensy rtc
time_t getTeensy3Time ( ) ;
2022-05-22 11:47:05 +00:00
# include <OneButton.h>
2022-04-10 16:36:19 +00:00
# include <SPI.h>
# include <Wire.h>
# include <Adafruit_GFX.h>
# include <Adafruit_SSD1306.h>
//128 x 64 px
# define SCREEN_WIDTH 128
# define SCREEN_HEIGHT 64
# define SCREEN_ADDRESS 0x3C
# define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display ( SCREEN_WIDTH , SCREEN_HEIGHT , & Wire , OLED_RESET ) ;
# define DISPLAYUPDATE_INTERVAL 200
2022-05-22 11:47:05 +00:00
bool flag_updatedisplay = false ;
uint8_t displaymode = 0 ;
# define DISPLAY_STATS 0
# define DISPLAY_STATS2 1
# define DISPLAY_STATS3 2
# define DISPLAY_MENU 3
uint8_t menu_entrypos = 0 ;
2022-05-22 19:02:18 +00:00
# define MENU_ENTRIES 8 // max id is MENU_ENTRIES-1
2022-04-10 16:36:19 +00:00
2022-03-28 19:50:00 +00:00
uint8_t error = 0 ;
# define IMU_NO_CHANGE 2 //IMU values did not change for too long
2022-03-28 17:52:20 +00:00
2022-03-28 19:03:36 +00:00
# include "hoverboard-esc-serial-comm.h"
2022-03-28 18:11:31 +00:00
2022-03-28 19:03:36 +00:00
ESCSerialComm esc ( Serial2 ) ;
2022-03-28 19:50:00 +00:00
//Serial1 = TX1=1, RX1=0
//Serial2 = TX2=10, RX2=9
//Serial3 = TX3=8, RX3=7
2022-05-22 11:47:05 +00:00
# define PIN_BUTTON_UP 3
# define PIN_BUTTON_INC 4
# define PIN_BUTTON_DEC 5
# define PIN_BUTTON_DOWN 6
OneButton btn_up = OneButton ( PIN_BUTTON_UP , true , true ) ; // Input pin for the button, Button is active LOW, Enable internal pull-up resistor
OneButton btn_inc = OneButton ( PIN_BUTTON_INC , true , true ) ;
OneButton btn_dec = OneButton ( PIN_BUTTON_DEC , true , true ) ;
OneButton btn_down = OneButton ( PIN_BUTTON_DOWN , true , true ) ;
//flags
bool button_up_click = false ;
bool button_inc_click = false ;
bool button_dec_click = false ;
bool button_down_click = false ;
2022-03-28 19:50:00 +00:00
# define PIN_GAMETRAK_LENGTH_A A6 //A6=20
# define PIN_GAMETRAK_LENGTH_B A7 //A7=21
# define PIN_GAMETRAK_VERTICAL A8 //A8=22
# define PIN_GAMETRAK_HORIZONTAL A9 //A9=23
2022-06-19 18:07:18 +00:00
# define SPEED_COEFFICIENT_NRF 1 // higher value == stronger
# define STEER_COEFFICIENT_NRF 0.5 // higher value == stronger
2022-05-22 11:47:05 +00:00
2022-06-19 18:07:18 +00:00
# define SPEED_COEFFICIENT_GT 1 // higher value == stronger
# define STEER_COEFFICIENT_GT 0.5 // higher value == stronger
unsigned long watchdogtimer = 0 ; //set to current millis everytime new good control input is calculated
2022-05-22 11:47:05 +00:00
2022-03-28 19:50:00 +00:00
long last_adcupdated = 0 ;
# define ADC_UPDATEPERIOD 10 //in ms
# define CONTROLUPDATEPERIOD 10
long last_controlupdate = 0 ;
2022-05-22 16:47:03 +00:00
float filter_nrf_set_speed = 0.02 ; //higher value, faster response. depends on CONTROLUPDATEPERIOD
float filter_nrf_set_steer = 0.06 ;
2022-03-28 19:50:00 +00:00
2022-06-19 18:07:18 +00:00
float filter_stop_set_speed = 0.015 ; //safety stop
float filter_stop_set_steer = 0.06 ; //safety stop
2022-04-10 16:36:19 +00:00
# define GT_LENGTH_MIN 200 //minimum length for stuff to start happen
# define GT_LENGTH_1_OFFSET -22.5
# define GT_LENGTH_1_SCALE 2.5
# define GT_LENGTH_2_OFFSET 563.6
# define GT_LENGTH_2_SCALE 0.45
# define GT_LENGTH_CROSSOVERADC ((GT_LENGTH_2_OFFSET-GT_LENGTH_1_OFFSET) / (GT_LENGTH_1_SCALE-GT_LENGTH_2_SCALE)) //crossover point from adc, where first and second lines cross
# define GT_LENGTH_CROSSOVER_FEATHER 76.0 //how much adc change in both directions should be smoothed when switching between first and second line
# define GT_LENGTH_MAXLENGTH 2000 //maximum length in [mm]. maximum string length is around 2m80
# define GT_LENGTH_ADC_MAXDIFF 127 //maximum adc value difference between A and B poti. Used to detect scratching poti. during length calibration was 57
int raw_length_maxdiff = 0 ;
//TODO: implement error for poti maxdiff
2022-03-28 19:50:00 +00:00
uint16_t gt_length = 0 ; //0=rolled up, 1unit = 1mm
2022-04-10 16:36:19 +00:00
/* calibration 20220410
lenght [ mm ] , adc
0 , 9
100 , 52
200 , 86
300 , 124
400 , 165
500 , 212
600 , 286
700 , 376
800 , 520
900 , 746
1000 , 984
1100 , 1198
1200 , 1404
1300 , 1628
1400 , 1853
1500 , 2107
1600 , 2316
1700 , 2538
1800 , 2730
1900 , 2942
2000 , 3150
*/
2022-03-28 19:50:00 +00:00
# define GT_VERTICAL_CENTER 2048 //adc value for center position
# define GT_VERTICAL_RANGE 2047 //adc value difference from center to maximum (30 deg)
int8_t gt_vertical = 0 ; //0=center. joystick can rotate +-30 degrees. -127 = -30 deg
//left = -30 deg, right= 30deg
# define GT_HORIZONTAL_CENTER 2048 //adc value for center position
# define GT_HORIZONTAL_RANGE 2047 //adc value difference from center to maximum (30 deg)
int8_t gt_horizontal = 0 ; //0=center
uint16_t gt_length_set = 1000 ; //set length to keep [mm]
# define GT_LENGTH_MINDIFF 10 //[mm] threshold, do not move within gt_length_set-GT_LENGTH_MINDIFF and gt_length_set+GT_LENGTH_MINDIFF
float gt_speed_p = 0.7 ; //value to multipy difference [mm] with -> out_speed
float gt_speedbackward_p = 0.7 ;
float gt_steer_p = 2.0 ;
2022-05-22 16:47:03 +00:00
int16_t gt_speed_limit = 500 ; //maximum out_speed value +
2022-05-22 14:44:52 +00:00
int16_t gt_backward_speed_limit = 100 ; //maximum out_speed value (for backward driving) -
int16_t gt_steer_limit = 300 ; //maximum out_steer value +-
2022-04-20 18:49:27 +00:00
# define GT_LENGTH_MAXIMUMDIFFBACKWARD -250 //[mm]. if gt_length_set=1000 and GT_LENGTH_MAXIMUMDIFFBACKWARD=-200 then only drives backward if lenght is greater 800
2022-03-28 19:50:00 +00:00
# include <SPI.h>
# include "nRF24L01.h"
# include "RF24.h"
RF24 radio ( 14 , 15 ) ; //ce, cs
//SCK D13 (Pro mini), A5 (bluepill),13 (teensy32)
//Miso D12 (Pro mini), A6 (bluepill),12 (teensy32)
//Mosi D11 (Pro mini), A7 (bluepill),11 (teensy32)
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes [ 2 ] = { 0xF0F0F0F0E1LL , 0xF0F0F0F0D2LL } ;
# define NRF24CHANNEL 75
struct nrfdata {
uint8_t steer ;
uint8_t speed ;
uint8_t commands ; //bit 0 set = motor enable
uint8_t checksum ;
} ;
nrfdata lastnrfdata ;
long last_nrfreceive = 0 ; //last time values were received and checksum ok
2022-04-10 16:36:19 +00:00
unsigned long nrf_delay = 0 ;
unsigned long last_nrfreceive_delay = 0 ;
2022-06-19 18:10:31 +00:00
unsigned long max_last_nrfreceive_delay = 0 ; //maximum value (used for display)
2022-03-28 19:50:00 +00:00
# define MAX_NRFDELAY 100 //ms. maximum time delay at which vehicle will disarm
boolean radiosendOk = false ;
//command variables
boolean motorenabled = false ; //set by nrfdata.commands
long last_send = 0 ;
int16_t set_speed = 0 ;
int16_t set_steer = 0 ;
# define NRFDATA_CENTER 127
//boolean armed = false;
boolean lastpacketOK = false ;
//Gametrak
//boolean armed_gt = false;
uint8_t controlmode = 0 ;
# define MODE_DISARMED 0
# define MODE_RADIONRF 1
# define MODE_GAMETRAK 2
2022-03-28 18:11:31 +00:00
2022-06-19 13:07:40 +00:00
// SD Logging
# include <SPI.h> //SCK=13, MISO=12, MOSI=11
# include <SD.h> //Format sd cart with FAT or FAT16
# define SDCHIPSELECT 16
boolean datalogging = true ;
2022-06-19 17:41:19 +00:00
String datalogging_filename = " UNKNOWN.txt " ;
2022-06-19 13:07:40 +00:00
2022-05-22 11:47:05 +00:00
void updateInputs ( unsigned long loopmillis ) ;
2022-04-10 16:36:19 +00:00
void updateDisplay ( unsigned long loopmillis ) ;
2022-05-22 11:47:05 +00:00
void display_show_stats ( ) ;
void display_show_stats2 ( ) ;
void display_show_stats3 ( ) ;
void display_show_menu ( ) ;
2022-06-19 13:20:49 +00:00
time_t getTeensy3Time ( ) ;
2022-06-19 17:41:19 +00:00
String addLeadingZero ( int number ) ;
String getCurrentDatestring ( ) ;
2022-04-10 16:36:19 +00:00
2022-03-28 17:52:20 +00:00
void setup ( ) {
2022-03-28 19:50:00 +00:00
Serial . begin ( SERIAL_BAUD ) ; //Debug and Program
2022-06-19 13:07:40 +00:00
2022-06-19 13:20:49 +00:00
Wire . begin ( ) ;
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if ( ! display . begin ( SSD1306_SWITCHCAPVCC , SCREEN_ADDRESS ) ) {
Serial . println ( F ( " SSD1306 allocation failed " ) ) ;
for ( ; ; ) ; // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display . display ( ) ;
display . clearDisplay ( ) ;
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE ) ;
display . setCursor ( 0 , 0 ) ;
display . println ( F ( " Init. ESC " ) ) ;
display . display ( ) ; // Show initial text
2022-03-28 19:50:00 +00:00
esc . init ( ) ;
2022-06-19 13:07:40 +00:00
2022-06-19 13:20:49 +00:00
display . print ( F ( " Init. SD.. " ) ) ; display . display ( ) ;
2022-06-19 13:07:40 +00:00
Serial . print ( " Initializing SD card... " ) ;
// see if the card is present and can be initialized:
if ( ! SD . begin ( SDCHIPSELECT ) ) {
Serial . println ( " Card failed, or not present " ) ;
2022-06-19 13:20:49 +00:00
display . print ( F ( " Fail! " ) ) ; display . display ( ) ;
2022-06-19 13:07:40 +00:00
datalogging = false ; //disable logging
2022-06-19 13:20:49 +00:00
delay ( 1000 ) ;
2022-06-19 13:07:40 +00:00
} else {
Serial . println ( " Card initialized. " ) ;
2022-06-19 13:20:49 +00:00
display . print ( F ( " OK " ) ) ; display . display ( ) ;
2022-06-19 17:41:19 +00:00
if ( datalogging ) {
int filenumber = 0 ;
char buffer [ 6 ] ;
sprintf ( buffer , " %04d " , filenumber ) ;
datalogging_filename = " LOG_ " + String ( buffer ) + " .TXT " ;
while ( SD . exists ( datalogging_filename ) & & filenumber < 10000 ) {
Serial . print ( datalogging_filename ) ; Serial . println ( " exists " ) ;
filenumber + + ;
sprintf ( buffer , " %04d " , filenumber ) ;
datalogging_filename = " LOG_ " + String ( buffer ) + " .TXT " ;
}
Serial . print ( datalogging_filename ) ; Serial . println ( " is free " ) ;
}
2022-06-19 13:07:40 +00:00
}
2022-04-10 16:36:19 +00:00
analogReadResolution ( 12 ) ;
pinMode ( PIN_GAMETRAK_LENGTH_A , INPUT_PULLUP ) ;
pinMode ( PIN_GAMETRAK_LENGTH_B , INPUT_PULLUP ) ;
pinMode ( PIN_GAMETRAK_VERTICAL , INPUT_PULLUP ) ;
pinMode ( PIN_GAMETRAK_HORIZONTAL , INPUT_PULLUP ) ;
2022-03-28 19:50:00 +00:00
2022-05-22 11:47:05 +00:00
btn_up . attachClick ( [ ] ( ) {
button_up_click = true ;
} ) ;
btn_down . attachClick ( [ ] ( ) {
button_down_click = true ;
} ) ;
btn_inc . attachClick ( [ ] ( ) {
button_inc_click = true ;
} ) ;
btn_dec . attachClick ( [ ] ( ) {
button_dec_click = true ;
} ) ;
2022-04-10 16:36:19 +00:00
2022-06-19 13:20:49 +00:00
display . print ( F ( " Init. RTC.. " ) ) ; display . display ( ) ;
2022-04-10 16:36:19 +00:00
2022-06-19 13:20:49 +00:00
setSyncProvider ( getTeensy3Time ) ; //See https://www.pjrc.com/teensy/td_libs_Time.html#teensy3
if ( timeStatus ( ) ! = timeSet ) {
Serial . println ( " Unable to sync with the RTC " ) ;
display . println ( F ( " Fail " ) ) ; display . display ( ) ;
delay ( 1000 ) ;
} else {
Serial . println ( " RTC has set the system time " ) ;
display . println ( F ( " OK " ) ) ; display . display ( ) ;
2022-06-19 17:41:19 +00:00
2022-06-19 13:20:49 +00:00
}
2022-03-28 19:50:00 +00:00
2022-06-19 13:20:49 +00:00
display . println ( F ( " Init. NRF24 " ) ) ; display . display ( ) ;
2022-03-28 19:50:00 +00:00
radio . begin ( ) ;
2022-04-10 16:36:19 +00:00
Serial . println ( " RF24 set rate " ) ;
2022-06-19 13:20:49 +00:00
if ( ! radio . setDataRate ( RF24_250KBPS ) ) { //set to slow data rate. default was 1MBPS
display . println ( F ( " Fail Data Rate! " ) ) ; display . display ( ) ;
}
2022-03-28 19:50:00 +00:00
//radio.setDataRate( RF24_1MBPS );
2022-04-10 16:36:19 +00:00
//Serial.println("set channel");
2022-03-28 19:50:00 +00:00
radio . setChannel ( NRF24CHANNEL ) ; //0 to 124 (inclusive)
2022-04-10 16:36:19 +00:00
//Serial.println("set retries and payload");
2022-03-28 19:50:00 +00:00
radio . setRetries ( 15 , 15 ) ; // optionally, increase the delay between retries & # of retries
radio . setPayloadSize ( 8 ) ; // optionally, reduce the payload size. seems to improve reliability
2022-04-10 16:36:19 +00:00
//Serial.println("open pipe");
2022-03-28 19:50:00 +00:00
radio . openWritingPipe ( pipes [ 0 ] ) ; //write on pipe 0
radio . openReadingPipe ( 1 , pipes [ 1 ] ) ; //read on pipe 1
2022-04-10 16:36:19 +00:00
Serial . println ( " start listening " ) ;
2022-03-28 19:50:00 +00:00
radio . startListening ( ) ;
2022-04-10 16:36:19 +00:00
2022-06-19 13:20:49 +00:00
display . println ( F ( " Finished " ) ) ;
2022-04-10 16:36:19 +00:00
display . display ( ) ; // Show initial text
2022-06-19 13:20:49 +00:00
2022-03-28 19:50:00 +00:00
2022-03-28 17:52:20 +00:00
}
2022-03-28 18:11:31 +00:00
2022-03-28 17:52:20 +00:00
void loop ( ) {
2022-05-22 19:02:18 +00:00
last_loopmillis = loopmillis ;
loopmillis = millis ( ) ;
2022-03-28 19:50:00 +00:00
2022-05-22 11:47:05 +00:00
btn_up . tick ( ) ;
btn_inc . tick ( ) ;
btn_dec . tick ( ) ;
btn_down . tick ( ) ;
2022-03-28 19:50:00 +00:00
2022-05-22 19:02:18 +00:00
2022-04-10 16:36:19 +00:00
if ( loopmillis - last_adcupdated > ADC_UPDATEPERIOD ) { //update analog readings
2022-05-22 19:02:18 +00:00
2022-03-28 19:50:00 +00:00
2022-04-10 16:36:19 +00:00
int raw_length_a = analogRead ( PIN_GAMETRAK_LENGTH_A ) ;
int raw_length_b = analogRead ( PIN_GAMETRAK_LENGTH_B ) ;
raw_length_maxdiff = max ( raw_length_maxdiff , abs ( raw_length_a - raw_length_b ) ) ;
int raw_length = ( raw_length_a + raw_length_b ) / 2 ;
uint16_t gt_length_1 = GT_LENGTH_1_OFFSET + raw_length * GT_LENGTH_1_SCALE ;
uint16_t gt_length_2 = GT_LENGTH_2_OFFSET + raw_length * GT_LENGTH_2_SCALE ;
double crossovermapping = constrain ( ( ( raw_length - GT_LENGTH_CROSSOVERADC ) / GT_LENGTH_CROSSOVER_FEATHER ) / 2.0 + 0.5 , 0.0 , 1.0 ) ; //0 for first, 1 for second
gt_length = constrain ( gt_length_1 * ( 1 - crossovermapping ) + gt_length_2 * crossovermapping , 0 , GT_LENGTH_MAXLENGTH ) ;
2022-03-28 19:50:00 +00:00
if ( gt_length < = GT_LENGTH_MIN ) {
gt_length = 0 ; //if below minimum measurable length set to 0mm
}
2022-04-10 16:36:19 +00:00
gt_vertical = constrain ( map ( analogRead ( PIN_GAMETRAK_VERTICAL ) - ( ( int16_t ) GT_VERTICAL_CENTER ) , - GT_VERTICAL_RANGE , + GT_VERTICAL_RANGE , - 127 , 127 ) , - 127 , 127 ) ; //left negative
gt_horizontal = constrain ( map ( analogRead ( PIN_GAMETRAK_HORIZONTAL ) - ( ( int16_t ) GT_HORIZONTAL_CENTER ) , - GT_HORIZONTAL_RANGE , + GT_HORIZONTAL_RANGE , - 127 , 127 ) , - 127 , 127 ) ; //down negative
2022-03-28 19:50:00 +00:00
last_adcupdated = millis ( ) ;
/*
2022-04-10 16:36:19 +00:00
Serial . print ( " gt_length= " ) ;
Serial . print ( gt_length ) ;
Serial . print ( " , gt_vertical= " ) ;
Serial . print ( gt_vertical ) ;
Serial . print ( " , gt_horizontal= " ) ;
Serial . print ( gt_horizontal ) ;
2022-03-28 19:50:00 +00:00
2022-04-10 16:36:19 +00:00
Serial . print ( " pl= " ) ;
Serial . print ( raw_length_a ) ;
Serial . print ( " , " ) ;
Serial . print ( raw_length_b ) ;
Serial . print ( " , pv= " ) ;
Serial . print ( analogRead ( PIN_GAMETRAK_VERTICAL ) ) ;
Serial . print ( " , ph= " ) ;
Serial . print ( analogRead ( PIN_GAMETRAK_HORIZONTAL ) ) ;
Serial . print ( " Ldiff= " ) ;
Serial . println ( abs ( raw_length_a - raw_length_b ) ) ;
*/
/*
static int _rawlengtharray [ 40 ] ;
static int _rawlapos = 0 ;
_rawlengtharray [ _rawlapos + + ] = raw_length ;
_rawlapos % = 40 ;
int rawlengthfilter = 0 ;
for ( int p = 0 ; p < 40 ; p + + ) {
rawlengthfilter + = _rawlengtharray [ p ] ;
}
rawlengthfilter / = 40 ;
static int maxldiff = 0 ;
maxldiff = max ( maxldiff , abs ( raw_length_a - raw_length_b ) ) ;
Serial . print ( " " ) ;
Serial . print ( rawlengthfilter ) ;
Serial . print ( " maxldiff= " ) ;
Serial . println ( maxldiff ) ; */
2022-03-28 19:50:00 +00:00
}
//NRF24
2022-04-10 16:36:19 +00:00
nrf_delay = loopmillis - last_nrfreceive ; //update nrf delay
2022-03-28 19:50:00 +00:00
if ( radio . available ( ) )
{
2022-04-10 16:36:19 +00:00
//Serial.println("radio available ...");
2022-03-28 19:50:00 +00:00
lastpacketOK = false ; //initialize with false, if checksum ok gets set to true
//digitalWrite(PIN_LED, !digitalRead(PIN_LED));
radio . read ( & lastnrfdata , sizeof ( nrfdata ) ) ;
if ( lastnrfdata . speed = = NRFDATA_CENTER & & lastnrfdata . steer = = NRFDATA_CENTER ) { //arm only when centered
controlmode = MODE_RADIONRF ; //set radionrf mode at first received packet
}
uint8_t calcchecksum = ( uint8_t ) ( ( lastnrfdata . steer + 3 ) * ( lastnrfdata . speed + 13 ) ) ;
if ( lastnrfdata . checksum = = calcchecksum ) { //checksum ok?
lastpacketOK = true ;
2022-04-10 16:36:19 +00:00
last_nrfreceive_delay = loopmillis - last_nrfreceive ; //for display purpose
2022-06-19 18:10:31 +00:00
max_last_nrfreceive_delay = max ( last_nrfreceive_delay , max_last_nrfreceive_delay ) ;
2022-04-10 16:36:19 +00:00
last_nrfreceive = loopmillis ;
2022-06-19 18:07:18 +00:00
watchdogtimer = loopmillis ; //reset watchdog
2022-03-28 19:50:00 +00:00
//parse commands
2022-06-19 18:07:18 +00:00
motorenabled = ( lastnrfdata . commands & ( 1 < < 0 ) ) > > 0 ; //check bit 0 . Used for safety-off when remote released
2022-03-28 19:50:00 +00:00
}
}
if ( controlmode = = MODE_RADIONRF & & nrf_delay > = MAX_NRFDELAY ) { //too long since last sucessful nrf receive
controlmode = MODE_DISARMED ;
# ifdef DEBUG
2022-04-10 16:36:19 +00:00
Serial . println ( " nrf_delay>=MAX_NRFDELAY, disarmed! " ) ;
2022-03-28 19:50:00 +00:00
# endif
}
if ( controlmode = = MODE_RADIONRF ) { //is armed in nrf mode
if ( lastpacketOK ) { //if lastnrfdata is valid
2022-04-10 16:36:19 +00:00
if ( loopmillis - last_controlupdate > CONTROLUPDATEPERIOD ) {
last_controlupdate = loopmillis ;
2022-03-28 19:50:00 +00:00
//out_speed=(int16_t)( (lastnrfdata.y-TRACKPOINT_CENTER)*1000/TRACKPOINT_MAX );
//out_steer=(int16_t)( -(lastnrfdata.x-TRACKPOINT_CENTER)*1000/TRACKPOINT_MAX );
2022-04-20 18:49:27 +00:00
int16_t new_set_speed = ( int16_t ) ( ( ( int16_t ) ( lastnrfdata . speed ) - NRFDATA_CENTER ) * 1000 / 127 ) ; //-1000 to 1000
int16_t new_set_steer = ( int16_t ) ( ( ( int16_t ) ( lastnrfdata . steer ) - NRFDATA_CENTER ) * 1000 / 127 ) ;
2022-03-28 19:50:00 +00:00
2022-04-20 18:49:27 +00:00
2022-05-22 11:47:05 +00:00
set_speed = set_speed * ( 1.0 - filter_nrf_set_speed ) + new_set_speed * filter_nrf_set_speed ; //simple Filter
set_steer = set_steer * ( 1.0 - filter_nrf_set_steer ) + new_set_steer * filter_nrf_set_steer ;
2022-03-28 19:50:00 +00:00
//calculate speed l and r from speed and steer
2022-06-19 18:07:18 +00:00
2022-03-28 19:50:00 +00:00
int16_t _out_speedl , _out_speedr ;
_out_speedl = constrain ( set_speed * SPEED_COEFFICIENT_NRF + set_steer * STEER_COEFFICIENT_NRF , - 1500 , 1500 ) ;
_out_speedr = constrain ( set_speed * SPEED_COEFFICIENT_NRF - set_steer * STEER_COEFFICIENT_NRF , - 1500 , 1500 ) ;
esc . setSpeed ( _out_speedl , _out_speedr ) ;
}
} //if pastpacket not ok, keep last out_steer and speed values until disarmed
# ifdef DEBUG
if ( ! lastpacketOK ) {
2022-04-10 16:36:19 +00:00
Serial . println ( " Armed but packet not ok " ) ;
2022-03-28 19:50:00 +00:00
}
# endif
}
if ( controlmode = = MODE_DISARMED ) { //check if gametrak can be armed
if ( gt_length > gt_length_set & & gt_length < gt_length_set + 10 ) { //is in trackable length
controlmode = MODE_GAMETRAK ; //enable gametrak mode
2022-04-10 16:36:19 +00:00
Serial . println ( " Enable Gametrak " ) ;
2022-03-28 19:50:00 +00:00
}
} else if ( controlmode = = MODE_GAMETRAK ) { //gametrak control active and not remote active
//Gametrak Control Code
motorenabled = true ;
2022-06-19 18:07:18 +00:00
watchdogtimer = loopmillis ; //reset watchdog
2022-03-28 19:50:00 +00:00
if ( gt_length < = GT_LENGTH_MIN ) { //let go
2022-04-12 14:28:51 +00:00
//Serial.println("gametrak released");
2022-03-28 19:50:00 +00:00
controlmode = MODE_DISARMED ;
motorenabled = false ;
}
int16_t _gt_length_diff = gt_length - gt_length_set ; //positive if needs to drive forward
2022-04-10 16:36:19 +00:00
if ( ( _gt_length_diff > - GT_LENGTH_MINDIFF ) & & ( _gt_length_diff < GT_LENGTH_MINDIFF ) ) { //minimum difference to drive
2022-03-28 19:50:00 +00:00
_gt_length_diff = 0 ; //threshold
}
2022-05-22 14:44:52 +00:00
set_steer = constrain ( ( int16_t ) ( - gt_horizontal * gt_steer_p ) , - gt_steer_limit , gt_steer_limit ) ; //steer positive is left //gt_horizontal left is negative
2022-03-28 19:50:00 +00:00
if ( _gt_length_diff > 0 ) { //needs to drive forward
2022-05-22 14:44:52 +00:00
set_speed = constrain ( ( int16_t ) ( _gt_length_diff * gt_speed_p ) , 0 , gt_speed_limit ) ;
2022-03-28 19:50:00 +00:00
} else { //drive backward
if ( _gt_length_diff > GT_LENGTH_MAXIMUMDIFFBACKWARD ) { //only drive if not pulled back too much
2022-05-22 14:44:52 +00:00
set_speed = constrain ( ( int16_t ) ( _gt_length_diff * gt_speedbackward_p ) , - gt_backward_speed_limit , 0 ) ;
2022-03-28 19:50:00 +00:00
} else {
set_speed = 0 ; //stop
set_steer = 0 ;
}
}
2022-04-12 14:28:51 +00:00
static float safetymultiplier = 1.0 ; //value to reduce output speed if gametrack is pointing too far down or up (string might be behind vehicle)
# define GT_SAFETY_THRESHOLD_H 120 //above which value (abs) safety slowdown should start
# define GT_SAFETY_THRESHOLD_V 120
# define SAFETYMULTIPLIER_UPDATE_INTERVAL 100
# define SAFETYMULTIPLIER_CHANGE_TIME_DOWN 2.0 //Time how long it should take to go from 100% to 0% when in safety slowdown
# define SAFETYMULTIPLIER_CHANGE_TIME_UP 1.0
static unsigned long last_safetymultiplier_update = 0 ;
2022-03-28 19:50:00 +00:00
2022-04-12 14:28:51 +00:00
if ( loopmillis - last_safetymultiplier_update > SAFETYMULTIPLIER_UPDATE_INTERVAL ) {
if ( abs ( gt_vertical ) > GT_SAFETY_THRESHOLD_V | | abs ( gt_horizontal ) > GT_SAFETY_THRESHOLD_H ) {
safetymultiplier - = 1.0 / ( 1000.0 / SAFETYMULTIPLIER_UPDATE_INTERVAL ) / SAFETYMULTIPLIER_CHANGE_TIME_DOWN ;
} else {
safetymultiplier + = 1.0 / ( 1000.0 / SAFETYMULTIPLIER_UPDATE_INTERVAL ) / SAFETYMULTIPLIER_CHANGE_TIME_UP ;
}
safetymultiplier = constrain ( safetymultiplier , 0.0 , 1.0 ) ;
last_safetymultiplier_update = loopmillis ;
}
2022-03-28 19:50:00 +00:00
//calculate speed l and r from speed and steer
2022-06-19 18:07:18 +00:00
if ( loopmillis - last_controlupdate > CONTROLUPDATEPERIOD ) {
last_controlupdate = loopmillis ;
int16_t _out_speedl , _out_speedr ;
_out_speedl = constrain ( set_speed * SPEED_COEFFICIENT_GT + set_steer * STEER_COEFFICIENT_GT , - 1000 , 1000 ) * safetymultiplier ;
_out_speedr = constrain ( set_speed * SPEED_COEFFICIENT_GT - set_steer * STEER_COEFFICIENT_GT , - 1000 , 1000 ) * safetymultiplier ;
esc . setSpeed ( _out_speedl , _out_speedr ) ;
}
2022-03-28 19:50:00 +00:00
}
if ( error > 0 ) { //disarm if error occured
controlmode = MODE_DISARMED ; //force disarmed
}
2022-06-19 18:07:18 +00:00
2022-03-28 19:50:00 +00:00
if ( controlmode = = MODE_DISARMED ) { //all disarmed
2022-06-19 18:07:18 +00:00
# define WATCHDOG_TIMEOUT 2000
if ( millis ( ) - watchdogtimer > WATCHDOG_TIMEOUT ) {
set_speed = 0 ;
set_steer = 0 ;
}
if ( loopmillis - last_controlupdate > CONTROLUPDATEPERIOD ) {
last_controlupdate = loopmillis ;
set_speed = set_speed * ( 1.0 - filter_stop_set_speed ) ; //simple Filter
set_steer = set_steer * ( 1.0 - filter_stop_set_steer ) ;
int16_t _out_speedl , _out_speedr ;
_out_speedl = constrain ( set_speed * SPEED_COEFFICIENT_NRF + set_steer * STEER_COEFFICIENT_NRF , - 1500 , 1500 ) ;
_out_speedr = constrain ( set_speed * SPEED_COEFFICIENT_NRF - set_steer * STEER_COEFFICIENT_NRF , - 1500 , 1500 ) ;
esc . setSpeed ( _out_speedl , _out_speedr ) ;
}
2022-03-28 19:50:00 +00:00
}
if ( esc . sendPending ( loopmillis ) ) {
2022-05-22 19:02:18 +00:00
2022-06-19 18:07:18 +00:00
if ( ! motorenabled ) { //motors disabled. Used for safety off when remote released
if ( loopmillis - last_controlupdate > CONTROLUPDATEPERIOD ) {
last_controlupdate = loopmillis ;
set_speed = set_speed * ( 1.0 - filter_stop_set_speed ) ; //simple Filter
set_steer = set_steer * ( 1.0 - filter_stop_set_steer ) ;
int16_t _out_speedl , _out_speedr ;
_out_speedl = constrain ( set_speed * SPEED_COEFFICIENT_NRF + set_steer * STEER_COEFFICIENT_NRF , - 1500 , 1500 ) ;
_out_speedr = constrain ( set_speed * SPEED_COEFFICIENT_NRF - set_steer * STEER_COEFFICIENT_NRF , - 1500 , 1500 ) ;
esc . setSpeed ( _out_speedl , _out_speedr ) ;
}
2022-03-28 19:50:00 +00:00
}
2022-04-10 16:36:19 +00:00
last_send = loopmillis ;
2022-03-28 19:50:00 +00:00
# ifdef DEBUG
2022-04-10 16:36:19 +00:00
Serial . print ( " out_speedl= " ) ;
Serial . print ( out_speedl ) ;
Serial . print ( " out_speedr= " ) ;
Serial . print ( out_speedr ) ;
Serial . print ( " checksum= " ) ;
Serial . print ( out_checksum ) ;
Serial . print ( " controlmode= " ) ;
Serial . print ( controlmode ) ;
2022-03-28 19:50:00 +00:00
2022-04-10 16:36:19 +00:00
Serial . println ( ) ;
2022-03-28 19:50:00 +00:00
# endif
}
2022-06-19 13:07:40 +00:00
static unsigned long last_datalogging_write = 0 ;
2022-06-19 17:41:19 +00:00
static boolean logging_headerWritten = false ;
2022-06-19 13:07:40 +00:00
if ( datalogging ) {
# define LOGGINGINTERVAL 100
if ( loopmillis - last_datalogging_write > LOGGINGINTERVAL )
{
last_datalogging_write = loopmillis ;
2022-06-19 17:41:19 +00:00
File dataFile = SD . open ( datalogging_filename , FILE_WRITE ) ;
2022-06-19 13:07:40 +00:00
if ( dataFile ) { // if the file is available, write to it
2022-06-19 17:41:19 +00:00
if ( ! logging_headerWritten ) {
dataFile . print ( " time,cmd_L,cmd_R, " ) ;
dataFile . print ( " current_L,current_R, " ) ;
dataFile . print ( " rpm_L,rpm_R, " ) ;
dataFile . print ( " temp,vbat, " ) ;
dataFile . println ( " trip,currentConsumed " ) ;
logging_headerWritten = true ;
}
dataFile . print ( String ( loopmillis ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getCmdL ( ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getCmdR ( ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getFiltered_curL ( ) , 3 ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getFiltered_curR ( ) , 3 ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getFeedback_speedL_meas ( ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getFeedback_speedR_meas ( ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getFeedback_boardTemp ( ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getFeedback_batVoltage ( ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getTrip ( ) ) ; dataFile . print ( " ; " ) ;
dataFile . print ( esc . getCurrentConsumed ( ) , 3 ) ;
dataFile . println ( " " ) ;
2022-06-19 13:07:40 +00:00
dataFile . close ( ) ;
}
}
}
2022-03-28 19:50:00 +00:00
2022-03-28 19:03:36 +00:00
esc . update ( loopmillis ) ;
2022-05-22 11:47:05 +00:00
updateInputs ( loopmillis ) ;
2022-04-10 16:36:19 +00:00
updateDisplay ( loopmillis ) ;
}
2022-05-22 11:47:05 +00:00
void updateInputs ( unsigned long loopmillis ) {
switch ( displaymode ) {
case DISPLAY_STATS : case DISPLAY_STATS2 : case DISPLAY_STATS3 :
if ( button_up_click ) { //first button opens menu
displaymode = DISPLAY_MENU ; // go to menu
}
if ( button_inc_click ) {
displaymode = DISPLAY_STATS ;
}
if ( button_dec_click ) {
displaymode = DISPLAY_STATS2 ;
}
if ( button_down_click ) {
displaymode = DISPLAY_STATS3 ;
2022-06-19 18:10:31 +00:00
max_last_nrfreceive_delay = 0 ; //reset when switching to this display
2022-05-22 11:47:05 +00:00
}
break ;
case DISPLAY_MENU :
if ( button_up_click ) {
if ( menu_entrypos > 0 ) {
menu_entrypos - - ;
}
}
if ( button_down_click ) {
if ( menu_entrypos < ( MENU_ENTRIES - 1 ) ) {
menu_entrypos + + ;
}
}
switch ( menu_entrypos ) {
case 0 : //Exit
if ( button_inc_click | | button_dec_click ) {
displaymode = DISPLAY_STATS ;
}
break ;
case 1 : //Filter NRF Speed
if ( button_inc_click ) {
2022-05-22 16:47:03 +00:00
filter_nrf_set_speed + = 0.005 ;
2022-05-22 11:47:05 +00:00
filter_nrf_set_speed = constrain ( filter_nrf_set_speed , 0.01 , 1.0 ) ;
}
if ( button_dec_click ) {
2022-05-22 16:47:03 +00:00
filter_nrf_set_speed - = 0.005 ;
2022-05-22 11:47:05 +00:00
filter_nrf_set_speed = constrain ( filter_nrf_set_speed , 0.01 , 1.0 ) ;
}
break ;
case 2 : //Filter NRF Steer
if ( button_inc_click ) {
filter_nrf_set_steer + = 0.01 ;
filter_nrf_set_steer = constrain ( filter_nrf_set_steer , 0.01 , 1.0 ) ;
}
if ( button_dec_click ) {
filter_nrf_set_steer - = 0.01 ;
filter_nrf_set_steer = constrain ( filter_nrf_set_steer , 0.01 , 1.0 ) ;
}
break ;
2022-05-22 14:44:52 +00:00
case 3 :
if ( button_inc_click ) {
gt_speed_p + = 0.05 ;
gt_speed_p = constrain ( gt_speed_p , 0.05 , 5.0 ) ;
}
if ( button_dec_click ) {
gt_speed_p - = 0.05 ;
gt_speed_p = constrain ( gt_speed_p , 0.05 , 5.0 ) ;
}
break ;
case 4 :
if ( button_inc_click ) {
gt_steer_p + = 0.05 ;
gt_steer_p = constrain ( gt_steer_p , 0.05 , 5.0 ) ;
}
if ( button_dec_click ) {
gt_steer_p - = 0.05 ;
gt_steer_p = constrain ( gt_steer_p , 0.05 , 5.0 ) ;
}
break ;
case 5 :
if ( button_inc_click ) {
gt_speed_limit + = 50 ;
gt_speed_limit = constrain ( gt_speed_limit , 50 , 1000 ) ;
}
if ( button_dec_click ) {
gt_speed_limit - = 50 ;
gt_speed_limit = constrain ( gt_speed_limit , 50 , 1000 ) ;
}
break ;
case 6 :
if ( button_inc_click ) {
gt_steer_limit + = 50 ;
gt_steer_limit = constrain ( gt_steer_limit , 50 , 1000 ) ;
}
if ( button_dec_click ) {
gt_steer_limit - = 50 ;
gt_steer_limit = constrain ( gt_steer_limit , 50 , 1000 ) ;
}
break ;
2022-05-22 19:02:18 +00:00
case 7 :
if ( button_inc_click ) {
esc . resetStatistics ( ) ;
}
break ;
2022-05-22 14:44:52 +00:00
2022-05-22 11:47:05 +00:00
}
break ;
}
if ( button_up_click | | button_down_click | | button_inc_click | | button_dec_click ) { //any button was pressed
flag_updatedisplay = true ;
button_up_click = false ;
button_down_click = false ;
button_inc_click = false ;
button_dec_click = false ;
}
}
2022-04-10 16:36:19 +00:00
void updateDisplay ( unsigned long loopmillis )
{
static unsigned long last_updatedisplay = 0 ;
2022-05-22 11:47:05 +00:00
if ( loopmillis - last_updatedisplay > DISPLAYUPDATE_INTERVAL | | flag_updatedisplay ) {
flag_updatedisplay = false ;
if ( displaymode = = DISPLAY_STATS ) {
display_show_stats ( ) ;
} else if ( displaymode = = DISPLAY_STATS2 ) {
display_show_stats2 ( ) ;
} else if ( displaymode = = DISPLAY_STATS3 ) {
display_show_stats3 ( ) ;
} else if ( displaymode = = DISPLAY_MENU ) {
display_show_menu ( ) ;
2022-04-10 16:36:19 +00:00
}
2022-04-12 14:28:51 +00:00
2022-04-10 16:36:19 +00:00
last_updatedisplay = loopmillis ;
}
2022-04-10 18:19:41 +00:00
}
2022-05-22 11:47:05 +00:00
void display_show_stats ( ) {
display . clearDisplay ( ) ;
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE ) ;
display . setCursor ( 0 , 0 ) ;
display . print ( F ( " MODE= " ) ) ;
switch ( controlmode ) {
case MODE_DISARMED :
display . println ( F ( " DISARMED " ) ) ;
break ;
case MODE_RADIONRF :
display . println ( F ( " RADIONRF " ) ) ;
break ;
case MODE_GAMETRAK :
display . println ( F ( " GAMETRAK " ) ) ;
break ;
default :
display . println ( F ( " UNDEF " ) ) ;
break ;
}
//updates only when display active
2022-05-22 19:02:18 +00:00
/* static float maxcurL=0;
2022-05-22 11:47:05 +00:00
static float maxcurR = 0 ;
maxcurL = max ( maxcurL , esc . getFiltered_curL ( ) ) ;
maxcurR = max ( maxcurR , esc . getFiltered_curR ( ) ) ;
static float mincurL = 0 ;
static float mincurR = 0 ;
mincurL = min ( mincurL , esc . getFiltered_curL ( ) ) ;
2022-05-22 19:02:18 +00:00
mincurR = min ( mincurR , esc . getFiltered_curR ( ) ) ; */
2022-06-19 17:41:19 +00:00
2022-05-22 11:47:05 +00:00
2022-05-22 19:02:18 +00:00
display . print ( F ( " Bat= " ) ) ; display . print ( esc . getFeedback_batVoltage ( ) ) ; display . print ( F ( " min= " ) ) ; display . println ( esc . getMinBatVoltage ( ) ) ;
2022-06-04 09:18:37 +00:00
display . print ( F ( " Temp= " ) ) ; display . print ( esc . getFeedback_boardTemp ( ) ) ; display . print ( F ( " max= " ) ) ; display . println ( esc . getMaxBoardTemp ( ) ) ;
2022-05-22 19:02:18 +00:00
display . print ( F ( " DC max= " ) ) ; display . print ( esc . getMaxcurL ( ) , 1 ) ; display . print ( F ( " / " ) ) ; display . println ( esc . getMaxcurR ( ) , 1 ) ; // display.print(F(" min=")); display.print(mincurL,1); display.print(F("/")); display.println(mincurR,1);
display . print ( F ( " trip= " ) ) ; display . print ( esc . getTrip ( ) , 0 ) ; display . print ( F ( " , " ) ) ; display . print ( esc . getCurrentConsumed ( ) , 3 ) ; display . println ( F ( " Ah " ) ) ;
2022-06-04 09:18:37 +00:00
display . print ( F ( " eff.= " ) ) ; display . print ( esc . getTrip ( ) / esc . getCurrentConsumed ( ) , 0 ) ; display . println ( F ( " m/Ah " ) ) ;
2022-06-19 17:41:19 +00:00
display . print ( F ( " RTC= " ) ) ; display . print ( getCurrentDatestring ( ) ) ; display . println ( F ( " " ) ) ;
if ( datalogging ) {
display . print ( datalogging_filename ) ; display . print ( F ( " " ) ) ; display . print ( loopmillis / 1000 ) ; display . println ( F ( " s " ) ) ;
} else {
display . print ( " No SD " ) ; display . println ( F ( " " ) ) ;
}
2022-05-22 19:02:18 +00:00
2022-05-22 11:47:05 +00:00
display . display ( ) ; // Show initial text
}
void display_show_stats2 ( ) {
display . clearDisplay ( ) ;
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE ) ;
display . setCursor ( 0 , 0 ) ;
display . print ( F ( " CMD= " ) ) ; display . print ( esc . getCmdL ( ) ) ; display . print ( F ( " , " ) ) ; display . println ( esc . getCmdR ( ) ) ;
display . print ( F ( " FBC= " ) ) ; display . print ( esc . getFeedback_cmd1 ( ) ) ; display . print ( F ( " , " ) ) ; display . println ( esc . getFeedback_cmd2 ( ) ) ;
2022-05-22 19:02:18 +00:00
display . print ( F ( " Speed= " ) ) ; display . print ( esc . getFeedback_speedL_meas ( ) ) ; display . print ( F ( " , " ) ) ; display . print ( esc . getFeedback_speedR_meas ( ) ) ; display . print ( F ( " = " ) ) ; display . print ( esc . getMeanSpeed ( ) ) ; display . println ( F ( " ms " ) ) ;
2022-05-22 11:47:05 +00:00
display . print ( F ( " Length= " ) ) ; display . println ( gt_length ) ;
display . print ( F ( " H= " ) ) ; display . print ( gt_horizontal ) ; display . print ( F ( " V= " ) ) ; display . println ( gt_vertical ) ;
display . print ( F ( " CMD= " ) ) ; display . print ( esc . getCmdL ( ) ) ; display . print ( F ( " , " ) ) ; display . println ( esc . getCmdR ( ) ) ;
display . display ( ) ; // Show initial text
}
void display_show_stats3 ( ) {
display . clearDisplay ( ) ;
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE ) ;
display . setCursor ( 0 , 0 ) ;
2022-05-22 19:02:18 +00:00
display . print ( F ( " looptime= " ) ) ; display . println ( loopmillis - last_loopmillis ) ;
display . print ( F ( " feedback= " ) ) ; display . println ( esc . getFeedbackInterval ( ) ) ;
2022-06-19 18:10:31 +00:00
display . print ( F ( " nrf_delay= " ) ) ; display . println ( last_nrfreceive_delay ) ; display . print ( F ( " max= " ) ) ; display . println ( max_last_nrfreceive_delay ) ;
2022-05-22 19:02:18 +00:00
display . print ( F ( " maxdiff= " ) ) ; display . println ( raw_length_maxdiff ) ;
2022-05-22 11:47:05 +00:00
display . display ( ) ; // Show initial text
}
void display_show_menu ( ) {
display . clearDisplay ( ) ;
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE ) ;
display . setCursor ( 0 , 0 ) ;
for ( uint8_t i = 0 ; i < MENU_ENTRIES ; i + + ) {
if ( i = = menu_entrypos ) {
display . print ( F ( " > " ) ) ;
} else {
display . print ( F ( " " ) ) ;
}
switch ( i ) {
case 0 :
display . print ( F ( " EXIT " ) ) ; display . println ( ) ;
break ;
case 1 :
2022-05-22 16:47:03 +00:00
display . print ( F ( " Fltr spd= " ) ) ; display . println ( filter_nrf_set_speed , 3 ) ;
2022-05-22 11:47:05 +00:00
break ;
case 2 :
2022-05-22 16:47:03 +00:00
display . print ( F ( " Fltr str= " ) ) ; display . println ( filter_nrf_set_steer , 3 ) ;
2022-05-22 11:47:05 +00:00
break ;
2022-05-22 14:44:52 +00:00
case 3 :
display . print ( F ( " gt_speed_p= " ) ) ; display . println ( gt_speed_p ) ;
break ;
case 4 :
display . print ( F ( " gt_steer_p= " ) ) ; display . println ( gt_steer_p ) ;
break ;
case 5 :
display . print ( F ( " gt_speed_limit= " ) ) ; display . println ( gt_speed_limit ) ;
break ;
case 6 :
display . print ( F ( " gt_steer_limit= " ) ) ; display . println ( gt_steer_limit ) ;
break ;
2022-05-22 19:02:18 +00:00
case 7 :
if ( ( loopmillis / 1000 ) % 2 = = 0 ) {
display . print ( F ( " Inc to reset stats " ) ) ;
} else {
display . print ( F ( " t= " ) ) ; display . println ( esc . getTripTime ( loopmillis ) / 1000 ) ; display . println ( F ( " s " ) ) ;
}
break ;
2022-05-22 11:47:05 +00:00
}
2022-05-22 14:44:52 +00:00
2022-05-22 11:47:05 +00:00
}
display . display ( ) ; // Show initial text
2022-06-19 13:20:49 +00:00
}
time_t getTeensy3Time ( )
{
return Teensy3Clock . get ( ) ;
2022-06-19 17:41:19 +00:00
}
String addLeadingZero ( int number ) {
if ( number < 10 ) {
return " 0 " + String ( number ) ;
}
return String ( number ) ;
}
String getCurrentDatestring ( ) {
return addLeadingZero ( year ( ) ) + addLeadingZero ( month ( ) ) + addLeadingZero ( day ( ) ) + " - " + addLeadingZero ( hour ( ) ) + addLeadingZero ( minute ( ) ) + addLeadingZero ( second ( ) ) ;
}