xioTechnologies / Fusion

MIT License
913 stars 230 forks source link

Need some help setting up the algorithm. #167

Closed brightproject closed 1 month ago

brightproject commented 1 month ago

Thanks to the team @xioTechnologies I succeeded to test a simple implementation of the xioTechnologies fusion sensor. I'm getting raw gyroscope angular velocity and accelerometer acceleration data from the FlightGear flight simulator. Background here. I managed to compile a simple example for stm32f411, for compilation I used the Arduino platform(using a combination of arduino-cli + visual studio. Raw data sampling from avia sim FlightGear - acceleration in m/s/s, gyro rates in rad/sec. I convert the data into the xioTechnologies.

      ax = -x_accel; // 9.81 m/s/s
      ay = y_accel; // 9.81 m/s/s
      az = -z_accel; // 9.81 m/s/s

      ax /= G;
      ay /= G;
      az /= G;

      gx = roll_rad_sec; // rad/sec
      gy = pitch_rad_sec; // rad/sec
      gz = yaw_rad_sec; // rad/sec

      gx *= RAD_TO_DEG; // deg/sec
      gy *= RAD_TO_DEG; // deg/sec
      gz *= RAD_TO_DEG; // deg/sec

performed at about 30-40 Hz. 40_samples_in_second

I set these values: #define SAMPLE_PERIOD (0.04f) // 40Hz. I tried also the following values: #define SAMPLE_PERIOD (0.005f) // replace this with actual sample period With the last value of 0.005 the algorithm is more efficient. Perhaps I think this meaning is wrong? Example code I'm using.

#include <Fusion.h>
#include <stdbool.h>
#include <stdio.h>

// #define PRINTF

#define SAMPLE_PERIOD (0.005f)

#define SERIAL_BAUD 115200

FusionAhrs ahrs;

void setup() {

    Serial.begin(SERIAL_BAUD);// PA9, PA10

    FusionAhrsInitialise(&ahrs);

}

void loop() { // this loop should repeat each time new gyroscope data is available
        const FusionVector gyroscope = {0.2f, 1.3f, 0.0f}; // replace this with actual gyroscope data in degrees/s
        const FusionVector accelerometer = {0.0f, 0.0f, 1.0f}; // replace this with actual accelerometer data in g

        FusionAhrsUpdateNoMagnetometer(&ahrs, gyroscope, accelerometer, SAMPLE_PERIOD);

        const FusionEuler euler = FusionQuaternionToEuler(FusionAhrsGetQuaternion(&ahrs));

        #ifdef PRINTF

        printf("Roll %0.1f, Pitch %0.1f, Yaw %0.1f\n", euler.angle.roll, euler.angle.pitch, euler.angle.yaw);

        #else

        Serial.print(" \tEiler Roll: ");
        Serial.print(euler.angle.roll);
        Serial.print(" \tEiler Pitch: ");
        Serial.print(euler.angle.pitch);
        Serial.print(" \tEiler Yaw: ");
        Serial.println(euler.angle.yaw);

        #endif
}

I tried different parameters from, but did not notice any significant differences.

void FusionAhrsInitialise(FusionAhrs *const ahrs) {
    const FusionAhrsSettings settings = {
            .convention = FusionConventionNwu,
            // .convention = FusionConventionEnu,
            // .convention = FusionConventionNed,
            .gain = 0.5f,
            // .gain = 0.01f,
            .gyroscopeRange = 0.0f,
            // .gyroscopeRange = 250.0f,
            // .gyroscopeRange = 500.0f,
            // .gyroscopeRange = 1000.0f,
            // .gyroscopeRange = 2000.0f,
            .accelerationRejection = 10.0f,
            // .accelerationRejection = 0.0f,
            // .magneticRejection = 90.0f,
            .magneticRejection = 0.0f,
            .recoveryTriggerPeriod = 10,
    };
    FusionAhrsSetSettings(ahrs, &settings);
    FusionAhrsReset(ahrs);
}

