/*
 * EKF Attitude Estimator main function.
 *
 * Estimates the attitude recursively once started.
 *
 * @param argc number of commandline arguments (plus command name)
 * @param argv strings containing the arguments
 */
int attitude_estimator_ekf_thread_main(int argc, char *argv[])
{

    const unsigned int loop_interval_alarm = 6500;	// loop interval in microseconds

    float dt = 0.005f;
    /* state vector x has the following entries [ax,ay,az||mx,my,mz||wox,woy,woz||wx,wy,wz]' */
    float z_k[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 9.81f, 0.2f, -0.2f, 0.2f};					/**< Measurement vector */
    float x_aposteriori_k[12];		/**< states */
    float P_aposteriori_k[144] = {100.f, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
                                  0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
                                  0,   0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,   0,
                                  0,   0,   0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,
                                  0,   0,   0,   0,  100.f,  0,   0,   0,   0,   0,   0,   0,
                                  0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,   0,   0,
                                  0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,   0,
                                  0,   0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,
                                  0,   0,   0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,
                                  0,   0,   0,   0,   0,   0,   0,   0,  0.0f, 100.0f,   0,   0,
                                  0,   0,   0,   0,   0,   0,   0,   0,  0.0f,   0,   100.0f,   0,
                                  0,   0,   0,   0,   0,   0,   0,   0,  0.0f,   0,   0,   100.0f,
                                 }; /**< init: diagonal matrix with big values */

    float x_aposteriori[12];
    float P_aposteriori[144];

    /* output euler angles */
    float euler[3] = {0.0f, 0.0f, 0.0f};

    float Rot_matrix[9] = {1.f,  0,  0,
                           0,  1.f,  0,
                           0,  0,  1.f
                          };		/**< init: identity matrix */

    // print text
    printf("Extended Kalman Filter Attitude Estimator initialized..\n\n");
    fflush(stdout);

    int overloadcounter = 19;

    /* Initialize filter */
    attitudeKalmanfilter_initialize();

    /* store start time to guard against too slow update rates */
    uint64_t last_run = hrt_absolute_time();

    struct sensor_combined_s raw;
    memset(&raw, 0, sizeof(raw));
    struct vehicle_gps_position_s gps;
    memset(&gps, 0, sizeof(gps));
    struct vehicle_global_position_s global_pos;
    memset(&global_pos, 0, sizeof(global_pos));
    struct vehicle_attitude_s att;
    memset(&att, 0, sizeof(att));
    struct vehicle_control_mode_s control_mode;
    memset(&control_mode, 0, sizeof(control_mode));
    struct vehicle_vicon_position_s vicon_pos;  // Added by Ross Allen
    memset(&vicon_pos, 0, sizeof(vicon_pos));

    uint64_t last_data = 0;
    uint64_t last_measurement = 0;
    uint64_t last_vel_t = 0;

    /* Vicon parameters - Added by Ross Allen */
    bool vicon_valid = false;
    //~ static const hrt_abstime vicon_topic_timeout = 500000;		// vicon topic timeout = 0.25s

    /* current velocity */
    math::Vector<3> vel;
    vel.zero();
    /* previous velocity */
    math::Vector<3> vel_prev;
    vel_prev.zero();
    /* actual acceleration (by GPS velocity) in body frame */
    math::Vector<3> acc;
    acc.zero();
    /* rotation matrix */
    math::Matrix<3, 3> R;
    R.identity();

    /* subscribe to raw data */
    int sub_raw = orb_subscribe(ORB_ID(sensor_combined));
    /* rate-limit raw data updates to 333 Hz (sensors app publishes at 200, so this is just paranoid) */
    orb_set_interval(sub_raw, 3);

    /* subscribe to GPS */
    int sub_gps = orb_subscribe(ORB_ID(vehicle_gps_position));

    /* subscribe to GPS */
    int sub_global_pos = orb_subscribe(ORB_ID(vehicle_global_position));

    /* subscribe to param changes */
    int sub_params = orb_subscribe(ORB_ID(parameter_update));

    /* subscribe to control mode*/
    int sub_control_mode = orb_subscribe(ORB_ID(vehicle_control_mode));

    /* subscribe to vicon position */
    int vehicle_vicon_position_sub = orb_subscribe(ORB_ID(vehicle_vicon_position)); // Added by Ross Allen

    /* advertise attitude */
    orb_advert_t pub_att = orb_advertise(ORB_ID(vehicle_attitude), &att);

    int loopcounter = 0;

    thread_running = true;

    /* advertise debug value */
    // struct debug_key_value_s dbg = { .key = "", .value = 0.0f };
    // orb_advert_t pub_dbg = -1;

    /* keep track of sensor updates */
    uint64_t sensor_last_timestamp[3] = {0, 0, 0};

    struct attitude_estimator_ekf_params ekf_params;

    struct attitude_estimator_ekf_param_handles ekf_param_handles;

    /* initialize parameter handles */
    parameters_init(&ekf_param_handles);

    bool initialized = false;

    float gyro_offsets[3] = { 0.0f, 0.0f, 0.0f };

    /* magnetic declination, in radians */
    float mag_decl = 0.0f;

    /* rotation matrix for magnetic declination */
    math::Matrix<3, 3> R_decl;
    R_decl.identity();

    /* register the perf counter */
    perf_counter_t ekf_loop_perf = perf_alloc(PC_ELAPSED, "attitude_estimator_ekf");

    /* Main loop*/
    while (!thread_should_exit) {

        struct pollfd fds[2];
        fds[0].fd = sub_raw;
        fds[0].events = POLLIN;
        fds[1].fd = sub_params;
        fds[1].events = POLLIN;
        int ret = poll(fds, 2, 1000);

        /* Added by Ross Allen */
        //~ hrt_abstime t = hrt_absolute_time();
        bool updated;

        if (ret < 0) {
            /* XXX this is seriously bad - should be an emergency */
        } else if (ret == 0) {
            /* check if we're in HIL - not getting sensor data is fine then */
            orb_copy(ORB_ID(vehicle_control_mode), sub_control_mode, &control_mode);

            if (!control_mode.flag_system_hil_enabled) {
                fprintf(stderr,
                        "[att ekf] WARNING: Not getting sensors - sensor app running?\n");
            }

        } else {

            /* only update parameters if they changed */
            if (fds[1].revents & POLLIN) {
                /* read from param to clear updated flag */
                struct parameter_update_s update;
                orb_copy(ORB_ID(parameter_update), sub_params, &update);

                /* update parameters */
                parameters_update(&ekf_param_handles, &ekf_params);
            }

            /* only run filter if sensor values changed */
            if (fds[0].revents & POLLIN) {

                /* get latest measurements */
                orb_copy(ORB_ID(sensor_combined), sub_raw, &raw);

                bool gps_updated;
                orb_check(sub_gps, &gps_updated);
                if (gps_updated) {
                    orb_copy(ORB_ID(vehicle_gps_position), sub_gps, &gps);

                    if (gps.eph < 20.0f && hrt_elapsed_time(&gps.timestamp_position) < 1000000) {
                        mag_decl = math::radians(get_mag_declination(gps.lat / 1e7f, gps.lon / 1e7f));

                        /* update mag declination rotation matrix */
                        R_decl.from_euler(0.0f, 0.0f, mag_decl);
                    }
                }

                bool global_pos_updated;
                orb_check(sub_global_pos, &global_pos_updated);
                if (global_pos_updated) {
                    orb_copy(ORB_ID(vehicle_global_position), sub_global_pos, &global_pos);
                }

                if (!initialized) {
                    // XXX disabling init for now
                    initialized = true;

                    // gyro_offsets[0] += raw.gyro_rad_s[0];
                    // gyro_offsets[1] += raw.gyro_rad_s[1];
                    // gyro_offsets[2] += raw.gyro_rad_s[2];
                    // offset_count++;

                    // if (hrt_absolute_time() - start_time > 3000000LL) {
                    // 	initialized = true;
                    // 	gyro_offsets[0] /= offset_count;
                    // 	gyro_offsets[1] /= offset_count;
                    // 	gyro_offsets[2] /= offset_count;
                    // }

                } else {

                    perf_begin(ekf_loop_perf);

                    /* Calculate data time difference in seconds */
                    dt = (raw.timestamp - last_measurement) / 1000000.0f;
                    last_measurement = raw.timestamp;
                    uint8_t update_vect[3] = {0, 0, 0};

                    /* Fill in gyro measurements */
                    if (sensor_last_timestamp[0] != raw.timestamp) {
                        update_vect[0] = 1;
                        // sensor_update_hz[0] = 1e6f / (raw.timestamp - sensor_last_timestamp[0]);
                        sensor_last_timestamp[0] = raw.timestamp;
                    }

                    z_k[0] =  raw.gyro_rad_s[0] - gyro_offsets[0];
                    z_k[1] =  raw.gyro_rad_s[1] - gyro_offsets[1];
                    z_k[2] =  raw.gyro_rad_s[2] - gyro_offsets[2];

                    /* update accelerometer measurements */
                    if (sensor_last_timestamp[1] != raw.accelerometer_timestamp) {
                        update_vect[1] = 1;
                        // sensor_update_hz[1] = 1e6f / (raw.timestamp - sensor_last_timestamp[1]);
                        sensor_last_timestamp[1] = raw.accelerometer_timestamp;
                    }

                    hrt_abstime vel_t = 0;
                    bool vel_valid = false;
                    if (ekf_params.acc_comp == 1 && gps.fix_type >= 3 && gps.eph < 10.0f && gps.vel_ned_valid && hrt_absolute_time() < gps.timestamp_velocity + 500000) {
                        vel_valid = true;
                        if (gps_updated) {
                            vel_t = gps.timestamp_velocity;
                            vel(0) = gps.vel_n_m_s;
                            vel(1) = gps.vel_e_m_s;
                            vel(2) = gps.vel_d_m_s;
                        }

                    } else if (ekf_params.acc_comp == 2 && gps.eph < 5.0f && global_pos.timestamp != 0 && hrt_absolute_time() < global_pos.timestamp + 20000) {
                        vel_valid = true;
                        if (global_pos_updated) {
                            vel_t = global_pos.timestamp;
                            vel(0) = global_pos.vel_n;
                            vel(1) = global_pos.vel_e;
                            vel(2) = global_pos.vel_d;
                        }
                    }

                    if (vel_valid) {
                        /* velocity is valid */
                        if (vel_t != 0) {
                            /* velocity updated */
                            if (last_vel_t != 0 && vel_t != last_vel_t) {
                                float vel_dt = (vel_t - last_vel_t) / 1000000.0f;
                                /* calculate acceleration in body frame */
                                acc = R.transposed() * ((vel - vel_prev) / vel_dt);
                            }
                            last_vel_t = vel_t;
                            vel_prev = vel;
                        }

                    } else {
                        /* velocity is valid, reset acceleration */
                        acc.zero();
                        vel_prev.zero();
                        last_vel_t = 0;
                    }

                    z_k[3] = raw.accelerometer_m_s2[0] - acc(0);
                    z_k[4] = raw.accelerometer_m_s2[1] - acc(1);
                    z_k[5] = raw.accelerometer_m_s2[2] - acc(2);

                    /* update magnetometer measurements */
                    if (sensor_last_timestamp[2] != raw.magnetometer_timestamp) {
                        update_vect[2] = 1;
                        // sensor_update_hz[2] = 1e6f / (raw.timestamp - sensor_last_timestamp[2]);
                        sensor_last_timestamp[2] = raw.magnetometer_timestamp;
                    }

                    z_k[6] = raw.magnetometer_ga[0];
                    z_k[7] = raw.magnetometer_ga[1];
                    z_k[8] = raw.magnetometer_ga[2];

                    uint64_t now = hrt_absolute_time();
                    unsigned int time_elapsed = now - last_run;
                    last_run = now;

                    if (time_elapsed > loop_interval_alarm) {
                        //TODO: add warning, cpu overload here
                        // if (overloadcounter == 20) {
                        // 	printf("CPU OVERLOAD DETECTED IN ATTITUDE ESTIMATOR EKF (%lu > %lu)\n", time_elapsed, loop_interval_alarm);
                        // 	overloadcounter = 0;
                        // }

                        overloadcounter++;
                    }

                    static bool const_initialized = false;

                    /* initialize with good values once we have a reasonable dt estimate */
                    if (!const_initialized && dt < 0.05f && dt > 0.001f) {
                        dt = 0.005f;
                        parameters_update(&ekf_param_handles, &ekf_params);

                        /* update mag declination rotation matrix */
                        if (gps.eph < 20.0f && hrt_elapsed_time(&gps.timestamp_position) < 1000000) {
                            mag_decl = math::radians(get_mag_declination(gps.lat / 1e7f, gps.lon / 1e7f));

                        } else {
                            mag_decl = ekf_params.mag_decl;
                        }

                        /* update mag declination rotation matrix */
                        R_decl.from_euler(0.0f, 0.0f, mag_decl);

                        x_aposteriori_k[0] = z_k[0];
                        x_aposteriori_k[1] = z_k[1];
                        x_aposteriori_k[2] = z_k[2];
                        x_aposteriori_k[3] = 0.0f;
                        x_aposteriori_k[4] = 0.0f;
                        x_aposteriori_k[5] = 0.0f;
                        x_aposteriori_k[6] = z_k[3];
                        x_aposteriori_k[7] = z_k[4];
                        x_aposteriori_k[8] = z_k[5];
                        x_aposteriori_k[9] = z_k[6];
                        x_aposteriori_k[10] = z_k[7];
                        x_aposteriori_k[11] = z_k[8];

                        const_initialized = true;
                    }

                    /* do not execute the filter if not initialized */
                    if (!const_initialized) {
                        continue;
                    }

                    attitudeKalmanfilter(update_vect, dt, z_k, x_aposteriori_k, P_aposteriori_k, ekf_params.q, ekf_params.r,
                                         euler, Rot_matrix, x_aposteriori, P_aposteriori);

                    /* swap values for next iteration, check for fatal inputs */
                    if (isfinite(euler[0]) && isfinite(euler[1]) && isfinite(euler[2])) {
                        memcpy(P_aposteriori_k, P_aposteriori, sizeof(P_aposteriori_k));
                        memcpy(x_aposteriori_k, x_aposteriori, sizeof(x_aposteriori_k));

                    } else {
                        /* due to inputs or numerical failure the output is invalid, skip it */
                        continue;
                    }

                    if (last_data > 0 && raw.timestamp - last_data > 30000)
                        printf("[attitude estimator ekf] sensor data missed! (%llu)\n", raw.timestamp - last_data);

                    last_data = raw.timestamp;

                    /* Check Vicon for attitude data*/
                    /* Added by Ross Allen */
                    orb_check(vehicle_vicon_position_sub, &updated);

                    if (updated) {
                        orb_copy(ORB_ID(vehicle_vicon_position), vehicle_vicon_position_sub, &vicon_pos);
                        vicon_valid = vicon_pos.valid;
                    }

                    //~ if (vicon_valid && (t > (vicon_pos.timestamp + vicon_topic_timeout))) {
                    //~ vicon_valid = false;
                    //~ warnx("VICON timeout");
                    //~ }

                    /* send out */
                    att.timestamp = raw.timestamp;

                    att.roll = euler[0];
                    att.pitch = euler[1];
                    att.yaw = euler[2] + mag_decl;

                    /* Use vicon yaw if valid and just overwrite*/
                    /* Added by Ross Allen */
                    if(vicon_valid) {
                        att.yaw = vicon_pos.yaw;
                    }

                    att.rollspeed = x_aposteriori[0];
                    att.pitchspeed = x_aposteriori[1];
                    att.yawspeed = x_aposteriori[2];
                    att.rollacc = x_aposteriori[3];
                    att.pitchacc = x_aposteriori[4];
                    att.yawacc = x_aposteriori[5];

                    att.g_comp[0] = raw.accelerometer_m_s2[0] - acc(0);
                    att.g_comp[1] = raw.accelerometer_m_s2[1] - acc(1);
                    att.g_comp[2] = raw.accelerometer_m_s2[2] - acc(2);

                    /* copy offsets */
                    memcpy(&att.rate_offsets, &(x_aposteriori[3]), sizeof(att.rate_offsets));

                    /* magnetic declination */

                    math::Matrix<3, 3> R_body = (&Rot_matrix[0]);
                    R = R_decl * R_body;

                    /* copy rotation matrix */
                    memcpy(&att.R[0][0], &R.data[0][0], sizeof(att.R));
                    att.R_valid = true;

                    if (isfinite(att.roll) && isfinite(att.pitch) && isfinite(att.yaw)) {
                        // Broadcast
                        orb_publish(ORB_ID(vehicle_attitude), pub_att, &att);

                    } else {
                        warnx("NaN in roll/pitch/yaw estimate!");
                    }

                    perf_end(ekf_loop_perf);
                }
            }
        }

        loopcounter++;
    }

    thread_running = false;

    return 0;
}
/*
 * EKF Attitude Estimator main function.
 *
 * Estimates the attitude recursively once started.
 *
 * @param argc number of commandline arguments (plus command name)
 * @param argv strings containing the arguments
 */
