2022-11-27 19:06:54 +00:00
/*
This file is part of the AberSailbot minimum viable control system ( AMVCS ) .
AMVCS is free software : you can
redistribute it and / or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation , version 2.
This program is distributed in the hope that it will be useful , but WITHOUT
ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE . See the GNU General Public License for more
details .
You should have received a copy of the GNU General Public License along with
this program ; if not , write to the Free Software Foundation , Inc . , 51
Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
Copyright Colin Sauze
2023-05-06 17:03:21 +01:00
libraries required :
timelib
esp32servo
tinygps
2022-11-27 19:06:54 +00:00
*/
2023-05-06 17:03:21 +01:00
2022-11-27 19:06:54 +00:00
# include <stdio.h>
2023-05-06 17:03:21 +01:00
//#include <Servo.h>
# include <ESP32Servo.h>
2022-11-27 19:06:54 +00:00
# include <Wire.h>
2023-05-06 17:03:21 +01:00
# include <HardwareSerial.h>
2022-11-27 19:06:54 +00:00
# include <math.h>
2023-05-06 17:03:21 +01:00
# include <WiFi.h>
# include <WiFiAP.h>
# include <AsyncUDP.h>
//Time.h became TimeLib.h as of version 1.6.1
# include "TimeLib.h"
2022-11-27 19:06:54 +00:00
# include "TinyGPS.h"
# define HMC6343_ADDRESS 0x19
# define HMC6343_HEADING_REG 0x50
# define GPS_ENABLE_PIN 12
2023-05-06 17:03:21 +01:00
# define CMPS12_ADDRESS 0x60
# define GPS_READ_INTERVAL 15 //how many seconds to leave between GPS reads
# define WP_THRESHOLD 15 //how close (in metres) should we get before we change waypoint?
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
# define rad2deg(x) (180 / M_PI) * x
# define deg2rad(x) x * M_PI / 180
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
Servo rudderServo ; // create servo object to control a servo
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
//SoftwareSerial myDebug(7, 8);
HardwareSerial myDebug ( 1 ) ;
2022-11-27 19:06:54 +00:00
TinyGPS gps ;
# define HEADING 0
# define WIND_DIR 1
# define ROLL 2
# define PITCH 3
# define RUDDER 4
# define SAIL 5
# define LAT 6
# define LON 7
# define TIME 8
2023-05-06 17:03:21 +01:00
# define DEBUG_CRITICAL 1 //really important messages that we don't want to ignore and are prepared to sacrifice execution speed to see
# define DEBUG_IMPORTANT 2 //fairly important messages that we probably want to see, but might cause issues with execution speed
# define DEBUG_MINOR 3 //less important messages that we can safely turn off to improve execution speed
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
# define DEBUG_THRESHOLD DEBUG_MINOR //set to 0 to show no debugging messages
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
const char * ssid = " boat " ;
AsyncUDP udp ;
byte ledState = 0 ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
struct Data {
uint16_t heading ;
uint16_t wind_dir ;
int8_t roll ;
int8_t pitch ;
int8_t rudder ;
byte sail ;
float lat ;
float lon ;
long unixtime ;
}
state ;
2022-11-27 19:06:54 +00:00
//make printf work
static FILE uartout = {
2023-05-06 17:03:21 +01:00
0 }
;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
static int uart_putchar ( char c , FILE * stream )
{
myDebug . write ( c ) ;
return 0 ;
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
static void say ( byte level , char * msg )
{
if ( level < = DEBUG_THRESHOLD )
{
2022-11-27 19:06:54 +00:00
myDebug . print ( " Debug " ) ;
myDebug . print ( level ) ;
myDebug . print ( " : [Ctrl] " ) ;
myDebug . println ( msg ) ;
}
}
//debugging printf that prepends "Debug:" to everything and can be easily turned off
2023-05-06 17:03:21 +01:00
void dprintf ( byte level , const char * fmt , . . . )
{
char outbuf [ 1024 ] ;
2022-11-30 13:34:48 +00:00
2023-05-06 17:03:21 +01:00
if ( level < = DEBUG_THRESHOLD )
{
printf ( " Debug%d: [Ctrl] " , level ) ;
2022-11-27 19:06:54 +00:00
va_list ap ;
va_start ( ap , fmt ) ;
2023-05-06 17:03:21 +01:00
vsnprintf ( outbuf , 1024 , fmt , ap ) ;
myDebug . print ( outbuf ) ;
2022-11-27 19:06:54 +00:00
va_end ( ap ) ;
}
}
2023-05-06 17:03:21 +01:00
void setup ( )
{
2022-11-27 19:06:54 +00:00
//Serial.begin(9600); //baud rate makes no difference on 32u4
2023-05-06 17:03:21 +01:00
Serial . begin ( 4800 , SERIAL_8N1 , 16 , 17 ) ; //for GPS // 17 tx, 16 rx
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
myDebug . begin ( 4800 , SERIAL_8N1 , 3 , 1 ) ; //debug UART on GPIO 6 and 7
say ( DEBUG_MINOR , " Debug serial system set up " ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
say ( DEBUG_CRITICAL , " Control system start up " ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
//required for printf
//but not on ESP32
//fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
//stdout = &uartout ;
dprintf ( DEBUG_IMPORTANT , " Printf configured \r \n " ) ;
2022-11-27 19:06:54 +00:00
delay ( 5000 ) ;
2023-05-06 17:03:21 +01:00
say ( DEBUG_IMPORTANT , " Setting up servos... " ) ;
2022-11-27 19:06:54 +00:00
//Use .attach for setting up connection to the servo
2023-05-06 17:03:21 +01:00
rudderServo . attach ( 5 , 1060 , 1920 ) ; // Attach, with the output limited
2022-11-27 19:06:54 +00:00
// between 1000 and 2000 ms
rudderServo . writeMicroseconds ( 1500 ) ;
2023-05-06 17:03:21 +01:00
say ( DEBUG_IMPORTANT , " Done " ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
say ( DEBUG_IMPORTANT , " Setting up I2C... " ) ;
Wire . begin ( ) ; // Initialise i2c for compass
say ( DEBUG_IMPORTANT , " Done " ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
say ( DEBUG_IMPORTANT , " Setting up GPS... " ) ;
pinMode ( GPS_ENABLE_PIN , OUTPUT ) ; //GPS on/off line
2022-11-27 19:06:54 +00:00
//setup GPS
2023-05-06 17:03:21 +01:00
digitalWrite ( GPS_ENABLE_PIN , 1 ) ;
2022-11-27 19:06:54 +00:00
delay ( 1000 ) ;
//turn off VTG
Serial . println ( " $PSRF103,05,00,00,01*21 \r " ) ;
//turn off RMC
Serial . println ( " $PSRF103,04,00,00,01*20 \r " ) ;
//turn off GSV
Serial . println ( " $PSRF103,03,00,00,01*27 \r " ) ;
//turn off GSA
Serial . println ( " $PSRF103,02,00,00,01*26 \r " ) ;
//turn off GLL
Serial . println ( " $PSRF103,01,00,00,01*25 \r " ) ;
//turn off GGA
Serial . println ( " $PSRF103,00,00,00,01*24 \r " ) ;
delay ( 1000 ) ;
//leave GPS on to get its initial fix
//digitalWrite(GPS_ENABLE_PIN,0);
2023-05-06 17:03:21 +01:00
//setup WiFi
say ( DEBUG_IMPORTANT , " setting up WiFi " ) ;
WiFi . softAP ( ssid ) ;
IPAddress myIP = WiFi . softAPIP ( ) ;
say ( DEBUG_IMPORTANT , " Done " ) ;
say ( DEBUG_IMPORTANT , " Setup Complete \n " ) ;
2022-11-27 19:06:54 +00:00
}
//computes an NMEA checksum
2023-05-06 17:03:21 +01:00
byte compute_checksum ( char * data , byte length )
{
byte computed_checksum = 0 ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
for ( byte i = 0 ; i < length ; i + + )
{
computed_checksum = ( byte ) computed_checksum ^ ( byte ) data [ i ] ;
2022-11-27 19:06:54 +00:00
}
return computed_checksum ;
}
//reads heading from HMC6343 compass
int readCompass ( ) {
2023-05-06 17:03:21 +01:00
unsigned char high_byte , low_byte , angle8 ;
char pitch , roll ;
unsigned int heading ;
Wire . beginTransmission ( CMPS12_ADDRESS ) ; //starts communication with CMPS12
Wire . write ( 1 ) ; //Sends the register we wish to start reading from
2022-11-27 19:06:54 +00:00
Wire . endTransmission ( ) ;
2023-05-06 17:03:21 +01:00
// Request 5 bytes from the CMPS12
// this will give us the 8 bit bearing,
// both bytes of the 16 bit bearing, pitch and roll
Wire . requestFrom ( CMPS12_ADDRESS , 5 ) ;
while ( Wire . available ( ) < 5 ) ; // Wait for all bytes to come back
angle8 = Wire . read ( ) ; // Read back the 5 bytes
high_byte = Wire . read ( ) ;
low_byte = Wire . read ( ) ;
pitch = Wire . read ( ) ;
roll = Wire . read ( ) ;
// heading is angle16
heading = high_byte ; // Calculate 16 bit angle
heading < < = 8 ;
heading + = low_byte ;
// may need to reimplement this later
// heading=heading/10;
// roll=roll/10;
// pitch=pitch/10;
myDebug . print ( " Heading = " ) ;
myDebug . print ( heading ) ;
// rewrite this to set state to our values
state . roll = ( int8_t ) roll ;
state . pitch = ( int8_t ) pitch ;
state . heading = ( uint16_t ) heading ;
dprintf ( DEBUG_IMPORTANT , " Heading: %d Roll: %d Pitch: %d \r \n " , state . heading , state . roll , state . pitch ) ;
printf ( " heading=%d \r \n " , heading ) ;
2022-11-27 19:06:54 +00:00
delay ( 100 ) ;
2023-05-06 17:03:21 +01:00
return ( int ) heading ; // Print the sensor readings to the serial port.
2022-11-27 19:06:54 +00:00
}
void readGPS ( ) {
2023-05-06 17:03:21 +01:00
unsigned long fix_age = 9999 , time , date ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " About to read GPS " ) ;
digitalWrite ( GPS_ENABLE_PIN , 1 ) ; //turn the GPS on
2022-11-27 19:06:54 +00:00
delay ( 1000 ) ;
2023-05-06 17:03:21 +01:00
while ( fix_age = = TinyGPS : : GPS_INVALID_AGE | | fix_age > 3000 ) //make sure the GPS has a fix, this might cause a wait the first time, but it should be quick any subsequent time
2022-11-27 19:06:54 +00:00
{
Serial . println ( " $PSRF103,04,01,00,01*21 \r " ) ;
2023-05-06 17:03:21 +01:00
dprintf ( DEBUG_MINOR , " NMEA string: " ) ;
2022-11-27 19:06:54 +00:00
unsigned long start = millis ( ) ;
2023-05-06 17:03:21 +01:00
while ( millis ( ) < start + 2000 )
{
if ( Serial . available ( ) )
{
2022-11-27 19:06:54 +00:00
int c = Serial . read ( ) ;
gps . encode ( c ) ;
2023-05-06 17:03:21 +01:00
if ( DEBUG_THRESHOLD > = DEBUG_MINOR )
{
2022-11-27 19:06:54 +00:00
myDebug . write ( c ) ;
}
2023-05-06 17:03:21 +01:00
if ( c = = ' \n ' )
{
2022-11-27 19:06:54 +00:00
break ;
}
}
}
2023-05-06 17:03:21 +01:00
gps . get_datetime ( & date , & time , & fix_age ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
dprintf ( DEBUG_MINOR , " fix age = %ld \r \n " , fix_age ) ;
if ( fix_age = = TinyGPS : : GPS_INVALID_AGE )
{
dprintf ( DEBUG_IMPORTANT , " Invalid fix, fix_age=%ld \r \n " , fix_age ) ;
say ( DEBUG_IMPORTANT , " No GPS fix " ) ;
2022-11-27 19:06:54 +00:00
}
}
2023-05-06 17:03:21 +01:00
digitalWrite ( GPS_ENABLE_PIN , 0 ) ; //turn the GPS off
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
gps . get_datetime ( & date , & time , & fix_age ) ;
gps . f_get_position ( & state . lat , & state . lon , & fix_age ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
if ( fix_age = = TinyGPS : : GPS_INVALID_AGE )
{
say ( DEBUG_IMPORTANT , " Invalid fix " ) ;
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
else
{
say ( DEBUG_IMPORTANT , " Fix Valid " ) ;
dprintf ( DEBUG_IMPORTANT , " lat=%ld lon=%ld \r \n " , ( long ) ( state . lat * 1000 ) , ( long ) ( state . lon * 1000 ) ) ;
2022-11-27 19:06:54 +00:00
int year ;
2023-05-06 17:03:21 +01:00
byte month , day , hour , min , sec ;
2022-11-27 19:06:54 +00:00
unsigned long age ;
2023-05-06 17:03:21 +01:00
gps . crack_datetime ( & year , & month , & day , & hour , & min , & sec , NULL , & age ) ;
setTime ( hour , min , sec , day , month , year ) ; //sets the time in the time library, lets us get unix time
2022-11-27 19:06:54 +00:00
2022-11-30 13:34:48 +00:00
}
2023-05-06 17:03:21 +01:00
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
int mod ( int value ) { //keeps angles betweeen 0 and 360
2022-11-27 19:06:54 +00:00
int newValue ;
2023-05-06 17:03:21 +01:00
if ( value < 0 ) {
2022-11-27 19:06:54 +00:00
newValue = value + 360 ;
2023-05-06 17:03:21 +01:00
}
else if ( value > = 360 ) {
2022-11-27 19:06:54 +00:00
newValue = value - 360 ;
2023-05-06 17:03:21 +01:00
}
else {
2022-11-27 19:06:54 +00:00
newValue = value ;
}
return newValue ;
}
//calculates difference between two headings taking wrap around into account
2023-05-06 17:03:21 +01:00
int get_hdg_diff ( int heading1 , int heading2 )
{
2022-11-27 19:06:54 +00:00
int result ;
2023-05-06 17:03:21 +01:00
result = heading1 - heading2 ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
if ( result < - 180 )
{
2022-11-27 19:06:54 +00:00
result = 360 + result ;
return result ;
2023-05-06 17:03:21 +01:00
}
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
if ( result > 180 )
{
result = 0 - ( 360 - result ) ;
2022-11-27 19:06:54 +00:00
}
return result ;
}
2023-05-06 17:03:21 +01:00
void loop ( )
{
say ( DEBUG_MINOR , " Entered loop " ) ;
unsigned long last_gps_read = 0 ;
unsigned long last_time = 0 , time_now = 0 ;
int wp_hdg = 0 ;
float wp_dist = 0.0 ;
int wp_num = 0 ;
float igain = 0.01 ;
float pgain = 0.1 ;
float running_err = 0.0 ;
int hdg_err = 0 ;
int relwind ;
long last_telemetry = 0 ;
# define TELEMETRY_INTERVAL 10
# define TARGET_LOOP_INTERVAL 100 //number of milliseconds between loop intervals
# define NUM_OF_WAYPOINTS 1
float wp_lats [ NUM_OF_WAYPOINTS ] ;
2022-11-27 19:06:54 +00:00
float wp_lons [ NUM_OF_WAYPOINTS ] ;
2023-05-06 17:03:21 +01:00
wp_lats [ 0 ] = 52.4 ;
wp_lons [ 0 ] = - 4.4 ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
while ( 1 )
{
2022-11-27 19:06:54 +00:00
//make loop execute at constant speed
2023-05-06 17:03:21 +01:00
time_now = millis ( ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
if ( time_now - last_time > 0 & & time_now - last_time < TARGET_LOOP_INTERVAL )
{
delay ( TARGET_LOOP_INTERVAL - ( time_now - last_time ) ) ;
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
last_time = millis ( ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " reading compass " ) ;
2022-11-27 19:06:54 +00:00
readCompass ( ) ;
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " finished reading compass " ) ;
//state.wind_dir=getTrueWind(); {
2022-11-27 19:06:54 +00:00
//no wind sensor, so just use a fixed wind direction
2023-05-06 17:03:21 +01:00
state . wind_dir = 270 ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
relwind = mod ( state . wind_dir - state . heading ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " may read gps " ) ;
if ( millis ( ) - last_gps_read > ( GPS_READ_INTERVAL * 1000 ) | | millis ( ) < last_gps_read ) //read the GPS at the specified interval or whenever the millis count wraps around
2022-11-27 19:06:54 +00:00
{
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " Reading GPS " ) ;
2022-11-27 19:06:54 +00:00
readGPS ( ) ;
2023-05-06 17:03:21 +01:00
wp_hdg = ( int ) TinyGPS : : course_to ( state . lat , state . lon , wp_lats [ wp_num ] , wp_lons [ wp_num ] ) ;
wp_dist = TinyGPS : : distance_between ( state . lat , state . lon , wp_lats [ wp_num ] , wp_lons [ wp_num ] ) ;
if ( wp_dist < WP_THRESHOLD )
{
wp_num + + ;
if ( wp_num = = NUM_OF_WAYPOINTS ) //reached last waypoint already
2022-11-27 19:06:54 +00:00
{
2023-05-06 17:03:21 +01:00
wp_num - - ;
}
else //reached new waypoint
2022-11-27 19:06:54 +00:00
{
2023-05-06 17:03:21 +01:00
wp_hdg = ( int ) TinyGPS : : course_to ( state . lat , state . lon , wp_lats [ wp_num ] , wp_lons [ wp_num ] ) ;
wp_dist = TinyGPS : : distance_between ( state . lat , state . lon , wp_lats [ wp_num ] , wp_lons [ wp_num ] ) ;
2022-11-27 19:06:54 +00:00
}
}
2023-05-06 17:03:21 +01:00
last_gps_read = millis ( ) ;
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " Finished possible gps read " ) ;
2022-11-27 19:06:54 +00:00
//sail logic
//sailLogic(relwind);
//rudder logic
2023-05-06 17:03:21 +01:00
hdg_err = get_hdg_diff ( wp_hdg , state . heading ) ;
2022-11-27 19:06:54 +00:00
running_err = running_err + ( float ) hdg_err ;
2023-05-06 17:03:21 +01:00
if ( abs ( running_err > 4000 ) )
{
running_err = 4000 ; // limit integral component
2022-11-27 19:06:54 +00:00
}
running_err = running_err * 0.9 ;
/*dprintf("hdg_err = %d running_err = ",hdg_err);
myDebug . println ( running_err ) ; */
2023-05-06 17:03:21 +01:00
state . rudder = ( int ) round ( ( pgain * ( float ) hdg_err ) + ( igain * running_err ) ) ;
if ( state . rudder < - 5 )
{
state . rudder = - 5 ;
}
else if ( state . rudder > 5 )
{
state . rudder = 5 ;
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " correcting rudder " ) ;
rudderServo . writeMicroseconds ( 1500 + ( state . rudder * 100 ) ) ;
2022-11-27 19:06:54 +00:00
2023-05-06 17:03:21 +01:00
say ( DEBUG_MINOR , " possible telemetry incoming: " ) ;
if ( last_telemetry + ( TELEMETRY_INTERVAL * 1000 ) < millis ( ) )
{
char msgbuf [ 255 ] ;
char nmeadata [ 80 ] ;
char checksum ;
//generate key value telemetry packet
snprintf ( msgbuf , 254 , " time=%ld lat=%.4f lon=%.4f hdg=%d hdg_err=%d roll=%d pitch=%d rudder=%d wp_num=%d wp_hdg=%d wp_dist=%ld " , now ( ) , state . lat , state . lon , state . heading , hdg_err , state . roll , state . pitch , state . rudder , wp_num , wp_hdg , ( long ) wp_dist ) ;
say ( DEBUG_CRITICAL , msgbuf ) ;
udp . broadcastTo ( msgbuf , 1234 ) ;
//generate compass NMEA string
snprintf ( nmeadata , 79 , " HDM,%d.0,M " , state . heading ) ;
checksum = compute_checksum ( nmeadata , strlen ( nmeadata ) ) ;
snprintf ( msgbuf , 254 , " $%s*%X \n " , nmeadata , checksum ) ;
say ( DEBUG_CRITICAL , msgbuf ) ;
udp . broadcastTo ( msgbuf , 10000 ) ;
//generate GPS NMEA string
char timestr [ 7 ] ;
char hemNS ;
char hemEW ;
char latstr [ 10 ] ; //DDMM.MMMM0
char lonstr [ 11 ] ; //DDDMM.MMMM0
int degrees ;
float minutes ;
//generate time
snprintf ( timestr , 6 , " %2d%2d%2d " , hour ( ) , minute ( ) , second ( ) ) ;
//generate lat/lon
degrees = abs ( ( int ) state . lat ) ;
minutes = ( fabs ( state . lat ) - ( float ) degrees ) * 60.0 ;
snprintf ( latstr , 9 , " %2d%2.4f " , degrees , minutes ) ;
//get the hemisphere north/south
if ( state . lat > 0 ) {
hemNS = ' N ' ;
}
else {
hemNS = ' S ' ;
}
degrees = abs ( ( int ) state . lon ) ;
minutes = ( fabs ( state . lon ) - ( float ) degrees ) * 60.0 ;
snprintf ( lonstr , 10 , " %3d%2.4f " , degrees , minutes ) ;
//get the hemisphere east/east
if ( state . lon > 0 ) {
hemEW = ' E ' ;
}
else {
hemEW = ' W ' ;
}
//$GPGLL,LATMM.MMMM,N/S,LONMM.MMMM,E/W,HHMMSS,A,*SUM
snprintf ( nmeadata , 79 , " GPGLL,%s,%c,%s,%c,%s,A% " , latstr , hemNS , lonstr , hemEW , timestr ) ;
checksum = compute_checksum ( nmeadata , strlen ( nmeadata ) ) ;
snprintf ( msgbuf , 254 , " $%s*%X \n " , nmeadata , checksum ) ;
say ( DEBUG_CRITICAL , msgbuf ) ;
//send to UDP port 10000
udp . broadcastTo ( msgbuf , 10000 ) ;
if ( DEBUG_THRESHOLD > = DEBUG_CRITICAL )
{
2022-11-27 19:06:54 +00:00
myDebug . print ( " lat= " ) ;
2023-05-06 17:03:21 +01:00
myDebug . print ( state . lat , 5 ) ;
2022-11-27 19:06:54 +00:00
myDebug . print ( " lon= " ) ;
2023-05-06 17:03:21 +01:00
myDebug . print ( state . lon , 5 ) ;
2022-11-27 19:06:54 +00:00
myDebug . print ( " wplat= " ) ;
2023-05-06 17:03:21 +01:00
myDebug . print ( wp_lats [ wp_num ] , 5 ) ;
2022-11-27 19:06:54 +00:00
myDebug . print ( " wplon= " ) ;
2023-05-06 17:03:21 +01:00
myDebug . print ( wp_lons [ wp_num ] , 5 ) ;
2022-11-27 19:06:54 +00:00
myDebug . print ( " running_err= " ) ;
myDebug . println ( running_err ) ;
}
2023-05-06 17:03:21 +01:00
last_telemetry = millis ( ) ;
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
2022-11-27 19:06:54 +00:00
}
2023-05-06 17:03:21 +01:00
}