I get the following values ​​for calculating orientation angles for a prolonged right roll. It can be seen that in the presence of gyroscopic speed around the X axis, the right roll angle begins to increase. When the roll angle reaches +19.135 degrees, the roll angle begins to decrease, although the angular velocity of rotation around the X axis is still there. The smallest angular velocity around the X axis will be gyro_x: 0.000190 and then the plane begins to turn left along the roll and levels out. It seems as if the algorithm calculates the roll angle normally at first, but then the acceleration factor along the Z axis begins to influence prematurely and the acceleration value exceeds 1G.

gyro_x: 0.079272 gyro_y: 0.024222 gyro_z: 0.042755 accel_x: 0.886400 accel_y: -0.038900 accel_z: -10.783700 roll: 18.688908 pitch: 5.459363 yaw: 53.302647
gyro_x: 0.079017 gyro_y: 0.024652 gyro_z: 0.043105 accel_x: 0.891100 accel_y: -0.037300 accel_z: -10.808900 roll: 18.766769 pitch: 5.478175 yaw: 53.402813
gyro_x: 0.076831 gyro_y: 0.025038 gyro_z: 0.043397 accel_x: 0.899000 accel_y: -0.032100 accel_z: -10.844100 roll: 18.839531 pitch: 5.497517 yaw: 53.503849
gyro_x: 0.074344 gyro_y: 0.025351 gyro_z: 0.043627 accel_x: 0.903300 accel_y: -0.033900 accel_z: -10.860000 roll: 18.906313 pitch: 5.517223 yaw: 53.605564
gyro_x: 0.070630 gyro_y: 0.025731 gyro_z: 0.043904 accel_x: 0.908800 accel_y: -0.039200 accel_z: -10.879600 roll: 18.964283 pitch: 5.537444 yaw: 53.708092
gyro_x: 0.067443 gyro_y: 0.026027 gyro_z: 0.044111 accel_x: 0.912800 accel_y: -0.045800 accel_z: -10.895100 roll: 19.014627 pitch: 5.558025 yaw: 53.811214
gyro_x: 0.064154 gyro_y: 0.026311 gyro_z: 0.044303 accel_x: 0.916600 accel_y: -0.053300 accel_z: -10.910000 roll: 19.057135 pitch: 5.578962 yaw: 53.914906
gyro_x: 0.060023 gyro_y: 0.026651 gyro_z: 0.044522 accel_x: 0.921300 accel_y: -0.063200 accel_z: -10.928300 roll: 19.089867 pitch: 5.600383 yaw: 54.019230
gyro_x: 0.055879 gyro_y: 0.026970 gyro_z: 0.044717 accel_x: 0.926500 accel_y: -0.072500 accel_z: -10.946300 roll: 19.112890 pitch: 5.622297 yaw: 54.124157
gyro_x: 0.053182 gyro_y: 0.027152 gyro_z: 0.044823 accel_x: 0.930000 accel_y: -0.077000 accel_z: -10.956700 roll: 19.129620 pitch: 5.644445 yaw: 54.229370
gyro_x: 0.048612 gyro_y: 0.027438 gyro_z: 0.044981 accel_x: 0.934600 accel_y: -0.086700 accel_z: -10.973800 roll: 19.135740 pitch: 5.667049 yaw: 54.335079
gyro_x: 0.045047 gyro_y: 0.027650 gyro_z: 0.045091 accel_x: 0.938100 accel_y: -0.094600 accel_z: -10.987300 roll: 19.133619 pitch: 5.689977 yaw: 54.441120
gyro_x: 0.038414 gyro_y: 0.028031 gyro_z: 0.045268 accel_x: 0.944700 accel_y: -0.110000 accel_z: -11.013800 roll: 19.116173 pitch: 5.713623 yaw: 54.547726
gyro_x: 0.034677 gyro_y: 0.028240 gyro_z: 0.045352 accel_x: 0.948900 accel_y: -0.118600 accel_z: -11.030400 roll: 19.090206 pitch: 5.737655 yaw: 54.654598
gyro_x: 0.031920 gyro_y: 0.028390 gyro_z: 0.045407 accel_x: 0.952300 accel_y: -0.124600 accel_z: -11.043700 roll: 19.058054 pitch: 5.761963 yaw: 54.761662
gyro_x: 0.028756 gyro_y: 0.028560 gyro_z: 0.045461 accel_x: 0.956600 accel_y: -0.131100 accel_z: -11.061800 roll: 19.018816 pitch: 5.786613 yaw: 54.868889
gyro_x: 0.026438 gyro_y: 0.028701 gyro_z: 0.045496 accel_x: 0.960000 accel_y: -0.135500 accel_z: -11.088400 roll: 18.974508 pitch: 5.811517 yaw: 54.976250
gyro_x: 0.024297 gyro_y: 0.028836 gyro_z: 0.045524 accel_x: 0.963500 accel_y: -0.139300 accel_z: -11.101000 roll: 18.925570 pitch: 5.836712 yaw: 55.083717
gyro_x: 0.021851 gyro_y: 0.028983 gyro_z: 0.045551 accel_x: 0.967900 accel_y: -0.143300 accel_z: -11.115300 roll: 18.871323 pitch: 5.862256 yaw: 55.191280
gyro_x: 0.020065 gyro_y: 0.029084 gyro_z: 0.045567 accel_x: 0.971400 accel_y: -0.145900 accel_z: -11.127600 roll: 18.813347 pitch: 5.888044 yaw: 55.298931
gyro_x: 0.018418 gyro_y: 0.029172 gyro_z: 0.045579 accel_x: 0.975000 accel_y: -0.148100 accel_z: -11.140100 roll: 18.751966 pitch: 5.914055 yaw: 55.406601
gyro_x: 0.016898 gyro_y: 0.029248 gyro_z: 0.045587 accel_x: 0.978600 accel_y: -0.150000 accel_z: -11.152900 roll: 18.687515 pitch: 5.940273 yaw: 55.514317
gyro_x: 0.015162 gyro_y: 0.029329 gyro_z: 0.045594 accel_x: 0.983200 accel_y: -0.151800 accel_z: -11.169200 roll: 18.619509 pitch: 5.966733 yaw: 55.622036
gyro_x: 0.013590 gyro_y: 0.029394 gyro_z: 0.045597 accel_x: 0.987700 accel_y: -0.153300 accel_z: -11.185600 roll: 18.548357 pitch: 5.993403 yaw: 55.729771
gyro_x: 0.012441 gyro_y: 0.029437 gyro_z: 0.045598 accel_x: 0.991200 accel_y: -0.154200 accel_z: -11.198800 roll: 18.475046 pitch: 6.020222 yaw: 55.837490
gyro_x: 0.011378 gyro_y: 0.029472 gyro_z: 0.045597 accel_x: 0.994700 accel_y: -0.155000 accel_z: -11.211900 roll: 18.399782 pitch: 6.047176 yaw: 55.945190
gyro_x: 0.010160 gyro_y: 0.029506 gyro_z: 0.045594 accel_x: 0.999200 accel_y: -0.155600 accel_z: -11.228300 roll: 18.322224 pitch: 6.074287 yaw: 56.052868
gyro_x: 0.008845 gyro_y: 0.029534 gyro_z: 0.045588 accel_x: 1.004500 accel_y: -0.156200 accel_z: -11.247600 roll: 18.242163 pitch: 6.101564 yaw: 56.160488
gyro_x: 0.007857 gyro_y: 0.029548 gyro_z: 0.045581 accel_x: 1.008900 accel_y: -0.156500 accel_z: -11.264800 roll: 18.160372 pitch: 6.128962 yaw: 56.268082
gyro_x: 0.006957 gyro_y: 0.029581 gyro_z: 0.045573 accel_x: 1.013100 accel_y: -0.156700 accel_z: -11.293800 roll: 18.077055 pitch: 6.156481 yaw: 56.375622
gyro_x: 0.006293 gyro_y: 0.029605 gyro_z: 0.045566 accel_x: 1.016400 accel_y: -0.156700 accel_z: -11.303500 roll: 17.992764 pitch: 6.184131 yaw: 56.483135
gyro_x: 0.005675 gyro_y: 0.029621 gyro_z: 0.045558 accel_x: 1.019700 accel_y: -0.156700 accel_z: -11.313100 roll: 17.907600 pitch: 6.211894 yaw: 56.590595
gyro_x: 0.005100 gyro_y: 0.029628 gyro_z: 0.045549 accel_x: 1.023100 accel_y: -0.156600 accel_z: -11.323000 roll: 17.821680 pitch: 6.239757 yaw: 56.697998
gyro_x: 0.004564 gyro_y: 0.029628 gyro_z: 0.045540 accel_x: 1.026500 accel_y: -0.156500 accel_z: -11.333000 roll: 17.735085 pitch: 6.267701 yaw: 56.805328
gyro_x: 0.003944 gyro_y: 0.029619 gyro_z: 0.045527 accel_x: 1.030500 accel_y: -0.156300 accel_z: -11.345200 roll: 17.647633 pitch: 6.295725 yaw: 56.912590
gyro_x: 0.003374 gyro_y: 0.029601 gyro_z: 0.045514 accel_x: 1.034500 accel_y: -0.156100 accel_z: -11.357400 roll: 17.559450 pitch: 6.323810 yaw: 57.019787
gyro_x: 0.003054 gyro_y: 0.029586 gyro_z: 0.045505 accel_x: 1.036900 accel_y: -0.155900 accel_z: -11.364500 roll: 17.471092 pitch: 6.351924 yaw: 57.126881
gyro_x: 0.002555 gyro_y: 0.029556 gyro_z: 0.045490 accel_x: 1.040700 accel_y: -0.155600 accel_z: -11.376300 roll: 17.382170 pitch: 6.380070 yaw: 57.233902
gyro_x: 0.001834 gyro_y: 0.029495 gyro_z: 0.045465 accel_x: 1.046800 accel_y: -0.155000 accel_z: -11.394600 roll: 17.292181 pitch: 6.408237 yaw: 57.340775
gyro_x: 0.001428 gyro_y: 0.029450 gyro_z: 0.045448 accel_x: 1.050500 accel_y: -0.154600 accel_z: -11.405500 roll: 17.201849 pitch: 6.436405 yaw: 57.447556
gyro_x: 0.001124 gyro_y: 0.029409 gyro_z: 0.045433 accel_x: 1.053400 accel_y: -0.154300 accel_z: -11.412100 roll: 17.111393 pitch: 6.464568 yaw: 57.554218
gyro_x: 0.000838 gyro_y: 0.029376 gyro_z: 0.045418 accel_x: 1.056200 accel_y: -0.153900 accel_z: -11.433400 roll: 17.020870 pitch: 6.492702 yaw: 57.660809
gyro_x: 0.000502 gyro_y: 0.029345 gyro_z: 0.045399 accel_x: 1.059700 accel_y: -0.153500 accel_z: -11.436300 roll: 16.930153 pitch: 6.520882 yaw: 57.767277
gyro_x: 0.000190 gyro_y: 0.029292 gyro_z: 0.045379 accel_x: 1.063100 accel_y: -0.153000 accel_z: -11.447100 roll: 16.839315 pitch: 6.549039 yaw: 57.873650
gyro_x: -0.000045 gyro_y: 0.029258 gyro_z: 0.045362 accel_x: 1.065700 accel_y: -0.152600 accel_z: -11.457500 roll: 16.748514 pitch: 6.577186 yaw: 57.979900
gyro_x: -0.000267 gyro_y: 0.029218 gyro_z: 0.045345 accel_x: 1.068300 accel_y: -0.152200 accel_z: -11.461200 roll: 16.657784 pitch: 6.605331 yaw: 58.086071
gyro_x: -0.000477 gyro_y: 0.029172 gyro_z: 0.045327 accel_x: 1.070800 accel_y: -0.151800 accel_z: -11.467800 roll: 16.567160 pitch: 6.633451 yaw: 58.192135