int attitude_estimator_ekf_thread_main(int argc, char *argv[])
{

const unsigned int loop_interval_alarm = 6500;	// loop interval in microseconds

	float dt = 0.005f;
/* state vector x has the following entries [ax,ay,az||mx,my,mz||wox,woy,woz||wx,wy,wz]' */
	float z_k[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 9.81f, 0.2f, -0.2f, 0.2f};					/**< Measurement vector */
	float x_aposteriori_k[12];		/**< states */
	float P_aposteriori_k[144] = {100.f, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
				     0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
				     0,   0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,   0,
				     0,   0,   0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,  100.f,  0,   0,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,
				     0,   0,   0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,
				     0,   0,   0,   0,   0,   0,   0,   0,  0.0f, 100.0f,   0,   0,
				     0,   0,   0,   0,   0,   0,   0,   0,  0.0f,   0,   100.0f,   0,
				     0,   0,   0,   0,   0,   0,   0,   0,  0.0f,   0,   0,   100.0f,
				    }; /**< init: diagonal matrix with big values */

	float x_aposteriori[12];
	float P_aposteriori[144];

	/* output euler angles */
	float euler[3] = {0.0f, 0.0f, 0.0f};

	float Rot_matrix[9] = {1.f,  0,  0,
			      0,  1.f,  0,
			      0,  0,  1.f
			     };		/**< init: identity matrix */

	// print text
	printf("Extended Kalman Filter Attitude Estimator initialized..\n\n");
	fflush(stdout);

	int overloadcounter = 19;

	/* Initialize filter */
	attitudeKalmanfilter_initialize();

	/* store start time to guard against too slow update rates */
	uint64_t last_run = hrt_absolute_time();

	struct sensor_combined_s raw;
	memset(&raw, 0, sizeof(raw));
	struct vehicle_attitude_s att;
	memset(&att, 0, sizeof(att));
	struct vehicle_status_s state;
	memset(&state, 0, sizeof(state));

	uint64_t last_data = 0;
	uint64_t last_measurement = 0;

	/* subscribe to raw data */
	int sub_raw = orb_subscribe(ORB_ID(sensor_combined));
	/* rate-limit raw data updates to 200Hz */
	orb_set_interval(sub_raw, 4);

	/* subscribe to param changes */
	int sub_params = orb_subscribe(ORB_ID(parameter_update));

	/* subscribe to system state*/
	int sub_state = orb_subscribe(ORB_ID(vehicle_status));

	/* advertise attitude */
	orb_advert_t pub_att = orb_advertise(ORB_ID(vehicle_attitude), &att);


	int loopcounter = 0;
	int printcounter = 0;

	thread_running = true;

	/* advertise debug value */
	// struct debug_key_value_s dbg = { .key = "", .value = 0.0f };
	// orb_advert_t pub_dbg = -1;

	float sensor_update_hz[3] = {0.0f, 0.0f, 0.0f};
	// XXX write this out to perf regs

	/* keep track of sensor updates */
	uint32_t sensor_last_count[3] = {0, 0, 0};
	uint64_t sensor_last_timestamp[3] = {0, 0, 0};

	struct attitude_estimator_ekf_params ekf_params;

	struct attitude_estimator_ekf_param_handles ekf_param_handles;

	/* initialize parameter handles */
	parameters_init(&ekf_param_handles);

	uint64_t start_time = hrt_absolute_time();
	bool initialized = false;

	float gyro_offsets[3] = { 0.0f, 0.0f, 0.0f };
	unsigned offset_count = 0;

	/* register the perf counter */
	perf_counter_t ekf_loop_perf = perf_alloc(PC_ELAPSED, "attitude_estimator_ekf");

	/* Main loop*/
	while (!thread_should_exit) {

		struct pollfd fds[2];
		fds[0].fd = sub_raw;
		fds[0].events = POLLIN;
		fds[1].fd = sub_params;
		fds[1].events = POLLIN;
		int ret = poll(fds, 2, 1000);

		if (ret < 0) {
			/* XXX this is seriously bad - should be an emergency */
		} else if (ret == 0) {
			/* check if we're in HIL - not getting sensor data is fine then */
			orb_copy(ORB_ID(vehicle_status), sub_state, &state);

			if (!state.flag_hil_enabled) {
				fprintf(stderr,
					"[att ekf] WARNING: Not getting sensors - sensor app running?\n");
			}

		} else {

			/* only update parameters if they changed */
			if (fds[1].revents & POLLIN) {
				/* read from param to clear updated flag */
				struct parameter_update_s update;
				orb_copy(ORB_ID(parameter_update), sub_params, &update);

				/* update parameters */
				parameters_update(&ekf_param_handles, &ekf_params);
			}

			/* only run filter if sensor values changed */
			if (fds[0].revents & POLLIN) {

				/* get latest measurements */
				orb_copy(ORB_ID(sensor_combined), sub_raw, &raw);

				if (!initialized) {

					gyro_offsets[0] += raw.gyro_rad_s[0];
					gyro_offsets[1] += raw.gyro_rad_s[1];
					gyro_offsets[2] += raw.gyro_rad_s[2];
					offset_count++;

					if (hrt_absolute_time() - start_time > 3000000LL) {
						initialized = true;
						gyro_offsets[0] /= offset_count;
						gyro_offsets[1] /= offset_count;
						gyro_offsets[2] /= offset_count;
					}

				} else {

					perf_begin(ekf_loop_perf);

					/* Calculate data time difference in seconds */
					dt = (raw.timestamp - last_measurement) / 1000000.0f;
					last_measurement = raw.timestamp;
					uint8_t update_vect[3] = {0, 0, 0};

					/* Fill in gyro measurements */
					if (sensor_last_count[0] != raw.gyro_counter) {
						update_vect[0] = 1;
						sensor_last_count[0] = raw.gyro_counter;
						sensor_update_hz[0] = 1e6f / (raw.timestamp - sensor_last_timestamp[0]);
						sensor_last_timestamp[0] = raw.timestamp;
					}

					z_k[0] =  raw.gyro_rad_s[0] - gyro_offsets[0];
					z_k[1] =  raw.gyro_rad_s[1] - gyro_offsets[1];
					z_k[2] =  raw.gyro_rad_s[2] - gyro_offsets[2];

					/* update accelerometer measurements */
					if (sensor_last_count[1] != raw.accelerometer_counter) {
						update_vect[1] = 1;
						sensor_last_count[1] = raw.accelerometer_counter;
						sensor_update_hz[1] = 1e6f / (raw.timestamp - sensor_last_timestamp[1]);
						sensor_last_timestamp[1] = raw.timestamp;
					}

					z_k[3] = raw.accelerometer_m_s2[0];
					z_k[4] = raw.accelerometer_m_s2[1];
					z_k[5] = raw.accelerometer_m_s2[2];

					/* update magnetometer measurements */
					if (sensor_last_count[2] != raw.magnetometer_counter) {
						update_vect[2] = 1;
						sensor_last_count[2] = raw.magnetometer_counter;
						sensor_update_hz[2] = 1e6f / (raw.timestamp - sensor_last_timestamp[2]);
						sensor_last_timestamp[2] = raw.timestamp;
					}

					z_k[6] = raw.magnetometer_ga[0];
					z_k[7] = raw.magnetometer_ga[1];
					z_k[8] = raw.magnetometer_ga[2];

					uint64_t now = hrt_absolute_time();
					unsigned int time_elapsed = now - last_run;
					last_run = now;

					if (time_elapsed > loop_interval_alarm) {
						//TODO: add warning, cpu overload here
						// if (overloadcounter == 20) {
						// 	printf("CPU OVERLOAD DETECTED IN ATTITUDE ESTIMATOR EKF (%lu > %lu)\n", time_elapsed, loop_interval_alarm);
						// 	overloadcounter = 0;
						// }

						overloadcounter++;
					}

					static bool const_initialized = false;

					/* initialize with good values once we have a reasonable dt estimate */
					if (!const_initialized && dt < 0.05f && dt > 0.005f) {
						dt = 0.005f;
						parameters_update(&ekf_param_handles, &ekf_params);

						x_aposteriori_k[0] = z_k[0];
						x_aposteriori_k[1] = z_k[1];
						x_aposteriori_k[2] = z_k[2];
						x_aposteriori_k[3] = 0.0f;
						x_aposteriori_k[4] = 0.0f;
						x_aposteriori_k[5] = 0.0f;
						x_aposteriori_k[6] = z_k[3];
						x_aposteriori_k[7] = z_k[4];
						x_aposteriori_k[8] = z_k[5];
						x_aposteriori_k[9] = z_k[6];
						x_aposteriori_k[10] = z_k[7];
						x_aposteriori_k[11] = z_k[8];

						const_initialized = true;
					}

					/* do not execute the filter if not initialized */
					if (!const_initialized) {
						continue;
					}

					uint64_t timing_start = hrt_absolute_time();

					attitudeKalmanfilter(update_vect, dt, z_k, x_aposteriori_k, P_aposteriori_k, ekf_params.q, ekf_params.r,
							     euler, Rot_matrix, x_aposteriori, P_aposteriori);

					/* swap values for next iteration, check for fatal inputs */
					if (isfinite(euler[0]) && isfinite(euler[1]) && isfinite(euler[2])) {
						memcpy(P_aposteriori_k, P_aposteriori, sizeof(P_aposteriori_k));
						memcpy(x_aposteriori_k, x_aposteriori, sizeof(x_aposteriori_k));

					} else {
						/* due to inputs or numerical failure the output is invalid, skip it */
						continue;
					}

					if (last_data > 0 && raw.timestamp - last_data > 12000) printf("[attitude estimator ekf] sensor data missed! (%llu)\n", raw.timestamp - last_data);

					last_data = raw.timestamp;

					/* send out */
					att.timestamp = raw.timestamp;

					// XXX Apply the same transformation to the rotation matrix
					att.roll = euler[0] - ekf_params.roll_off;
					att.pitch = euler[1] - ekf_params.pitch_off;
					att.yaw = euler[2] - ekf_params.yaw_off;

					att.rollspeed = x_aposteriori[0];
					att.pitchspeed = x_aposteriori[1];
					att.yawspeed = x_aposteriori[2];
					att.rollacc = x_aposteriori[3];
					att.pitchacc = x_aposteriori[4];
					att.yawacc = x_aposteriori[5];

					//att.yawspeed =z_k[2] ;
					/* copy offsets */
					memcpy(&att.rate_offsets, &(x_aposteriori[3]), sizeof(att.rate_offsets));

					/* copy rotation matrix */
					memcpy(&att.R, Rot_matrix, sizeof(Rot_matrix));
					att.R_valid = true;

					if (isfinite(att.roll) && isfinite(att.pitch) && isfinite(att.yaw)) {
						// Broadcast
						orb_publish(ORB_ID(vehicle_attitude), pub_att, &att);

					} else {
						warnx("NaN in roll/pitch/yaw estimate!");
					}

					perf_end(ekf_loop_perf);
				}
			}
		}

		loopcounter++;
	}

	thread_running = false;

	return 0;
}
/*
 * EKF Attitude Estimator main function.
 *
 * Estimates the attitude recursively once started.
 *
 * @param argc number of commandline arguments (plus command name)
 * @param argv strings containing the arguments
 */
