Gyroscope calculation - numerically integrating the angular velocity to get the current relative angle or the heading.
void gyro_init(uint8_t port, float lsb_us_per_deg, uint32_t time_ms) {
uint32_t samples;
uint32_t sum;
uint32_t start_time_ms;
_port = port;
_lsb_us_per_deg = lsb_us_per_deg;
// average some samples for offset
sum = 0.0;
samples = 0;
start_time_ms = get_time ();
while ( (get_time() - start_time_ms) < time_ms ) {
sum += analog_read (_port);
samples ++;
}
_offset = (uint16_t)(sum / samples);
_offset_fix = (sum % samples);
_fix_divisor = samples;
_theta = 0;
init_lock (&gyro_lock, "gyro lock");
create_thread (&gyro_update, STACK_DEFAULT, 0, "gyro");
}
int gyro_update(void) {
/* The units of theta are converter LSBs * ms
1 deg/s = 5mV = 0.256 LSB for ADXRS300, 12.5mV = 0.64LSB for ADXRS150
1 deg = 0.256LSB * 1000ms = 256 (stored in lsb_ms_per_deg)
To convert theta to degrees, divide by lsb_ms_per_deg. */
uint32_t delta_t_us, new_time_us, time_us;
int32_t analog_value, fix_value;
time_us = get_time_us();
for(;;) {
analog_value = (int32_t)analog_read(_port) - _offset;
new_time_us = get_time_us();
delta_t_us = (new_time_us - time_us);
int32_t dtheta = analog_value * delta_t_us;
fix_value = _offset_fix * delta_t_us;
/* This does the Riemann sum; CCW gyro output polarity is negative
when the gyro is visible from the top of the robot. */
acquire (&gyro_lock);
// accumulate fractional error
_theta_fix += fix_value;
// apply error correction
// negative because _offset is subtracted
// from dtheta
dtheta -= _theta_fix / _fix_divisor;
_theta_fix %= _fix_divisor;
// integrate angle
_theta -= dtheta;
release (&gyro_lock);
time_us = new_time_us;
yield();
}
return 0;
}
float gyro_get_degrees (void) {
acquire (&gyro_lock);
float result = _theta / _lsb_us_per_deg;
release (&gyro_lock);
return result;
float in;
acquire(&socket_lock);
write(sockfd, "a\n", 2);
read(sockfd, socket_buffer, SOCKET_BUF_SIZE);
sscanf(socket_buffer, "%f", &in);
release(&socket_lock);
return in;
}
void gyro_set_degrees (float deg) {
acquire (&gyro_lock);
_theta = deg * _lsb_us_per_deg;
release (&gyro_lock);
}