331404192-d8e1a985-3801-4da6-a48b-e4f2b63f5fe0 I also wrote a small Python script for drawing graphs. Initially, the plane makes a right bank, then descends, then gains altitude and makes a left bank. At the very bottom, the orientation angles produced by the simulator are drawn in green; the remaining angles are calculated by the algorithm xioTechnologies. The only thing that coincided was the yaw...albeit a 140-degree shift. matplot_python_pic1

But in video more visual representation compared to text output. https://www.youtube.com/watch?v=cWlsb3izkYQ GUI on Processing from here with minor modifications. At rolls of up to 10 degrees, the algorithm handles the evolutions quite well. But if a prolonged roll begins, then the roll value calculated using the xioTechnologies algorithm first advances ahead of the real roll angle, which is displayed by the PFD Airbus A320, and then begins to return to zero. And when the real roll angle (on the PFD) begins to move in the opposite direction, i.e. the plane levels out in the horizon, the roll value calculated by the xioTechnologies algorithm begins to move in the opposite direction, aggravating the situation. The reason for this is centrifugal acceleration, which cannot be distinguished from gravity. The situation with the pitch angle is approximately the same. I deliberately do not try to use an advanced example because I want to practice the basic settings of the algorithm with a simple example. How can I tell if the algorithm was initialized based on accelerometer and gyroscope data? How to correctly use algorithm flags and how to activate them?