int attitude_estimator_ekf_thread_main(int argc, char *argv[])
{
	// print text
	printf("Extended Kalman Filter Attitude Estimator initialized..\n\n");
	fflush(stdout);

	int overloadcounter = 19;

	/* Initialize filter */
	attitudeKalmanfilter_initialize();

	/* store start time to guard against too slow update rates */
	uint64_t last_run = hrt_absolute_time();

	struct sensor_combined_s raw;
	struct vehicle_attitude_s att;

	uint64_t last_data = 0;
	uint64_t last_measurement = 0;

	/* subscribe to raw data */
	int sub_raw = orb_subscribe(ORB_ID(sensor_combined));
	/* rate-limit raw data updates to 200Hz */
	orb_set_interval(sub_raw, 4);

	/* subscribe to param changes */
	int sub_params = orb_subscribe(ORB_ID(parameter_update));

	/* advertise attitude */
	orb_advert_t pub_att = orb_advertise(ORB_ID(vehicle_attitude), &att);


	int loopcounter = 0;
	int printcounter = 0;

	thread_running = true;

	/* advertise debug value */
	struct debug_key_value_s dbg = { .key = "", .value = 0.0f };
	orb_advert_t pub_dbg = orb_advertise(ORB_ID(debug_key_value), &dbg);

	/* keep track of sensor updates */
	uint32_t sensor_last_count[3] = {0, 0, 0};
	uint64_t sensor_last_timestamp[3] = {0, 0, 0};
	float sensor_update_hz[3] = {0.0f, 0.0f, 0.0f};

	struct attitude_estimator_ekf_params ekf_params;

	struct attitude_estimator_ekf_param_handles ekf_param_handles;

	/* initialize parameter handles */
	parameters_init(&ekf_param_handles);

	/* Main loop*/
	while (!thread_should_exit) {

		struct pollfd fds[2] = {
			{ .fd = sub_raw,   .events = POLLIN },
			{ .fd = sub_params, .events = POLLIN }
		};
		int ret = poll(fds, 2, 1000);

		if (ret < 0) {
			/* XXX this is seriously bad - should be an emergency */
		} else if (ret == 0) {
			/* XXX this means no sensor data - should be critical or emergency */
			printf("[attitude estimator ekf] WARNING: Not getting sensor data - sensor app running?\n");
		} else {
	
			/* only update parameters if they changed */
			if (fds[1].revents & POLLIN) {
				/* read from param to clear updated flag */
				struct parameter_update_s update;
				orb_copy(ORB_ID(parameter_update), sub_params, &update);

				/* update parameters */
				parameters_update(&ekf_param_handles, &ekf_params);
			}

			/* only run filter if sensor values changed */
			if (fds[0].revents & POLLIN) {

				/* get latest measurements */
				orb_copy(ORB_ID(sensor_combined), sub_raw, &raw);

				/* Calculate data time difference in seconds */
				dt = (raw.timestamp - last_measurement) / 1000000.0f;
				last_measurement = raw.timestamp;
				uint8_t update_vect[3] = {0, 0, 0};

				/* Fill in gyro measurements */
				if (sensor_last_count[0] != raw.gyro_counter) {
					update_vect[0] = 1;
					sensor_last_count[0] = raw.gyro_counter;
					sensor_update_hz[0] = 1e6f / (raw.timestamp - sensor_last_timestamp[0]);
					sensor_last_timestamp[0] = raw.timestamp;
				}

				z_k[0] =  raw.gyro_rad_s[0];
				z_k[1] =  raw.gyro_rad_s[1];
				z_k[2] =  raw.gyro_rad_s[2];

				/* update accelerometer measurements */
				if (sensor_last_count[1] != raw.accelerometer_counter) {
					update_vect[1] = 1;
					sensor_last_count[1] = raw.accelerometer_counter;
					sensor_update_hz[1] = 1e6f / (raw.timestamp - sensor_last_timestamp[1]);
					sensor_last_timestamp[1] = raw.timestamp;
				}
				z_k[3] = raw.accelerometer_m_s2[0];
				z_k[4] = raw.accelerometer_m_s2[1];
				z_k[5] = raw.accelerometer_m_s2[2];

				/* update magnetometer measurements */
				if (sensor_last_count[2] != raw.magnetometer_counter) {
					update_vect[2] = 1;
					sensor_last_count[2] = raw.magnetometer_counter;
					sensor_update_hz[2] = 1e6f / (raw.timestamp - sensor_last_timestamp[2]);
					sensor_last_timestamp[2] = raw.timestamp;
				}
				z_k[6] = raw.magnetometer_ga[0];
				z_k[7] = raw.magnetometer_ga[1];
				z_k[8] = raw.magnetometer_ga[2];

				uint64_t now = hrt_absolute_time();
				unsigned int time_elapsed = now - last_run;
				last_run = now;

				if (time_elapsed > loop_interval_alarm) {
					//TODO: add warning, cpu overload here
					// if (overloadcounter == 20) {
					// 	printf("CPU OVERLOAD DETECTED IN ATTITUDE ESTIMATOR EKF (%lu > %lu)\n", time_elapsed, loop_interval_alarm);
					// 	overloadcounter = 0;
					// }

					overloadcounter++;
				}

				int32_t z_k_sizes = 9;
				// float u[4] = {0.0f, 0.0f, 0.0f, 0.0f};

				static bool const_initialized = false;

				/* initialize with good values once we have a reasonable dt estimate */
				if (!const_initialized /*&& dt < 0.05 && dt > 0.005*/) 
				{
					dt = 0.005f;
					parameters_update(&ekf_param_handles, &ekf_params);

					x_aposteriori_k[0] = z_k[0];
					x_aposteriori_k[1] = z_k[1];
					x_aposteriori_k[2] = z_k[2];
					x_aposteriori_k[3] = 0.0f;
					x_aposteriori_k[4] = 0.0f;
					x_aposteriori_k[5] = 0.0f;
					x_aposteriori_k[6] = z_k[3];
					x_aposteriori_k[7] = z_k[4];
					x_aposteriori_k[8] = z_k[5];
					x_aposteriori_k[9] = z_k[6];
					x_aposteriori_k[10] = z_k[7];
					x_aposteriori_k[11] = z_k[8];

					const_initialized = true;
				}

				/* do not execute the filter if not initialized */
				if (!const_initialized) {
					continue;
				}

				dt = 0.004f;

				uint64_t timing_start = hrt_absolute_time();
				// attitudeKalmanfilter(dt, update_vect, z_k, &z_k_sizes, u, x_aposteriori_k, P_aposteriori_k, knownConst, euler,
				// 	Rot_matrix, x_aposteriori, P_aposteriori);
				attitudeKalmanfilter(update_vect, dt, z_k, x_aposteriori_k, P_aposteriori_k, ekf_params.q, ekf_params.r,
					euler, Rot_matrix, x_aposteriori, P_aposteriori);
				/* swap values for next iteration */
				memcpy(P_aposteriori_k, P_aposteriori, sizeof(P_aposteriori_k));
				memcpy(x_aposteriori_k, x_aposteriori, sizeof(x_aposteriori_k));
				uint64_t timing_diff = hrt_absolute_time() - timing_start;

				// /* print rotation matrix every 200th time */
				if (printcounter % 200 == 0) {
					// printf("x apo:\n%8.4f\t%8.4f\t%8.4f\n%8.4f\t%8.4f\t%8.4f\n%8.4f\t%8.4f\t%8.4f\n",
					// 	x_aposteriori[0], x_aposteriori[1], x_aposteriori[2],
					// 	x_aposteriori[3], x_aposteriori[4], x_aposteriori[5],
					// 	x_aposteriori[6], x_aposteriori[7], x_aposteriori[8]);


					// }

					//printf("EKF attitude iteration: %d, runtime: %d us, dt: %d us (%d Hz)\n", loopcounter, (int)timing_diff, (int)(dt * 1000000.0f), (int)(1.0f / dt));
					//printf("roll: %8.4f\tpitch: %8.4f\tyaw:%8.4f\n", (double)euler[0], (double)euler[1], (double)euler[2]);
					//printf("update rates gyro: %8.4f\taccel: %8.4f\tmag:%8.4f\n", (double)sensor_update_hz[0], (double)sensor_update_hz[1], (double)sensor_update_hz[2]);
				// 	printf("\n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d\n", (int)(Rot_matrix[0] * 100), (int)(Rot_matrix[1] * 100), (int)(Rot_matrix[2] * 100),
				// 	       (int)(Rot_matrix[3] * 100), (int)(Rot_matrix[4] * 100), (int)(Rot_matrix[5] * 100),
				// 	       (int)(Rot_matrix[6] * 100), (int)(Rot_matrix[7] * 100), (int)(Rot_matrix[8] * 100));
				}

				// 				int i = printcounter % 9;

				// 	// for (int i = 0; i < 9; i++) {
				// 		char name[10];
				// 		sprintf(name, "xapo #%d", i);
				// 		memcpy(dbg.key, name, sizeof(dbg.key));
				// 		dbg.value = x_aposteriori[i];
				// 		orb_publish(ORB_ID(debug_key_value), pub_dbg, &dbg);

				printcounter++;

				if (last_data > 0 && raw.timestamp - last_data > 12000) printf("[attitude estimator ekf] sensor data missed! (%llu)\n", raw.timestamp - last_data);

				last_data = raw.timestamp;

				/* send out */
				att.timestamp = raw.timestamp;
				att.roll = euler[0];
				att.pitch = euler[1];
				att.yaw = euler[2];

				// XXX replace with x_apo after fix to filter
				att.rollspeed = raw.gyro_rad_s[0]; //x_aposteriori[0];
				att.pitchspeed = raw.gyro_rad_s[1]; //x_aposteriori[1];
				att.yawspeed = raw.gyro_rad_s[2]; //x_aposteriori[2];

				/* copy offsets */
				memcpy(&att.rate_offsets, &(x_aposteriori[3]), sizeof(att.rate_offsets));

				/* copy rotation matrix */
				memcpy(&att.R, Rot_matrix, sizeof(Rot_matrix));
				att.R_valid = true;

				// Broadcast
				orb_publish(ORB_ID(vehicle_attitude), pub_att, &att);
			}
		}

		loopcounter++;
	}
示例#4
0
/*
 * EKF Attitude Estimator main function.
 *
 * Estimates the attitude recursively once started.
 *
 * @param argc number of commandline arguments (plus command name)
 * @param argv strings containing the arguments
 */
void app_att_est_ekf_main(void* parameter)
{

const unsigned int loop_interval_alarm = 6500;	// loop interval in microseconds

	float dt = 0.005f;
/* state vector x has the following entries [ax,ay,az||mx,my,mz||wox,woy,woz||wx,wy,wz]' */
	float z_k[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 9.81f, 0.2f, -0.2f, 0.2f};					/**< Measurement vector */
	float x_aposteriori_k[12];		/**< states */
	float P_aposteriori_k[144] = {100.f, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
				     0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
				     0,   0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,   0,
				     0,   0,   0, 100.f,   0,   0,   0,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,  100.f,  0,   0,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,   0,
				     0,   0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,   0,
				     0,   0,   0,   0,   0,   0,   0,   0, 100.f,   0,   0,   0,
				     0,   0,   0,   0,   0,   0,   0,   0,  0.0f, 100.0f,   0,   0,
				     0,   0,   0,   0,   0,   0,   0,   0,  0.0f,   0,   100.0f,   0,
				     0,   0,   0,   0,   0,   0,   0,   0,  0.0f,   0,   0,   100.0f,
				    }; /**< init: diagonal matrix with big values */

	float x_aposteriori[12];
	float P_aposteriori[144];

	/* output euler angles */
	float euler[3] = {0.0f, 0.0f, 0.0f};

	float Rot_matrix[9] = {1.f,  0,  0,
			      0,  1.f,  0,
			      0,  0,  1.f
			     };		/**< init: identity matrix */

	// print text
	printf("Extended Kalman Filter Attitude Estimator initialized..\n\n");
	fflush(stdout);

	int overloadcounter = 19;

	/* Initialize filter */
	attitudeKalmanfilter_initialize();

	/* store start time to guard against too slow update rates */
	uint64_t last_run = hrt_absolute_time();

	sensor_combined_s raw;
	rt_memset(&raw, 0, sizeof(raw));
	//struct vehicle_gps_position_s gps;
	//rt_memset(&gps, 0, sizeof(gps));
	//struct vehicle_global_position_s global_pos;
	//rt_memset(&global_pos, 0, sizeof(global_pos));
	vehicle_attitude_s att;
	rt_memset(&att, 0, sizeof(att));
	//struct vehicle_control_mode_s control_mode;
	//rt_memset(&control_mode, 0, sizeof(control_mode));

	uint64_t last_data = 0;
	uint64_t last_measurement = 0;
    rt_uint32_t sensors_sub = 0;
	uint64_t last_timestamp_acc = 0;
	uint64_t last_timestamp_gyro = 0;
	uint64_t last_timestamp_mag = 0;

	/* rotation matrix */
	float R[3][3] = {1,0,0,
					 0,1,0,
					 0,0,1};

	/* subscribe to raw data */
	orb_subscribe(ORB_ID(sensor_combined),&sensors_sub);

	orb_advertise(ORB_ID(vehicle_attitude), &att);

	att_est_ekf_running = true;

	bool initialized = false;

	/* magnetic declination, in radians */
	float mag_decl = 0.0f;

	/* rotation matrix for magnetic declination */
	float R_mag[3][3] = {1,0,0,
						 0,1,0,
						 0,0,1};

    uint8_t update_vect[3] = {0, 0, 0};
	
	rt_memset(&ekf_params, 0, sizeof(ekf_params));
	ekf_params.q[0] = 1e-4f;
	ekf_params.q[1] = 0.08f;
	ekf_params.q[2] = 0.009f;
	ekf_params.q[3] = 0.005f;
	ekf_params.q[4] = 0.0f;
	
	ekf_params.r[0] = 0.0008f;
	ekf_params.r[1] = 10000.0f;
	ekf_params.r[2] = 100.0f;
	ekf_params.r[3] = 0.0f;
	
	/* Main loop*/
	while (!att_est_ekf_should_exit) {   
		/* only run filter if sensor values changed */
		if (orb_check(&sensors_sub,5000) == RT_EOK) {

			/* get latest measurements */
			orb_copy(ORB_ID(sensor_combined), &raw);
		}
		else{
			rt_kprintf("sensors data lost!\n");
		}
		if (!initialized) {
			initialized = true;
		}
		else {
			/* Calculate data time difference in seconds */
			dt = (raw.acc_timestamp - last_measurement) / 1000000.0f;
			last_measurement = raw.acc_timestamp;
			
			if(raw.gyro_timestamp != last_timestamp_gyro)
			{
				update_vect[0] = 1;
				last_timestamp_gyro = raw.gyro_timestamp;
			}
			if(raw.acc_timestamp != last_timestamp_acc)
			{
				update_vect[1] = 1;
				last_timestamp_acc = raw.acc_timestamp;
			}
			if(raw.mag_timestamp != last_timestamp_mag)
			{
				update_vect[2] = 1;
				last_timestamp_mag = raw.mag_timestamp;
			}
			
			z_k[0] =  raw.gyro_rad_s[0];
			z_k[1] =  raw.gyro_rad_s[1];
			z_k[2] =  raw.gyro_rad_s[2];

			z_k[3] = raw.acc_m_s2[0];
			z_k[4] = raw.acc_m_s2[1];
			z_k[5] = raw.acc_m_s2[2];

			z_k[6] = raw.mag_ga[0];
			z_k[7] = raw.mag_ga[1];
			z_k[8] = raw.mag_ga[2];

			uint64_t now = hrt_absolute_time();
			unsigned int time_elapsed = now - last_run;
			last_run = now;

			if (time_elapsed > loop_interval_alarm) {

				/* cpu overload */

				overloadcounter++;
			}

			static bool const_initialized = false;

			/* initialize with good values once we have a reasonable dt estimate */
			if (!const_initialized && dt < 0.05f && dt > 0.001f) {
				dt = 0.005f;
				
				/* update mag declination rotation matrix */
				euler_to_rot_mat(R_mag,0.0f, 0.0f, mag_decl);

				x_aposteriori_k[0] = z_k[0];
				x_aposteriori_k[1] = z_k[1];
				x_aposteriori_k[2] = z_k[2];
				x_aposteriori_k[3] = 0.0f;
				x_aposteriori_k[4] = 0.0f;
				x_aposteriori_k[5] = 0.0f;
				x_aposteriori_k[6] = z_k[3];
				x_aposteriori_k[7] = z_k[4];
				x_aposteriori_k[8] = z_k[5];
				x_aposteriori_k[9] = z_k[6];
				x_aposteriori_k[10] = z_k[7];
				x_aposteriori_k[11] = z_k[8];

				const_initialized = true;
			}

			/* do not execute the filter if not initialized */
			if (!const_initialized) {
				continue;
			}

			attitudeKalmanfilter(update_vect, dt, z_k, x_aposteriori_k, P_aposteriori_k, ekf_params.q, ekf_params.r,
						 euler, Rot_matrix, x_aposteriori, P_aposteriori);

			
			for(int i = 0;i < 3;i++)
			{
				update_vect[i] = 0;
			}
			/* swap values for next iteration, check for fatal inputs */
			if (isfinite(euler[0]) && isfinite(euler[1]) && isfinite(euler[2])) {
				rt_memcpy(P_aposteriori_k, P_aposteriori, sizeof(P_aposteriori_k));
				rt_memcpy(x_aposteriori_k, x_aposteriori, sizeof(x_aposteriori_k));

			} else {
				/* due to inputs or numerical failure the output is invalid, skip it */
				continue;
			}

			if (last_data > 0 && raw.acc_timestamp - last_data > 30000)
				printf("[attitude estimator ekf] sensor data missed! (%llu)\n", raw.acc_timestamp - last_data);

			last_data = raw.acc_timestamp;

			/* send out */
			att.timestamp = raw.acc_timestamp;

			att.roll = euler[0];
			att.pitch = euler[1];
			att.yaw = euler[2] + mag_decl;

			att.rollspeed = x_aposteriori[0];
			att.pitchspeed = x_aposteriori[1];
			att.yawspeed = x_aposteriori[2];
			att.rollacc = x_aposteriori[3];
			att.pitchacc = x_aposteriori[4];
			att.yawacc = x_aposteriori[5];

			att.g_comp[0] = raw.acc_m_s2[0];
			att.g_comp[1] = raw.acc_m_s2[1];
			att.g_comp[2] = raw.acc_m_s2[2];

			/* copy offsets */
			rt_memcpy(&att.rate_offsets, &(x_aposteriori[3]), sizeof(att.rate_offsets));

			/* magnetic declination */
			float R_body[3][3] = {0};
			rt_memcpy(&R_body, &Rot_matrix, sizeof(R_body));
			
			//R = R_mag * R_body;
			for(int i = 0;i < 3;i++){
				for(int j = 0;j < 3;i++)
				{
					R[i][j] = 0;
					for(int k = 0;k < 3;k++)
						R[i][j] += R_mag[i][k] * R_body[k][j];
				}
			}
						
			
			/* copy rotation matrix */
			rt_memcpy(&att.R, &R, sizeof(att.R));
			att.R_valid = true;

			if (isfinite(att.roll) && isfinite(att.pitch) && isfinite(att.yaw)) {
				// Broadcast
				orb_publish(ORB_ID(vehicle_attitude), &att);

			} else {
				rt_kprintf("NaN in roll/pitch/yaw estimate!");
			}
		}
	}
	att_est_ekf_running = false;
}