int CCONV gps_on_position_change(CPhidgetGPSHandle gps, void *userptr, double latitude, double longitude, double altitude) { PhidgetInfo *info = userptr; GpsInfo *gps_info = info->type_info; // Calculate the sample time: sample_tick(gps_info->sample_rate, NULL); // Get the GPS time: GPSDate date; GPSTime time; if ( (CPhidgetGPS_getDate(gps, &date) == EPHIDGET_OK) && (CPhidgetGPS_getTime(gps, &time) == EPHIDGET_OK) ) { gps_info->now_at_utc.tm_sec = time.tm_sec; gps_info->now_at_utc.tm_min = time.tm_min; gps_info->now_at_utc.tm_hour = time.tm_hour; gps_info->now_at_utc.tm_mday = date.tm_mday; gps_info->now_at_utc.tm_mon = date.tm_mon; gps_info->now_at_utc.tm_year = date.tm_year; gps_info->now_at_utc_ms = (time.tm_ms >= 1000) ? 0 : time.tm_ms; gps_info->is_now_at_utc_known = true; } else gps_info->is_now_at_utc_known = false; // Get Position values: if (gps_info->latitude != PUNK_DBL) { gps_info->is_latitude_known = true; gps_info->latitude = latitude; } else gps_info->is_latitude_known = false; if (gps_info->longitude != PUNK_DBL) { gps_info->is_longitude_known = true; gps_info->longitude = longitude; } else gps_info->is_longitude_known = false; if (gps_info->altitude != PUNK_DBL) { gps_info->is_altitude_known = true; gps_info->altitude = altitude; } else gps_info->is_altitude_known = false; double heading, velocity; if (CPhidgetGPS_getHeading(gps, &heading) == EPHIDGET_OK) { gps_info->heading = heading; gps_info->is_heading_known = true; } else gps_info->is_heading_known = false; if (CPhidgetGPS_getVelocity(gps, &velocity) == EPHIDGET_OK) { gps_info->velocity = velocity; gps_info->is_velocity_known = true; } else gps_info->is_velocity_known = false; return 0; }
int CCONV gps_on_fix_change(CPhidgetGPSHandle gps, void *userptr, int status) { PhidgetInfo *info = userptr; GpsInfo *gps_info = info->type_info; // Calculate the sample time: sample_tick(gps_info->sample_rate, NULL); // I'm fairly certain that status is always either 1 or 0 gps_info->is_fixed = (status) ? true : false; return 0; }
//callback that will run at datarate //data - array of spatial event data structures that holds the spatial data packets that were sent in this event //count - the number of spatial data event packets included in this event int CCONV spatial_on_data(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count) { PhidgetInfo *info = userptr; SpatialInfo *spatial_info = info->type_info; int i; for(i = 0; i < count; i++) { sample_tick(spatial_info->sample_rate, &data[i]->timestamp); // Set the values to where they need to be: for(int j=0; j < spatial_info->accelerometer_axes; j++) spatial_info->acceleration[j] = data[i]->acceleration[j]; spatial_info->is_acceleration_known = true; // Sometimes the compass will return nonesense in the form of this constant // I'm fairly certain that simply checking the first element of the array // will suffice, and when this is the case, we just keep the prior values: if (data[i]->magneticField[0] == PUNK_DBL) spatial_info->is_compass_known = false; else { for(int j=0; j < spatial_info->compass_axes; j++) spatial_info->compass[j] = data[i]->magneticField[j]; spatial_info->is_compass_known = true; } // Gyro Time! these get handled slightly different... double timestamp = data[i]->timestamp.seconds + data[i]->timestamp.microseconds/MICROSECONDS_IN_SECOND; double timechange = (spatial_info->last_microsecond > 0) ? timestamp - spatial_info->last_microsecond : 0; // This is kind of superceeded by the orientation_ functions, but I'm // leaving it in for posterity: for(int j=0; j < spatial_info->gyro_axes; j++) spatial_info->gyroscope[j] += data[i]->angularRate[j] * timechange; spatial_info->is_gyroscope_known = true; // If we're dealing with 3 dimensional sensors, we can calculate orientation: if (spatial_info->gyro_axes == 3) { // This is a shortcut to keep things DRY below: double angular_rate_in_rad[3]; for(int j=0; j < 3; j++) angular_rate_in_rad[j] = data[i]->angularRate[j] * M_PI/180; euler_to_3x3dcm((double *) &spatial_info->gyroscope_dcm, angular_rate_in_rad[0] * timechange, angular_rate_in_rad[1] * timechange, angular_rate_in_rad[2] * timechange, NULL); // Madgwick Orientation time - Update the ahrs: if (!spatial_info->is_ahrs_initialized) { if (spatial_info->is_compass_known) spatial_ahrs_init(spatial_info, data[i]->acceleration[0], data[i]->acceleration[1], data[i]->acceleration[2], data[i]->magneticField[0], data[i]->magneticField[1], data[i]->magneticField[2]); } else { float gx = (float) angular_rate_in_rad[0]; float gy = (float) angular_rate_in_rad[1]; float gz = (float) angular_rate_in_rad[2]; float ax = (float) data[i]->acceleration[0]; float ay = (float) data[i]->acceleration[1]; float az = (float) data[i]->acceleration[2]; if (spatial_info->is_compass_known) // We have enough info for a MARG update: spatial_ahrs_update(spatial_info, gx, gy, gz, ax, ay, az, (float) data[i]->magneticField[0], (float) data[i]->magneticField[1], (float) data[i]->magneticField[2]); else // We only have enough info for a IMU update: spatial_ahrs_update_imu(spatial_info, gx, gy, gz, ax, ay, az); } } // We'll need this on the next go around: spatial_info->last_microsecond = timestamp; } return 0; }
static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv) { struct xpp_drift *driftinfo = &xbus->drift; struct xpp_ticker *ticker = &xbus->ticker; unsigned long flags; bool cycled; spin_lock_irqsave(&driftinfo->lock, flags); cycled = xpp_ticker_step(&xbus->ticker, tv); if(ref_ticker && syncer && xbus->sync_mode == SYNC_MODE_PLL) { int new_delta_tick = ticker->count - ref_ticker->count; int lost_ticks = new_delta_tick - driftinfo->delta_tick; driftinfo->delta_tick = new_delta_tick; if(lost_ticks) { driftinfo->lost_ticks++; driftinfo->lost_tick_count += abs(lost_ticks); XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n", lost_ticks, (abs(lost_ticks) > 1) ? "s": ""); ticker->cycle = SYNC_ADJ_QUICK; if(abs(lost_ticks) > 100) ticker->count = ref_ticker->count; } else { long usec_delta; bool nofix = 0; usec_delta = (long)usec_diff( &ticker->last_sample.tv, &ref_ticker->last_sample.tv); usec_delta -= driftinfo->wanted_offset; sample_tick(xbus, usec_delta); if(abs(usec_delta) > 300) { /* * We are close to the edge, send a brutal * fix, and skip calculation until next time. */ if(usec_delta > 0 && xbus->sync_adjustment > -SYNC_ADJ_MAX) { XBUS_DBG(SYNC, xbus, "Pullback usec_delta=%ld\n", usec_delta); send_drift(xbus, -SYNC_ADJ_MAX); /* emergency push */ } if(usec_delta < 0 && xbus->sync_adjustment < SYNC_ADJ_MAX) { XBUS_DBG(SYNC, xbus, "Pushback usec_delta=%ld\n", usec_delta); send_drift(xbus, SYNC_ADJ_MAX); /* emergency push */ } ticker->cycle = SYNC_ADJ_QUICK; nofix = 1; } else { /* good data, use it */ if(usec_delta > driftinfo->delta_max) driftinfo->delta_max = usec_delta; if(usec_delta < driftinfo->delta_min) driftinfo->delta_min = usec_delta; } if(!nofix && cycled) { int offset = 0; driftinfo->median = (driftinfo->delta_max + driftinfo->delta_min) / 2; driftinfo->jitter = driftinfo->delta_max - driftinfo->delta_min; if(abs(driftinfo->median) >= 150) { /* more than 1 usb uframe */ int factor = abs(driftinfo->median) / 125; factor = 1 + (factor * 8000) / ticker->cycle; if(driftinfo->median > 0) offset = driftinfo->calc_drift - factor; else offset = driftinfo->calc_drift + factor; /* for large median, push some more */ if(abs(driftinfo->median) >= 300) { /* more than 2 usb uframes */ ticker->cycle = SYNC_ADJ_QUICK; XBUS_NOTICE(xbus, "Back to quick: median=%d\n", driftinfo->median); } } else { ticker->cycle += 500; if(ticker->cycle >= SYNC_ADJ_SLOW) ticker->cycle = SYNC_ADJ_SLOW; } driftinfo->calc_drift = offset; XBUS_DBG(SYNC, xbus, "ADJ: min=%d max=%d jitter=%d median=%d offset=%d\n", driftinfo->delta_min, driftinfo->delta_max, driftinfo->jitter, driftinfo->median, offset); if(offset < -SYNC_ADJ_MAX) offset = -SYNC_ADJ_MAX; if(offset > SYNC_ADJ_MAX) offset = SYNC_ADJ_MAX; xbus->sync_adjustment_offset = offset; if(xbus != syncer && xbus->sync_adjustment != offset) send_drift(xbus, offset); driftinfo_recalc(driftinfo); } } } spin_unlock_irqrestore(&driftinfo->lock, flags); }