https://github.com/xioTechnologies/Fusion?tab=readme-ov-file#algorithm-flags

Perhaps this behavior of the roll angle during a long turn is typical and normal for an algorithm that uses only a gyroscope and an accelerometer as input data? Can you please tell me how to configure the algorithm to work acceptable with the data obtained from the flight simulation on FlightGear. Or do you recommend going straight to the advanced example and already working on its settings? I need some time, several experiments and tips from(if it is possible) the authors of the algorithm to understand and configure the code properly, first using a simulator, then I want to introduce some noise to simulate real MEMS sensors, and then try the configured algorithm in a real flight with sensors, like BNO055.

xioTechnologies commented 1 month ago

I'm afraid that there is just too much in the post for me to effectively answer. I suggest you start from the simple example which does not require any configuration or setup, and then post your questions or issues so that we deal with them one at a time.

brightproject commented 1 month ago

I'm afraid that there is just too much in the post for me to effectively answer. I suggest you start from the simple example which does not require any configuration or setup, and then post your questions or issues so that we deal with them one at a time.

Thank you for your answer, I really appreciate your support and nothing bad will happen if you can’t help me. Using a simple example, in the post above I slightly changed the output data, if you look at the graphical plotting of the orientation angles obtained from the simulator and calculated by the algorithm. What could be the reason for this manifestation? matplot_python_v3

