Keep fused location streaming through GPS rejects
This commit is contained in:
@@ -13,7 +13,9 @@ GPS_DEBUG ?= 1
|
|||||||
GPS_DEBUG_LEVEL ?= 4
|
GPS_DEBUG_LEVEL ?= 4
|
||||||
BSP_UART_CLOCK_HZ ?= 100000000
|
BSP_UART_CLOCK_HZ ?= 100000000
|
||||||
BSP_UART_BAUDRATE ?= 115200
|
BSP_UART_BAUDRATE ?= 115200
|
||||||
|
GPS_SYSTEM_UART_BAUDRATE ?= 460800
|
||||||
BSP_CLINT_TIMEBASE_HZ ?= 1000000
|
BSP_CLINT_TIMEBASE_HZ ?= 1000000
|
||||||
|
GPS_SYSTEM_CLINT_TIMEBASE_HZ ?= 500000
|
||||||
# BSP_DTIM_* mirrors the FPGA DTIM_* knobs and is used by C code plus linker scripts.
|
# BSP_DTIM_* mirrors the FPGA DTIM_* knobs and is used by C code plus linker scripts.
|
||||||
BSP_DTIM_BASE ?= 0x80000000
|
BSP_DTIM_BASE ?= 0x80000000
|
||||||
BSP_DTIM_SIZE ?= 0x00100000
|
BSP_DTIM_SIZE ?= 0x00100000
|
||||||
@@ -38,7 +40,9 @@ help:
|
|||||||
@echo " APP_FLASH_OFFSET=$(APP_FLASH_OFFSET)"
|
@echo " APP_FLASH_OFFSET=$(APP_FLASH_OFFSET)"
|
||||||
@echo " BSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)"
|
@echo " BSP_UART_CLOCK_HZ=$(BSP_UART_CLOCK_HZ)"
|
||||||
@echo " BSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)"
|
@echo " BSP_UART_BAUDRATE=$(BSP_UART_BAUDRATE)"
|
||||||
|
@echo " GPS_SYSTEM_UART_BAUDRATE=$(GPS_SYSTEM_UART_BAUDRATE)"
|
||||||
@echo " BSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)"
|
@echo " BSP_CLINT_TIMEBASE_HZ=$(BSP_CLINT_TIMEBASE_HZ)"
|
||||||
|
@echo " GPS_SYSTEM_CLINT_TIMEBASE_HZ=$(GPS_SYSTEM_CLINT_TIMEBASE_HZ)"
|
||||||
@echo " BSP_DTIM_BASE=$(BSP_DTIM_BASE)"
|
@echo " BSP_DTIM_BASE=$(BSP_DTIM_BASE)"
|
||||||
@echo " BSP_DTIM_SIZE=$(BSP_DTIM_SIZE)"
|
@echo " BSP_DTIM_SIZE=$(BSP_DTIM_SIZE)"
|
||||||
|
|
||||||
@@ -57,7 +61,7 @@ steval-mki217v1-test:
|
|||||||
@make -C steval_mki217v1_test TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/steval_mki217v1_test" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all
|
@make -C steval_mki217v1_test TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/steval_mki217v1_test" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all
|
||||||
|
|
||||||
gps-system:
|
gps-system:
|
||||||
@make -C gps_system TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/gps_system" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all
|
@make -C gps_system TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/gps_system" GPS_DEBUG="$(GPS_DEBUG)" GPS_DEBUG_LEVEL="$(GPS_DEBUG_LEVEL)" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(GPS_SYSTEM_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(GPS_SYSTEM_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all
|
||||||
|
|
||||||
app:
|
app:
|
||||||
@test -d "$(APP)"
|
@test -d "$(APP)"
|
||||||
|
|||||||
@@ -474,14 +474,14 @@ static void print_metrics(scenario_kind_t scenario, unsigned int gps_ms,
|
|||||||
static int run_matrix(void)
|
static int run_matrix(void)
|
||||||
{
|
{
|
||||||
static const unsigned int gps_periods_ms[] = {200u, 500u, 1000u};
|
static const unsigned int gps_periods_ms[] = {200u, 500u, 1000u};
|
||||||
static const unsigned int imu_periods_ms[] = {19u, 20u, 200u, 300u};
|
static const unsigned int imu_periods_ms[] = {19u, 20u, 100u, 200u, 300u};
|
||||||
bool passed = true;
|
bool passed = true;
|
||||||
printf("Four-satellite asynchronous platform matrix; 3 s outage and 2 s coherent GNSS fault\n");
|
printf("Four-satellite asynchronous platform matrix; 3 s outage and 2 s coherent GNSS fault\n");
|
||||||
for(unsigned int scenario = 0u; scenario < SCENARIO_COUNT; scenario++)
|
for(unsigned int scenario = 0u; scenario < SCENARIO_COUNT; scenario++)
|
||||||
{
|
{
|
||||||
for(unsigned int gps_index = 0u; gps_index < 3u; gps_index++)
|
for(unsigned int gps_index = 0u; gps_index < 3u; gps_index++)
|
||||||
{
|
{
|
||||||
for(unsigned int imu_index = 0u; imu_index < 4u; imu_index++)
|
for(unsigned int imu_index = 0u; imu_index < 5u; imu_index++)
|
||||||
{
|
{
|
||||||
metrics_t metrics = run_case((scenario_kind_t)scenario,
|
metrics_t metrics = run_case((scenario_kind_t)scenario,
|
||||||
gps_periods_ms[gps_index], imu_periods_ms[imu_index], NULL);
|
gps_periods_ms[gps_index], imu_periods_ms[imu_index], NULL);
|
||||||
@@ -504,7 +504,7 @@ static int run_matrix(void)
|
|||||||
fprintf(stderr, "FAIL: platform scenario matrix contract.\n");
|
fprintf(stderr, "FAIL: platform scenario matrix contract.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("PASS: 19/20 ms production rates stayed bounded; 200/300 ms coarse IMU "
|
printf("PASS: 19/20 ms production rates stayed bounded; 100/200/300 ms coarse IMU "
|
||||||
"rates remained finite and their dynamic accuracy loss is reported, not hidden.\n");
|
"rates remained finite and their dynamic accuracy loss is reported, not hidden.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -512,6 +512,33 @@ static int run_matrix(void)
|
|||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if(argc == 1) return run_matrix();
|
if(argc == 1) return run_matrix();
|
||||||
|
if((argc == 6) && (strcmp(argv[1], "--benchmark") == 0))
|
||||||
|
{
|
||||||
|
scenario_kind_t scenario;
|
||||||
|
if(!parse_scenario(argv[2], &scenario))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "unknown scenario: %s\n", argv[2]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
unsigned int gps_ms = (unsigned int)strtoul(argv[3], NULL, 10);
|
||||||
|
unsigned int imu_ms = (unsigned int)strtoul(argv[4], NULL, 10);
|
||||||
|
unsigned int iterations = (unsigned int)strtoul(argv[5], NULL, 10);
|
||||||
|
if((iterations == 0u) ||
|
||||||
|
!((gps_ms == 200u) || (gps_ms == 500u) || (gps_ms == 1000u)) ||
|
||||||
|
!((imu_ms == 19u) || (imu_ms == 20u) || (imu_ms == 100u) ||
|
||||||
|
(imu_ms == 200u) || (imu_ms == 300u)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "supported GPS: 200/500/1000 ms; "
|
||||||
|
"IMU: 19/20/100/200/300 ms; iterations > 0\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
metrics_t metrics;
|
||||||
|
for(unsigned int iteration = 0u; iteration < iterations; iteration++)
|
||||||
|
metrics = run_case(scenario, gps_ms, imu_ms, NULL);
|
||||||
|
print_metrics(scenario, gps_ms, imu_ms, &metrics);
|
||||||
|
printf("completed %u benchmark iterations\n", iterations);
|
||||||
|
return metrics.finite ? 0 : 1;
|
||||||
|
}
|
||||||
if((argc == 6) && (strcmp(argv[1], "--log") == 0))
|
if((argc == 6) && (strcmp(argv[1], "--log") == 0))
|
||||||
{
|
{
|
||||||
scenario_kind_t scenario;
|
scenario_kind_t scenario;
|
||||||
@@ -523,10 +550,10 @@ int main(int argc, char** argv)
|
|||||||
unsigned int gps_ms = (unsigned int)strtoul(argv[3], NULL, 10);
|
unsigned int gps_ms = (unsigned int)strtoul(argv[3], NULL, 10);
|
||||||
unsigned int imu_ms = (unsigned int)strtoul(argv[4], NULL, 10);
|
unsigned int imu_ms = (unsigned int)strtoul(argv[4], NULL, 10);
|
||||||
if(!((gps_ms == 200u) || (gps_ms == 500u) || (gps_ms == 1000u)) ||
|
if(!((gps_ms == 200u) || (gps_ms == 500u) || (gps_ms == 1000u)) ||
|
||||||
!((imu_ms == 19u) || (imu_ms == 20u) ||
|
!((imu_ms == 19u) || (imu_ms == 20u) || (imu_ms == 100u) ||
|
||||||
(imu_ms == 200u) || (imu_ms == 300u)))
|
(imu_ms == 200u) || (imu_ms == 300u)))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "supported GPS: 200/500/1000 ms; IMU: 19/20/200/300 ms\n");
|
fprintf(stderr, "supported GPS: 200/500/1000 ms; IMU: 19/20/100/200/300 ms\n");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
FILE* log_file = fopen(argv[5], "w");
|
FILE* log_file = fopen(argv[5], "w");
|
||||||
@@ -546,6 +573,9 @@ int main(int argc, char** argv)
|
|||||||
return metrics.finite ? 0 : 1;
|
return metrics.finite ? 0 : 1;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "usage: %s [--log stationary|pedestrian|car|aircraft "
|
fprintf(stderr, "usage: %s [--log stationary|pedestrian|car|aircraft "
|
||||||
"200|500|1000 19|20|200|300 output.log]\n", argv[0]);
|
"200|500|1000 19|20|100|200|300 output.log]\n"
|
||||||
|
" %s [--benchmark stationary|pedestrian|car|aircraft "
|
||||||
|
"200|500|1000 19|20|100|200|300 iterations]\n",
|
||||||
|
argv[0], argv[0]);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ GPS_DEBUG ?= 1
|
|||||||
GPS_DEBUG_LEVEL ?= 4
|
GPS_DEBUG_LEVEL ?= 4
|
||||||
|
|
||||||
# The current Genesys2 Rocket/fabric domain that clocks the UART is 50 MHz.
|
# The current Genesys2 Rocket/fabric domain that clocks the UART is 50 MHz.
|
||||||
# Keep the requested 115200 baud physical rather than producing 57600 baud
|
# The 50 Hz fused-location stream plus GPS diagnostics does not fit safely in
|
||||||
# with the common 100 MHz fallback divider.
|
# the polling UART budget at 115200 baud.
|
||||||
BSP_UART_CLOCK_HZ ?= 50000000
|
BSP_UART_CLOCK_HZ ?= 50000000
|
||||||
|
BSP_UART_BAUDRATE ?= 460800
|
||||||
|
BSP_CLINT_TIMEBASE_HZ ?= 500000
|
||||||
|
|
||||||
# Select one sensor backend, or keep the default read-only WHO_AM_I probe.
|
# Select one sensor backend, or keep the default read-only WHO_AM_I probe.
|
||||||
# Accepted values: auto, tdk, st (stm is an alias for st).
|
# Accepted values: auto, tdk, st (stm is an alias for st).
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
#error "GPS_ESKF_ENABLE must be 0 or 1"
|
#error "GPS_ESKF_ENABLE must be 0 or 1"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define IMU_SAMPLES_BEFORE_GPS_SERVICE 1u
|
||||||
|
#define IMU_SAMPLES_AFTER_GPS_SERVICE 3u
|
||||||
|
|
||||||
static void initialize_sensor_fusion(gps_system_state_t* system)
|
static void initialize_sensor_fusion(gps_system_state_t* system)
|
||||||
{
|
{
|
||||||
system->fusion_enabled = (GPS_ESKF_ENABLE != 0);
|
system->fusion_enabled = (GPS_ESKF_ENABLE != 0);
|
||||||
@@ -43,18 +46,32 @@ static void initialize_sensor_fusion(gps_system_state_t* system)
|
|||||||
true); /* Current prototype is the PX4-equivalent unarmed bench mode. */
|
true); /* Current prototype is the PX4-equivalent unarmed bench mode. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int feed_pending_imu_to_eskf(gps_system_state_t* system)
|
static unsigned int feed_pending_imu_to_eskf(
|
||||||
|
gps_system_state_t* system,
|
||||||
|
unsigned int max_samples)
|
||||||
{
|
{
|
||||||
if(!system->fusion_initialized)
|
if(!system->fusion_initialized || (max_samples == 0u))
|
||||||
{
|
{
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int processed = 0u;
|
unsigned int processed = 0u;
|
||||||
imu_sensor_service();
|
imu_sensor_service();
|
||||||
while(imu_sensor_take_measurement(&system->imu_sample))
|
while((processed < max_samples) &&
|
||||||
|
imu_sensor_take_measurement(&system->imu_sample))
|
||||||
{
|
{
|
||||||
(void)navigation_fusion_push_imu(&system->imu_sample);
|
bool accepted = navigation_fusion_push_imu(&system->imu_sample);
|
||||||
|
if(accepted &&
|
||||||
|
navigation_fusion_get_output(&system->fused_solution) &&
|
||||||
|
system->fused_solution.global_valid &&
|
||||||
|
(system->fused_solution.timestamp_ticks !=
|
||||||
|
system->last_fused_location_tick))
|
||||||
|
{
|
||||||
|
gps_system_uart_publish_fused_location(
|
||||||
|
&system->fused_solution);
|
||||||
|
system->last_fused_location_tick =
|
||||||
|
system->fused_solution.timestamp_ticks;
|
||||||
|
}
|
||||||
processed++;
|
processed++;
|
||||||
}
|
}
|
||||||
return processed;
|
return processed;
|
||||||
@@ -78,21 +95,33 @@ int main(void)
|
|||||||
system.fusion_enabled, system.fusion_initialized,
|
system.fusion_enabled, system.fusion_initialized,
|
||||||
system.imu_initialized, system.imu_running);
|
system.imu_initialized, system.imu_running);
|
||||||
|
|
||||||
|
bool imu_backlog_may_remain = false;
|
||||||
for(;;)
|
for(;;)
|
||||||
|
{
|
||||||
|
/* Skip WFI only while draining a bounded IMU backlog. Every batch
|
||||||
|
* still services GPS before more prediction work, so a continuously
|
||||||
|
* non-empty IMU queue cannot starve navigation epochs. */
|
||||||
|
if(!imu_backlog_may_remain)
|
||||||
{
|
{
|
||||||
/* GPS, IMU data-ready and the maintenance timer wake this loop. */
|
/* GPS, IMU data-ready and the maintenance timer wake this loop. */
|
||||||
asm volatile("wfi");
|
asm volatile("wfi");
|
||||||
|
}
|
||||||
|
|
||||||
/* IMU prediction runs at the sensor's own timestamped rate. */
|
/* Limit pre-GPS work to one sample for low event latency. */
|
||||||
(void)feed_pending_imu_to_eskf(&system);
|
(void)feed_pending_imu_to_eskf(
|
||||||
|
&system, IMU_SAMPLES_BEFORE_GPS_SERVICE);
|
||||||
|
|
||||||
/* GPS remains an independent receiver: events first, then coherent WLS. */
|
/* GPS remains an independent receiver: events first, then coherent WLS. */
|
||||||
gps_receiver_process_pending_events();
|
gps_receiver_process_pending_events();
|
||||||
system.gps_epoch_ready = gps_receiver_solve_ready_epoch(
|
system.gps_epoch_ready = gps_receiver_solve_ready_epoch(
|
||||||
&system.gps_solution, &system.gps_measurement_ticks);
|
&system.gps_solution, &system.gps_measurement_ticks);
|
||||||
|
|
||||||
/* WLS may take long enough for more IMU samples to arrive. */
|
/* WLS may take long enough for more IMU samples to arrive. Drain a
|
||||||
(void)feed_pending_imu_to_eskf(&system);
|
* small batch, then return to GPS service before continuing. */
|
||||||
|
unsigned int imu_after_gps = feed_pending_imu_to_eskf(
|
||||||
|
&system, IMU_SAMPLES_AFTER_GPS_SERVICE);
|
||||||
|
imu_backlog_may_remain =
|
||||||
|
(imu_after_gps == IMU_SAMPLES_AFTER_GPS_SERVICE);
|
||||||
|
|
||||||
if(system.gps_epoch_ready && system.gps_solution.solution_valid)
|
if(system.gps_epoch_ready && system.gps_solution.solution_valid)
|
||||||
{
|
{
|
||||||
@@ -114,15 +143,6 @@ int main(void)
|
|||||||
/* Delayed GPS update is applied at its capture timestamp; newer
|
/* Delayed GPS update is applied at its capture timestamp; newer
|
||||||
* IMU history is replayed to produce the current fused state. */
|
* IMU history is replayed to produce the current fused state. */
|
||||||
(void)navigation_fusion_push_gps(&system.gps_for_fusion);
|
(void)navigation_fusion_push_gps(&system.gps_for_fusion);
|
||||||
if(navigation_fusion_get_output(&system.fused_solution) &&
|
|
||||||
system.fused_solution.global_valid)
|
|
||||||
{
|
|
||||||
gps_system_uart_publish_location("imu_corrected",
|
|
||||||
system.fused_solution.latitude_deg,
|
|
||||||
system.fused_solution.longitude_deg,
|
|
||||||
system.fused_solution.height_m,
|
|
||||||
&system.gps_solution);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ void gps_system_uart_publish_location(
|
|||||||
double height_m,
|
double height_m,
|
||||||
const gps_nav_solution_t* gps);
|
const gps_nav_solution_t* gps);
|
||||||
|
|
||||||
|
void gps_system_uart_publish_fused_location(
|
||||||
|
const navigation_fusion_output_t* output);
|
||||||
|
|
||||||
void gps_system_uart_publish_startup(
|
void gps_system_uart_publish_startup(
|
||||||
bool fusion_enabled,
|
bool fusion_enabled,
|
||||||
bool fusion_initialized,
|
bool fusion_initialized,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t timestamp_ticks;
|
uint64_t timestamp_ticks;
|
||||||
|
uint64_t last_accepted_gps_ticks;
|
||||||
double position_enu_m[3];
|
double position_enu_m[3];
|
||||||
double velocity_enu_mps[3];
|
double velocity_enu_mps[3];
|
||||||
double latitude_deg;
|
double latitude_deg;
|
||||||
|
|||||||
@@ -43,7 +43,9 @@
|
|||||||
#define GPS_ACQ_IP_BASE_ADDR(index) (BSP_GPS_ACQ_BASE + ((uintptr_t)(index) * BSP_GPS_ACQ_STRIDE))
|
#define GPS_ACQ_IP_BASE_ADDR(index) (BSP_GPS_ACQ_BASE + ((uintptr_t)(index) * BSP_GPS_ACQ_STRIDE))
|
||||||
#define GPS_ACQ_INTR_LINE(index) (BSP_GPS_ACQ_IRQ + ((unsigned int)(index) * BSP_GPS_ACQ_IRQ_STRIDE))
|
#define GPS_ACQ_INTR_LINE(index) (BSP_GPS_ACQ_IRQ + ((unsigned int)(index) * BSP_GPS_ACQ_IRQ_STRIDE))
|
||||||
#define GPS_EVENT_QUEUE_SIZE 64u
|
#define GPS_EVENT_QUEUE_SIZE 64u
|
||||||
#define GPS_SYSTICK_HZ 20u
|
/* Genesys2 CLINT is 500 kHz. Keep foreground maintenance at
|
||||||
|
* 10 Hz; the tracking IP's 20 ms NAV timer is independent. */
|
||||||
|
#define GPS_SYSTICK_HZ 10u
|
||||||
#define GPS_NAV_SOLVE_TIMER_TICK_MS 20u
|
#define GPS_NAV_SOLVE_TIMER_TICK_MS 20u
|
||||||
#ifndef GPS_NAV_SOLVE_TIMER_TICKS
|
#ifndef GPS_NAV_SOLVE_TIMER_TICKS
|
||||||
#define GPS_NAV_SOLVE_TIMER_TICKS 50u
|
#define GPS_NAV_SOLVE_TIMER_TICKS 50u
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ typedef struct {
|
|||||||
imu_sample_t imu_sample;
|
imu_sample_t imu_sample;
|
||||||
navigation_fusion_output_t fused_solution;
|
navigation_fusion_output_t fused_solution;
|
||||||
uint64_t gps_measurement_ticks;
|
uint64_t gps_measurement_ticks;
|
||||||
|
uint64_t last_fused_location_tick;
|
||||||
uint64_t last_status_tick;
|
uint64_t last_status_tick;
|
||||||
bool gps_epoch_ready;
|
bool gps_epoch_ready;
|
||||||
bool fusion_enabled;
|
bool fusion_enabled;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include "gps/gps_receiver.h"
|
#include "gps/gps_receiver.h"
|
||||||
#include "imu/imu_sensor.h"
|
#include "imu/imu_sensor.h"
|
||||||
|
|
||||||
|
#define GPS_AIDED_MAX_AGE_MS 1000u
|
||||||
|
|
||||||
void gps_system_uart_publish_location(
|
void gps_system_uart_publish_location(
|
||||||
const char* source,
|
const char* source,
|
||||||
double latitude_deg,
|
double latitude_deg,
|
||||||
@@ -27,6 +29,33 @@ void gps_system_uart_publish_location(
|
|||||||
gps->tracked_satellite_count, gps->used_satellite_count);
|
gps->tracked_satellite_count, gps->used_satellite_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gps_system_uart_publish_fused_location(
|
||||||
|
const navigation_fusion_output_t* output)
|
||||||
|
{
|
||||||
|
if((output == NULL) || !output->global_valid)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t age_ticks = output->timestamp_ticks >= output->last_accepted_gps_ticks
|
||||||
|
? output->timestamp_ticks - output->last_accepted_gps_ticks : 0u;
|
||||||
|
uint64_t age_ms_wide =
|
||||||
|
age_ticks / (BSP_CLINT_TIMEBASE_HZ / 1000u);
|
||||||
|
uint32_t age_ms = age_ms_wide > UINT32_MAX
|
||||||
|
? UINT32_MAX : (uint32_t)age_ms_wide;
|
||||||
|
const char* mode =
|
||||||
|
(output->gps_accepted > 0u) && (age_ms <= GPS_AIDED_MAX_AGE_MS)
|
||||||
|
? "gps_aided" : "dead_reckoning";
|
||||||
|
|
||||||
|
/* At 50 Hz this compact record uses about 14% of the 460800-baud link,
|
||||||
|
* leaving headroom for navigation work and lower-rate diagnostics. */
|
||||||
|
GPS_LOG(DEBUG_STATUS, GPS_LOG_CAT_LOCATION,
|
||||||
|
"source=imu_corrected mode=%s lat=%.9lf lon=%.9lf "
|
||||||
|
"height=%.2lf gps_age_ms=%lu\r\n",
|
||||||
|
mode, output->latitude_deg, output->longitude_deg,
|
||||||
|
output->height_m, (unsigned long)age_ms);
|
||||||
|
}
|
||||||
|
|
||||||
void gps_system_uart_publish_startup(
|
void gps_system_uart_publish_startup(
|
||||||
bool fusion_enabled,
|
bool fusion_enabled,
|
||||||
bool fusion_initialized,
|
bool fusion_initialized,
|
||||||
|
|||||||
@@ -123,6 +123,8 @@ bool navigation_fusion_get_output(navigation_fusion_output_t* output)
|
|||||||
}
|
}
|
||||||
const fusion_runtime_t* runtime = &fusion_engine.current;
|
const fusion_runtime_t* runtime = &fusion_engine.current;
|
||||||
output->timestamp_ticks = runtime->filter_timestamp_ticks;
|
output->timestamp_ticks = runtime->filter_timestamp_ticks;
|
||||||
|
output->last_accepted_gps_ticks =
|
||||||
|
runtime->last_accepted_position_ticks;
|
||||||
memcpy(output->position_enu_m, runtime->filter.position_m,
|
memcpy(output->position_enu_m, runtime->filter.position_m,
|
||||||
sizeof(output->position_enu_m));
|
sizeof(output->position_enu_m));
|
||||||
memcpy(output->velocity_enu_mps, runtime->filter.velocity_mps,
|
memcpy(output->velocity_enu_mps, runtime->filter.velocity_mps,
|
||||||
|
|||||||
@@ -114,9 +114,10 @@ static uint32_t gps_nav_ready_channel_mask(void)
|
|||||||
uint32_t status = trck_ips[i]->STATUS_REG;
|
uint32_t status = trck_ips[i]->STATUS_REG;
|
||||||
uint32_t control = trck_ips[i]->CONTROL_REG;
|
uint32_t control = trck_ips[i]->CONTROL_REG;
|
||||||
bool busy = (status & (1u << GPS_TRCK_BUSY_POS)) != 0u;
|
bool busy = (status & (1u << GPS_TRCK_BUSY_POS)) != 0u;
|
||||||
|
bool locked = (status & (1u << GPS_TRCK_LOCK_POS)) != 0u;
|
||||||
bool nav_irq_enabled =
|
bool nav_irq_enabled =
|
||||||
(control & (1u << GPS_TRCK_NAV_SOLVE_INTR_EN_POS)) != 0u;
|
(control & (1u << GPS_TRCK_NAV_SOLVE_INTR_EN_POS)) != 0u;
|
||||||
if(tracking_allocated[i] && busy && nav_irq_enabled)
|
if(tracking_allocated[i] && busy && locked && nav_irq_enabled)
|
||||||
{
|
{
|
||||||
ready_mask |= 1u << i;
|
ready_mask |= 1u << i;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -579,13 +579,13 @@ static void gps_enable_nav_solve_for_snapshot_locked(const unsigned char snapsho
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int gps_collect_busy_tracking_locked(
|
static unsigned int gps_collect_tracked_channels_locked(
|
||||||
unsigned int tracked_prns[GPS_TRCK_IP_COUNT])
|
unsigned int tracked_prns[GPS_TRCK_IP_COUNT])
|
||||||
{
|
{
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
for(unsigned char i = 0 ; i < GPS_TRCK_IP_COUNT ; i++)
|
for(unsigned char i = 0 ; i < GPS_TRCK_IP_COUNT ; i++)
|
||||||
{
|
{
|
||||||
if(trck_ips[i]->STATUS_REG & (1u << GPS_TRCK_BUSY_POS))
|
if(gps_tracking_ip_alive(i))
|
||||||
{
|
{
|
||||||
if(tracked_prns != NULL)
|
if(tracked_prns != NULL)
|
||||||
{
|
{
|
||||||
@@ -1099,11 +1099,11 @@ bool calculate_position(gps_nav_solution_t* solution_out,
|
|||||||
bool run_nav = false;
|
bool run_nav = false;
|
||||||
bool initial_run = false;
|
bool initial_run = false;
|
||||||
unsigned int ready_count;
|
unsigned int ready_count;
|
||||||
unsigned int busy_count;
|
unsigned int tracked_count;
|
||||||
unsigned int tracked_prns[GPS_TRCK_IP_COUNT];
|
unsigned int tracked_prns[GPS_TRCK_IP_COUNT];
|
||||||
unsigned int coherent_nav_count = 0;
|
unsigned int coherent_nav_count = 0;
|
||||||
static uint64_t last_nav_status_log_tick = 0;
|
static uint64_t last_nav_status_log_tick = 0;
|
||||||
static unsigned int last_nav_status_busy_count = GPS_TRCK_IP_COUNT + 1u;
|
static unsigned int last_nav_status_tracked_count = GPS_TRCK_IP_COUNT + 1u;
|
||||||
static unsigned int last_nav_status_ready_count = GPS_TRCK_IP_COUNT + 1u;
|
static unsigned int last_nav_status_ready_count = GPS_TRCK_IP_COUNT + 1u;
|
||||||
static unsigned int last_nav_status_coherent_count = GPS_TRCK_IP_COUNT + 1u;
|
static unsigned int last_nav_status_coherent_count = GPS_TRCK_IP_COUNT + 1u;
|
||||||
|
|
||||||
@@ -1117,7 +1117,7 @@ bool calculate_position(gps_nav_solution_t* solution_out,
|
|||||||
|
|
||||||
ready_count = gps_collect_nav_snapshot_locked(
|
ready_count = gps_collect_nav_snapshot_locked(
|
||||||
snapshot, snapshot_ips, NULL, false, false);
|
snapshot, snapshot_ips, NULL, false, false);
|
||||||
busy_count = gps_collect_busy_tracking_locked(
|
tracked_count = gps_collect_tracked_channels_locked(
|
||||||
GPS_DEBUG_ENABLED(DEBUG_CHANNELS) ? tracked_prns : NULL);
|
GPS_DEBUG_ENABLED(DEBUG_CHANNELS) ? tracked_prns : NULL);
|
||||||
|
|
||||||
if(ready_count < MIN_NEEDED_SATELLITE)
|
if(ready_count < MIN_NEEDED_SATELLITE)
|
||||||
@@ -1197,19 +1197,19 @@ bool calculate_position(gps_nav_solution_t* solution_out,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t now = gps_get_systick();
|
uint64_t now = gps_get_systick();
|
||||||
if((busy_count != last_nav_status_busy_count) ||
|
if((tracked_count != last_nav_status_tracked_count) ||
|
||||||
(ready_count != last_nav_status_ready_count) ||
|
(ready_count != last_nav_status_ready_count) ||
|
||||||
(coherent_nav_count != last_nav_status_coherent_count) ||
|
(coherent_nav_count != last_nav_status_coherent_count) ||
|
||||||
((now - last_nav_status_log_tick) >= GPS_NAV_STATUS_LOG_PERIOD_TICKS))
|
((now - last_nav_status_log_tick) >= GPS_NAV_STATUS_LOG_PERIOD_TICKS))
|
||||||
{
|
{
|
||||||
GPS_LOG(DEBUG_DEBUG, GPS_LOG_CAT_NAV, "busy channels=%u ready channels=%u coherent_nav=%u\r\n",
|
GPS_LOG(DEBUG_DEBUG, GPS_LOG_CAT_NAV, "tracked channels=%u ready channels=%u coherent_nav=%u\r\n",
|
||||||
busy_count, ready_count, coherent_nav_count);
|
tracked_count, ready_count, coherent_nav_count);
|
||||||
last_nav_status_busy_count = busy_count;
|
last_nav_status_tracked_count = tracked_count;
|
||||||
last_nav_status_ready_count = ready_count;
|
last_nav_status_ready_count = ready_count;
|
||||||
last_nav_status_coherent_count = coherent_nav_count;
|
last_nav_status_coherent_count = coherent_nav_count;
|
||||||
last_nav_status_log_tick = now;
|
last_nav_status_log_tick = now;
|
||||||
}
|
}
|
||||||
(void)busy_count;
|
(void)tracked_count;
|
||||||
|
|
||||||
if(run_nav)
|
if(run_nav)
|
||||||
{
|
{
|
||||||
@@ -1231,7 +1231,7 @@ bool calculate_position(gps_nav_solution_t* solution_out,
|
|||||||
uint64_t nav_software_cycles = gps_read_cycle_counter() - nav_software_start_cycles;
|
uint64_t nav_software_cycles = gps_read_cycle_counter() - nav_software_start_cycles;
|
||||||
if(nav_ok)
|
if(nav_ok)
|
||||||
{
|
{
|
||||||
nav_solution.tracked_satellite_count = busy_count;
|
nav_solution.tracked_satellite_count = tracked_count;
|
||||||
uint64_t measurement_timestamp = gps_nav_median_local_timestamp(
|
uint64_t measurement_timestamp = gps_nav_median_local_timestamp(
|
||||||
snapshot_local_timestamps, satellite_count);
|
snapshot_local_timestamps, satellite_count);
|
||||||
if(measurement_timestamp != 0u)
|
if(measurement_timestamp != 0u)
|
||||||
@@ -1304,8 +1304,8 @@ bool calculate_position(gps_nav_solution_t* solution_out,
|
|||||||
if(GPS_DEBUG_ENABLED(DEBUG_CHANNELS))
|
if(GPS_DEBUG_ENABLED(DEBUG_CHANNELS))
|
||||||
{
|
{
|
||||||
GPS_LOG(DEBUG_CHANNELS, GPS_LOG_CAT_TRK,
|
GPS_LOG(DEBUG_CHANNELS, GPS_LOG_CAT_TRK,
|
||||||
"tracked satellites=%u prns=[", busy_count);
|
"tracked satellites=%u prns=[", tracked_count);
|
||||||
for(unsigned int i = 0 ; i < busy_count ; i++)
|
for(unsigned int i = 0 ; i < tracked_count ; i++)
|
||||||
{
|
{
|
||||||
PRINT_DEBUG(DEBUG_CHANNELS, "%s%u",
|
PRINT_DEBUG(DEBUG_CHANNELS, "%s%u",
|
||||||
(i == 0u) ? "" : ",", tracked_prns[i]);
|
(i == 0u) ? "" : ",", tracked_prns[i]);
|
||||||
|
|||||||
@@ -216,12 +216,13 @@ bool imu_sensor_init(const imu_sensor_config_t* config)
|
|||||||
#elif defined(IMU_SENSOR_BUILD_ST)
|
#elif defined(IMU_SENSOR_BUILD_ST)
|
||||||
return try_st(config);
|
return try_st(config);
|
||||||
#else
|
#else
|
||||||
/* WHO_AM_I probing is read-only until a matching backend is found. */
|
/* WHO_AM_I probing is read-only until a matching backend is found.
|
||||||
if(try_tdk(config))
|
* Prefer the Genesys2 STEVAL/LSM6DSOX path when both devices respond. */
|
||||||
|
if(try_st(config))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return try_st(config);
|
return try_tdk(config);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,36 @@ static void assembly_waits_for_every_ready_channel(void)
|
|||||||
"assembly lost a ready-channel interrupt");
|
"assembly lost a ready-channel interrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void busy_unlocked_channel_does_not_block_epoch(void)
|
||||||
|
{
|
||||||
|
gps_nav_epoch_assembly_t assembly;
|
||||||
|
gps_nav_epoch_assembly_reset(&assembly);
|
||||||
|
|
||||||
|
/* Model the board failure: channels 0..8 are allocated and busy, but
|
||||||
|
* channel 4 has lost lock and therefore cannot produce this NAV epoch. */
|
||||||
|
const uint32_t allocated_busy_mask = 0x1ffu;
|
||||||
|
const uint32_t locked_mask = allocated_busy_mask & ~(1u << 4);
|
||||||
|
const uint32_t ready_mask = allocated_busy_mask & locked_mask;
|
||||||
|
|
||||||
|
for(unsigned int channel = 0u ; channel < 9u ; channel++)
|
||||||
|
{
|
||||||
|
if((ready_mask & (1u << channel)) == 0u)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
gps_nav_epoch_event_result_t result =
|
||||||
|
gps_nav_epoch_assembly_push(
|
||||||
|
&assembly, 1500u, channel, ready_mask);
|
||||||
|
bool last = channel == 8u;
|
||||||
|
CHECK((result == GPS_NAV_EPOCH_EVENT_COMPLETE) == last,
|
||||||
|
"busy unlocked channel blocked a complete locked-channel epoch");
|
||||||
|
}
|
||||||
|
CHECK(assembly.expected_mask == 0x1efu,
|
||||||
|
"busy unlocked channel entered the ready mask");
|
||||||
|
CHECK(assembly.received_mask == assembly.expected_mask,
|
||||||
|
"locked channels did not complete the epoch");
|
||||||
|
}
|
||||||
|
|
||||||
static void assembly_handles_duplicates_and_epoch_order(void)
|
static void assembly_handles_duplicates_and_epoch_order(void)
|
||||||
{
|
{
|
||||||
gps_nav_epoch_assembly_t assembly;
|
gps_nav_epoch_assembly_t assembly;
|
||||||
@@ -458,6 +488,7 @@ int main(void)
|
|||||||
{
|
{
|
||||||
epoch_id_rounding_and_week_wrap();
|
epoch_id_rounding_and_week_wrap();
|
||||||
assembly_waits_for_every_ready_channel();
|
assembly_waits_for_every_ready_channel();
|
||||||
|
busy_unlocked_channel_does_not_block_epoch();
|
||||||
assembly_handles_duplicates_and_epoch_order();
|
assembly_handles_duplicates_and_epoch_order();
|
||||||
assembly_disconnect_and_reconnect();
|
assembly_disconnect_and_reconnect();
|
||||||
channel_join_does_not_expand_active_epoch();
|
channel_join_does_not_expand_active_epoch();
|
||||||
|
|||||||
Reference in New Issue
Block a user