1. Algorithm description
NeuraDrive library allows to perform driving tracking analysis and extrapolate information regarding driving style of the driver, road surface conditions and turns detection. NeuraDrive is a IMU-based solution that exploits only linear accelerations and angular velocity readings, measured in mg and dps, respectively and sampled @50Hz. NeuraDrive requires a single inertial sensor, that has to be firmly fixed on the vehicle, for all the time of the acquisition: in this library parameters and thresholds have been specifically adapted for a device application on the vehicle windshield, inside the passenger compartment. More details on this topic are explained in calibration section.
In DRV_Parameters.h parameters and constants used within DRV_Tracker logic are defined. The following operation can be done:
- DRV_ResetParameters has to be called during initialization of the library to reset all the alogrithm parameters at pre-defined and documented values;
- DRV_SetParameters can be called in order to modify algorithm parameters: run this command at user’s own risk;
- DRV_GetParameters can be called in order to get parameter values.
NeuraDrive integration requires only a few lines of code, which implement the following functionalities:
- Initialization ad setting parameter phases have to be completed before running the algorithm:
- with DRV_ResetParameters algorithm parameters are initialized. For more information please see DRV_Parameters.h section.
- with DRV_Init algorithms variables are initialized. This function has to be called each time the sampling period elapses.
- with DRV_CalibOnWindshield_Init device orientation quaternion variables are initialized. This function has to be called each time the orientation on the windshield changes.
- In DRV_Update all major functionalities and features are computed: as depicted in the AlgorithmFlowchart, five main blocks are present: compensation section, operating condition, driving style, road surface and turns event detection and respective classification.DRV_Update has to be called on each iteration.
- Compensation section consists in the following logic:
device orientation is automatically estimated in quaternion form (both tilting qT and heading qH quaternions) exploiting an acceleration acquisition during a static phase, acquired in the firsts seconds of acquisition. This operation is mandatory for a correct alignment of the device reference system with respect to the vehicle one as depicted in FIGURE1, and therefore a correct computation of the features. The management of this function is let to the user: the estimation can be performed only one single time since the device has been fixed in a certain position on the windshield. The estimation will not be repeated until the function DRV_CalibOnWindshield_Init will be called again. In this version a position of the device with gravity mainly located on the accelerometer z-axis direction (upward or downward) is mandatory for a correct algorithm response. Device positioning that do not are than those recommended could lead to a wrong and unwanted results. - Driving operating condition detection is a section where static phases and driving phases are detected.
- Compensation section consists in the following logic:
- Results, in terms of value over time, can be achieved calling the functions: DRV_GetDrivingStyle,DRV_GetRoadSurface and DRV_GetTurns.
In DRV_Statistics.h commands to achieve statistics on events of interest are documented. Statistics command have to be called after DRV_Update function. With DRV_Stat_Init counters for statistic purpose are erased.
- For driving style statistics, the number of event can be read for each class with “get” commands
(see DRV_Stat_GetDrivingStyleNORMAL, DRV_Stat_GetDrivingStyleMODERATE, DRV_Stat_GetDrivingStyleFAST); - For road surface statistics, the number of event can be read for each class with “get” commands
(see DRV_Stat_GetRoadSurfaceNORMAL, DRV_Stat_GetRoadSurfaceMODERATE, DRV_Stat_GetRoadSurfaceHARD); - For turn statistics the number of event can be read for each class with “get” commands
(see DRV_Stat_GetTurnRIGHT, DRV_Stat_GetTurnLEFT, DRV_Stat_GetTurnSWINGING); - DRV_Stat_Init command has to be called each time the counters want to be erased.
FIGURE 1.1 VEHICLE REFERENCE SYSTEM CONVENTION
2. Flowchart
The following block diagram describes the flow of operations that implement the NeuraDrive logic.
FIGURE 2.1 TRACKING ALGORITHM FLOWCHART
The following block diagram describes NeuraDrive statistics functioning.
FIGURE 2.2 DRIVING TRACKER EVENTS STATISTICS FLOWCHART
3. References
The following lines contain general information about the library, such as version and date of publication, together with the contact details of the 221e internal staff responsible for maintaining and managing the library.
-
Authors and Referents
Giorgio Barzon
Roberto Bortoletto -
Library Version
v1.0.0 -
Date
July 2022 -
Copyright
Copyright (c) 2020 All Rights Reserved by 221e srl. [email protected]
4. Requirements
The following lines contain information about the library size occupation and time execution. Tests and measurements have been perfomed with a NUCLEO-L476RG board, clocked @64MHz, and including within Atollic TrueSTUDIO project the NeuraDrive static library compiled for NUCLEO-L476RG as well as library header files. No optimization (i.e., -O0) has been applied during library compilation. Results are reported in the following tables.
FLASH Occupation [kB] | RAM Occupation [kB] |
---|---|
40.59 | 1.96 |
TABLE 4.1 DRV MEMORY OCCUPATION
Timing [clock hits] | Timing @64MHz [ms] | |
---|---|---|
DRV_Update + all get functions in DRV_Example.c |
Average: 10533, Maximum: 12176 | Average: 0.165, Maximum: 0.190 |
DRV_Init | Average: 1546, Maximum: 1620 | Average: 0.024, Maximum: 0.025 |
DRV_ResetParameters + DRV_CalibOnWindshield_Init + DRV_Stat_Init |
Average: 928, Maximum: 999 | Average: 0.015, Maximum: 0.016 |
TABLE 4.2 DRV EXECUTIONS TIMINGS
5. Example Documentation
5.1 DRV_Example.c
This is an example of library usage for NeuraDrive logic with accelerometer and gyroscope data. The data were acquired with the 221e Muse device, installed on a car windshield. The test was performed completing a known path and performing some braking events in order to trigger the logic. An example of the result obtained is depicted in Example Figure. The following lines show how the library was executed on the collected data.
FIGURE 5.1 OUTPUT EXAMPLE
#include<stdio.h> // Include C standard libraries #include "DRV_Tracker.h" // Include DRV_Tracker.h library #include "DRV_Statistics.h" // Include DRV_Statistics.h library #include "DRV_Parameters.h" // Include DRV_Parameters.h library #define inputDataLength 6 // Define input data lenght float inputData[inputDataLength] = { 0, 0, 0, 0, 0 }; // Initialize input data array: Gyr [dps] and Axl [mg] triplets uint32_t iterationCounter = 0; // Initialize iterationCounter #define Erase_Statistics_time_lenght 3000 // Erase statistics, for example, every 10 minutes (@50Hz) int main(void) { FILE *fIn = fopen("input_data.txt", "r"); // Open input file FILE *fOut = fopen("output_data.txt", "w"); // Open output file DRV_ResetParameters(); // DRV_ResetParameters call. It resets algoritm parameters DRV_Init(); // DRV_Init call. It initializes algorithm variables DRV_CalibOnWindshield_Init(); // DRV_Update call. It resets calibration variables DRV_Stat_Init(); // DRV_Stat_Init call. It resets statistics // While loop while (feof(fIn) == 0) { uint8_t i; // Support variable // Read current data for (i = 0; i < inputDataLength; i++) fscanf(fIn, "%f", &inputData[i]); // Read data: Acc.X Acc.Y Acc.Z Gyr.X Gyr.Y Gyr.Z float inAxl[3] = { inputData[0], inputData[1], inputData[2] }; float inGyr[3] = { inputData[3], inputData[4], inputData[5] }; DRV_Update(inAxl, inGyr); // DRV_Update call DRV_DRIVING_STYLE Driving_style_out = DRV_GetDrivingStyle(); // DRV_GetDrivingStyle call DRV_ROADSURFACE_CLASS Road_surface_out = DRV_GetRoadSurface(); // DRV_GetRoadSurface call DRV_TURNS_TYPE Turns_out = DRV_GetTurns(); // DRV_GetTurns call uint32_t Get_style_NORMAL = DRV_Stat_GetDrivingStyleNORMAL(); // Get cumulative "NORMAL" driving style events uint32_t Get_style_MODERATE = DRV_Stat_GetDrivingStyleMODERATE(); // Get cumulative "MODERATE" driving style events uint32_t Get_style_FAST = DRV_Stat_GetDrivingStyleFAST(); // Get cumulative "HARD" driving style events uint32_t Get_surface_NORMAL = DRV_Stat_GetRoadSurfaceNORMAL(); // Get cumulative "NORMAL" road surface events uint32_t Get_surface_MODERATE = DRV_Stat_GetRoadSurfaceMODERATE(); // Get cumulative "MODERATE" road surface events uint32_t Get_surface_HARD = DRV_Stat_GetRoadSurfaceHARD(); // Get cumulative "HARD" road surface events uint32_t Get_turn_LEFT = DRV_Stat_GetTurnLEFT(); // Get cumulative "LEFT" turn events uint32_t Get_turn_RIGHT = DRV_Stat_GetTurnRIGHT(); // Get cumulative "RIGHT" turn events uint32_t Get_turn_SWING = DRV_Stat_GetTurnSWINGING(); // Get cumulative "SWINGING" turn events if(iterationCounter % Erase_Statistics_time_lenght == 0){ // Erase statistics each defined time period DRV_Stat_Init(); // DRV_Stat_Init call } fprintf(fOut, "%dnt", Driving_style_out); // Print Driving_style_out result on output file fprintf(fOut, "%dnt", Road_surface_out); // Print Road_surface_out result on output file fprintf(fOut, "%dnt", Turns_out); // Print Turns_out result on output file fprintf(fOut, "%dnt", Get_style_NORMAL); // Print Get_style_NORMAL result on output file fprintf(fOut, "%dnt", Get_style_MODERATE); // Print Get_style_MODERATE result on output file fprintf(fOut, "%dnt", Get_style_FAST); // Print Get_style_FAST result on output file fprintf(fOut, "%dnt", Get_surface_NORMAL); // Print Get_surface_NORMAL result on output file fprintf(fOut, "%dnt", Get_surface_MODERATE); // Print Get_surface_MODERATE result on output file fprintf(fOut, "%dnt", Get_surface_HARD); // Print Get_surface_HARD result on output file fprintf(fOut, "%dnt", Get_turn_LEFT); // Print Get_turn_LEFT result on output file fprintf(fOut, "%dnt", Get_turn_RIGHT); // Print Get_turn_RIGHT result on output file fprintf(fOut, "%dnn", Get_turn_SWING); // Print Get_turn_SWING result on output file iterationCounter++; // Increment iteration counter } // Close I/O files fclose(fIn); fclose(fOut); return 0; }