Left roll, descent, right roll, climb. Blue line - the algorithm calculates, green line - I receive angle data from the simulator.

xioTechnologies commented 1 month ago

As I said, I cannot offer a useful response to your original post. I suggested a way we could proceed but if that does not work for you then I probably won't be able to help.

brightproject commented 1 month ago

As I said, I cannot offer a useful response to your original post. I suggested a way we could proceed but if that does not work for you then I probably won't be able to help.

I recorded data without a magnetometer. sensor_data_v4.csv Ran a simple example, the result is this: Figure_v4

The video shows the flight itself https://www.youtube.com/watch?v=AN81DyVbvak

Have I prepared the gyroscope and accelerometer data correctly for input into the algorithm? The number of samples is still 28 Hz. In the example file sensor_data I see a sampling rate of 100 Hz. Unfortunately, getting raw data from the simulator at a high enough frequency is a big problem. Here's a 35 Hz sample sensor_data_v5.csv Figure_v5

Which is the maximum I can get from FlightGear, despite telling the simulator to output 100 samples per second. C:\Program Files\FlightGear 2020.3\bin>fgfs --generic=serial,out,100,\\.\COM15,230400,insgns-imu2 --aircraft=A320neo-PW I also tried the advanced example, again without a magnetometer, for this I slightly modified the example code by changing these lines:

data = numpy.genfromtxt("sensor_data_v5.csv", delimiter=",", skip_header=1)

sample_rate = 30 # 30 Hz

timestamp = data[:, 0]
gyroscope = data[:, 1:4]
accelerometer = data[:, 4:7]
# magnetometer = data[:, 7:10]
# magnetometer = [1, 1, 1]
magnetometer = [0, 0, 0]
# Convert the list to a numpy array
magnetometer_array = numpy.array(magnetometer)

# Instant algorithms
offset = imufusion.Offset(sample_rate)
ahrs = imufusion.Ahrs()

ahrs.settings = imufusion.Settings(imufusion.CONVENTION_NWU, # convention
 0.5, #gain
 2000, # gyroscope range
 #250, #gyroscope range
 #10, #acceleration rejection
 0, # acceleration rejection
 #10, #magnetic rejection
 0, # magnetic rejection
 5 * sample_rate) # recovery trigger period = 5 seconds

# Process sensor data
delta_time = numpy.diff(timestamp, prepend=timestamp[0])

euler = numpy.empty((len(timestamp), 3))
internal_states = numpy.empty((len(timestamp), 6))
flags = numpy.empty((len(timestamp), 4))

for index in range(len(timestamp)):
 gyroscope[index] = offset.update(gyroscope[index])

 # ahrs.update(gyroscope[index], accelerometer[index], magnetometer[index], delta_time[index])
 ahrs.update(gyroscope[index], accelerometer[index], magnetometer_array, delta_time[index])

The result is as follows: Figure_v5_advanced As far as I understand, the actual roll angle, which the plane was turning towards, was 30 degrees and lasted from x=64 to x=110. For some reason, the algorithm calculated the roll at 88 degrees at the beginning, then decreased to 0, and then became -48 degrees and then returned to 0 again. The situation is similar with the left roll. I would be very grateful for clarification, although it seems to me that the algorithm works fine, and this is apparently its limits. Or am I setting it up incorrectly?

xioTechnologies commented 1 month ago

The CSV columns should be: Time (s),Gyroscope X (deg/s),Gyroscope Y (deg/s),Gyroscope Z (deg/s),Accelerometer X (g),Accelerometer Y (g),Accelerometer Z (g). Your gyroscope and accelerometer columns look ok.

The difference between the first two time values in your CSV file corresponds to a sample rate of 26.36 Hz. simple_example.py includes the expression 1 / 100 on line 37 for a sample rate of 100 Hz. You need to change this to 1 / 26.36 to match your data.

I do not understand the sentence, "The number of samples is still 28 Hz".

I wrote this reply before you edited your post. You have since added allot more your post, confusing the discussion. I can't help you if this is how you are going to communicate.

brightproject commented 1 month ago

I do not understand the sentence, "The number of samples is still 28 Hz".

This means that I made the first data sample and calculated that I get 28 samples/rows per second, and concluded that the sampling rate is 28 Hz. After that, I made a second data sample, and in this I received 35 samples/rows of data per second.

The difference between the first two time values in your CSV file corresponds to a sample rate of 26.36 Hz. simple_example.py includes the expression 1 / 100 on line 37 for a sample rate of 100 Hz. You need to change this to 1 / 26.36 to match your data.

Thanks, I changed the divisor number and got this result. Figure_v5_26_hz I play with the parameters of the algorithm, not yet understanding its operation well enough. But I couldn’t get it to hold the bank angle in a turn for long enough. And the main question here is - the algorithm does not allow you to compensate for centripetal acceleration during rolls and turns, or do I need to study the operation of the algorithm better and adjust it?

xioTechnologies commented 1 month ago

Your questions about configuration, features, and expected behaviour are all moot until you can get the basics working. It sounds like you are not sure what your sample rate is, or even if it is fixed.

Before you do anything else, you need to determine your sample rate and/or the timestamps of measurements.

brightproject commented 1 month ago

Your questions about configuration, features, and expected behaviour are all moot until you can get the basics working. It sounds like you are not sure that your sample rate is, or even if it is fixed.

Before you do anything else, you need to determine your sample rate and/or the timestamps of measurements.

Unfortunately, after writing one question, I continue to search for a solution to the problem, and certainly additional questions arise, and I update/edit/supplement the original request, and can’t do anything about it, please understand and forgive me. Regarding the sample rate issue, because... I use a flight simulator, and for objective reasons I cannot get a sampling frequency from the simulator greater than 40 Hz, then I propose to assume that my samples are at this frequency. Collected data in file

sensor_data_v7.csv

Running a simple example shows that the orientation angles are not stabilized and the roll quickly decreases (this is not even a roll, but a sawtooth movement), although the roll angles are long in nature Figure_1_simple_v7

Advanced example used with the following settings

ahrs.settings = imufusion.Settings(imufusion.CONVENTION_NWU,  # convention
# ahrs.settings = imufusion.Settings(imufusion.CONVENTION_ENU,  # convention
                                   # 0.01,  # gain
                                   # 0.05,  # gain
                                   # 0.6,  # gain
                                   0.008,  # gain
                                   # 0.00000,  # gain
                                   0,  # gyroscope range
                                   # 2000,  # gyroscope range
                                   # 250,  # gyroscope range
                                   1,  # acceleration rejection
                                   # 0,  # acceleration rejection
                                   1,  # magnetic rejection
                                   # 0,  # magnetic rejection
                                   # 5 * sample_rate)  # recovery trigger period = 5 seconds
                                   1)  # recovery trigger period = 5 seconds

The result is as follows Figure_1_advanced_v7_0_008

It can be seen that the bank angle became longer, however, immediately after the right bank, the return to straight flight was not at 0 degrees. And then I noticed some strange things if you specify the parameter 0.00000, # gain Then the picture will be as follows Figure_1_advanced_v7_0_000

It turns out with zero sensitivity, roll angles almost always return to zero degrees, although in fact the lines just narrowed a little along the Y axis and jumped up a little. I also don’t quite understand the following - the plane in the simulator rotated in the bank angle by +-30 degrees. But the simple and advanced example, for unknown reasons, show roll angles of 5 degrees - could you please comment on this? I already looked at the example code, I thought maybe the scaling was wrong somewhere ... but with the test data sensor_data.csv all the angles are normal. My python self-code shows excellent results from the collected data matplot_python_v7

The parameters of the C++ code algorithm are as follows:

const FusionAhrsSettings settings = {
  // info about convention
  // https://github.com/xioTechnologies/Fusion/issues/117#issuecomment-1677998150
          .convention = FusionConventionNwu,
          // .convention = FusionConventionEnu,
          // .convention = FusionConventionNed,
          // .gain = 1.5f,
          // .gain = 0.6f,
          .gain = 0.008f,
          // .gain = 0.0079f,
          .gyroscopeRange = 0.0f, /* replace this with actual gyroscope range in degrees/s */
          // .gyroscopeRange = 250.0f,
          // .gyroscopeRange = 500.0f,
          // .gyroscopeRange = 1000.0f,
          // .gyroscopeRange = 2000.0f,
          // .accelerationRejection = 5.0f,
          .accelerationRejection = 0.0f,
          // .accelerationRejection = 0.6f,
          // .magneticRejection = 90.0f,
          .magneticRejection = 0.0f,
          // .recoveryTriggerPeriod = 0.0f,
          // .recoveryTriggerPeriod = 0.14,
          // .recoveryTriggerPeriod = 0.142,
          // .recoveryTriggerPeriod = 5 * SAMPLE_PERIOD, /* 5 seconds */
          // .recoveryTriggerPeriod = 37500 * SAMPLE_PERIOD, /* 5 seconds */
  };

These are quite acceptable results for me and there are plans to improve them using a magnetometer. I verified that the algorithm could maintain roll and pitch angles despite prolonged tilts, ascents, and descents. I was able to tune the algorithm only by selecting the SAMPLE_PERIOD and .gain coefficients Based on the results of searching for coefficients, I settled on the following

SAMPLE_PERIOD (0.0342f)
.gain = 0.008f

And again, I noticed some strangeness, or rather a pattern, which in no way relates to the fusion algorithm. The pattern applies to my code, which is executed on STM32F411 and it is as follows - when I execute the code without collecting data samples, then with the SAMPLE_PERIOD coefficient indicated above, the fusion algorithm is not bad, it maintains the roll and pitch angles without errors for 30-60 seconds. But if I want to collect data samples, then I introduce an additional load into the microcontroller code, and the microcontroller executes the program, including FusionAhrsUpdateNoMagnetometer(&ahrs, gyroscope, accelerometer, SAMPLE_PERIOD); A little longer and I have to change the SAMPLE_PERIOD factor. I also thought that this notorious SAMPLE_PERIOD coefficient is similar to the sample_rate coefficient from an extended example in Python. But it turned out that the sample_rate coefficient cannot even be given a fractional value. I probably still don’t fully understand the magic of the settings of the fusion algorithm, but I understand that the operation of the algorithm greatly depends on the quantity, i.e. frequency of data from the gyroscope and accelerometer, as well as selection of coefficients in the code section: imufusion.Settings I hope another long text did not confuse you. Thank you.

xioTechnologies commented 1 month ago

I have asked that we tackle issues one at a time, and I identified the unknown sample rate as being the critical issue that must be solved before anything else. I can't support you unless you engage with what I am saying.

brightproject commented 1 month ago

I have asked that we tackle issues one at a time, and I identified the unknown sample rate as being the critical issue that must be solved before anything else. I can't support you unless you engage with what I am saying.

My SAMPLE_PERIOD is 0.0340 seconds, then:

Frequency = 1 / 0.0340
Frequency ≈ 29.4118 Hz

Thus, a SAMPLE_PERIOD of 0.0340 seconds corresponds to a frequency of approximately 30 Hz. ​ Could you convert this issue into a discussion?

xioTechnologies commented 1 month ago

The first step is for you to run simple_example.py with valid data. This means using the correct sample rate and timestamps. I am not confident that the latest sample rate you have reported is correct because you have reported numerous other conflicting values:

I was expecting you to confirm the actual sample rate, verified in such a way that previously reported values could be discounted.

brightproject commented 1 month ago

I was expecting you to confirm the actual sample rate, verified in such a way that previously reported values could be discounted

Now I have conducted a series of tests, and I realized that the sample frequency that the simulator produces is not a constant, this is precisely a simulation problem, because the sampling frequency is tied to the FPS of the simulator itself. Still, I managed to run the eighth version of the collected data samples: sensor_data_v8.csv Simple example: Figure_1_simple_v8 Here I also tried to output the quaternion mapping, but I couldn't solve the issue with this line of code quaternion[index] = ahrs.quaternion.array

https://github.com/xioTechnologies/Fusion/issues/99#issuecomment-1513751508

Advanced example Figure_1_advanced_v8

Advanced example used with the following settings

ahrs.settings = imufusion.Settings(imufusion.CONVENTION_NWU,  # convention
                                   0.0001,  # gain
                                   0,  # gyroscope range
                                   50,  # acceleration rejection
                                   0,  # magnetic rejection
                                   10)  # recovery trigger period = 5 seconds

As far as I understand the setting of the algorithm, SAMPLE_PERIOD sets the rate of change of the orientation angle, and GAIN sets how long during the roll the angle will not decrease while the roll itself is in progress. I have already begun to understand a little about the operation of the algorithm, the only thing that is not clear is how to enable acceleration when the plane is in horizontal flight, so that gravity corrects the position of the bank angle. Now, with a roll of -+30 degrees, the roll is calculated accurately, and the roll lasts a long time, but when the plane levels out into horizontal flight, the roll becomes not 0 degrees, but -+5. This changes the pitch angle. As if there is no calculation of the gravity vector or it is not used.

xioTechnologies commented 1 month ago

I want to help you but you refuse to engage with the process. I am leaving the discussion. Good luck.

brightproject commented 2 weeks ago

I want to help you but you refuse to engage with the process. I am leaving the discussion. Good luc

@xioTechnologies If may, I ask a question? I managed to collect data from the flight, I filtered this data and put it into an advanced filter example. I first rotated the X and Y axes of the gyroscope, because The reference system of the aircraft isNED, but for the example you need ENU. The filtered data file is below. real__flight_data_filtered.csv

The filter parameters are as follows.

ahrs.settings = imufusion.Settings(imufusion.CONVENTION_ENU,  # convention
                                   0.7,  # gain
                                   0.8,  # gyroscope range
                                   0.8,  # acceleration rejection
                                   10.5,  # magnetic rejection
                                   # 5 * sample_rate)  # recovery trigger period = 5 seconds
                                   600)  # recovery trigger period = 5 seconds

Result Figure It's impossible to figure this out without your help. Thank you.