mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-07-05 20:42:08 -07:00
Add Orientation Tracker
This commit is contained in:
parent
88c03aa744
commit
32e1539c22
6 changed files with 182 additions and 8 deletions
|
@ -35,7 +35,8 @@ set(HEADER_FILES
|
|||
include/chiaki/time.h
|
||||
include/chiaki/fec.h
|
||||
include/chiaki/regist.h
|
||||
include/chiaki/opusdecoder.h)
|
||||
include/chiaki/opusdecoder.h
|
||||
include/chiaki/orientation.h)
|
||||
|
||||
set(SOURCE_FILES
|
||||
src/common.c
|
||||
|
@ -73,7 +74,8 @@ set(SOURCE_FILES
|
|||
src/time.c
|
||||
src/fec
|
||||
src/regist.c
|
||||
src/opusdecoder.c)
|
||||
src/opusdecoder.c
|
||||
src/orientation.c)
|
||||
|
||||
if(CHIAKI_ENABLE_FFMPEG_DECODER)
|
||||
list(APPEND HEADER_FILES include/chiaki/ffmpegdecoder.h)
|
||||
|
|
43
lib/include/chiaki/orientation.h
Normal file
43
lib/include/chiaki/orientation.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL
|
||||
|
||||
#ifndef CHIAKI_ORIENTATION_H
|
||||
#define CHIAKI_ORIENTATION_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Quaternion orientation from accelerometer and gyroscope
|
||||
* using Madgwick's algorithm.
|
||||
* See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms
|
||||
*/
|
||||
typedef struct chiaki_orientation_t
|
||||
{
|
||||
float x, y, z, w;
|
||||
} ChiakiOrientation;
|
||||
|
||||
CHIAKI_EXPORT void chiaki_orientation_init(ChiakiOrientation *orient);
|
||||
CHIAKI_EXPORT void chiaki_orientation_update(ChiakiOrientation *orient, float gx, float gy, float gz, float ax, float ay, float az, float time_step_sec);
|
||||
|
||||
/**
|
||||
* Extension of ChiakiOrientation, also tracking an absolute timestamp
|
||||
*/
|
||||
typedef struct chiaki_orientation_tracker_t
|
||||
{
|
||||
ChiakiOrientation orient;
|
||||
uint32_t timestamp;
|
||||
bool first_sample;
|
||||
} ChiakiOrientationTracker;
|
||||
|
||||
CHIAKI_EXPORT void chiaki_orientation_tracker_init(ChiakiOrientationTracker *tracker);
|
||||
CHIAKI_EXPORT void chiaki_orientation_tracker_update(ChiakiOrientationTracker *tracker,
|
||||
float gx, float gy, float gz, float ax, float ay, float az, uint32_t timestamp_us);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CHIAKI_ORIENTATION_H
|
126
lib/src/orientation.c
Normal file
126
lib/src/orientation.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
// SPDX-License-Identifier: LicenseRef-AGPL-3.0-only-OpenSSL
|
||||
|
||||
#include <chiaki/orientation.h>
|
||||
|
||||
CHIAKI_EXPORT void chiaki_orientation_init(ChiakiOrientation *orient)
|
||||
{
|
||||
orient->x = orient->y = orient->z = 0.0f;
|
||||
orient->w = 1.0f;
|
||||
}
|
||||
|
||||
#define BETA 0.1f // 2 * proportional gain
|
||||
static float inv_sqrt(float x);
|
||||
|
||||
CHIAKI_EXPORT void chiaki_orientation_update(ChiakiOrientation *orient, float gx, float gy, float gz, float ax, float ay, float az, float time_step_sec)
|
||||
{
|
||||
float q0 = orient->w, q1 = orient->x, q2 = orient->y, q3 = orient->z;
|
||||
// Madgwick's IMU algorithm.
|
||||
// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms
|
||||
float recip_norm;
|
||||
float s0, s1, s2, s3;
|
||||
float q_dot1, q_dot2, q_dot3, q_dot4;
|
||||
float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3;
|
||||
|
||||
// Rate of change of quaternion from gyroscope
|
||||
q_dot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);
|
||||
q_dot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);
|
||||
q_dot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);
|
||||
q_dot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);
|
||||
|
||||
// Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
|
||||
if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f)))
|
||||
{
|
||||
// Normalise accelerometer measurement
|
||||
recip_norm = inv_sqrt(ax * ax + ay * ay + az * az);
|
||||
ax *= recip_norm;
|
||||
ay *= recip_norm;
|
||||
az *= recip_norm;
|
||||
|
||||
// Auxiliary variables to avoid repeated arithmetic
|
||||
_2q0 = 2.0f * q0;
|
||||
_2q1 = 2.0f * q1;
|
||||
_2q2 = 2.0f * q2;
|
||||
_2q3 = 2.0f * q3;
|
||||
_4q0 = 4.0f * q0;
|
||||
_4q1 = 4.0f * q1;
|
||||
_4q2 = 4.0f * q2;
|
||||
_8q1 = 8.0f * q1;
|
||||
_8q2 = 8.0f * q2;
|
||||
q0q0 = q0 * q0;
|
||||
q1q1 = q1 * q1;
|
||||
q2q2 = q2 * q2;
|
||||
q3q3 = q3 * q3;
|
||||
|
||||
// Gradient decent algorithm corrective step
|
||||
s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay;
|
||||
s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az;
|
||||
s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az;
|
||||
s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay;
|
||||
recip_norm = inv_sqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude
|
||||
s0 *= recip_norm;
|
||||
s1 *= recip_norm;
|
||||
s2 *= recip_norm;
|
||||
s3 *= recip_norm;
|
||||
|
||||
// Apply feedback step
|
||||
q_dot1 -= BETA * s0;
|
||||
q_dot2 -= BETA * s1;
|
||||
q_dot3 -= BETA * s2;
|
||||
q_dot4 -= BETA * s3;
|
||||
}
|
||||
|
||||
// Integrate rate of change of quaternion to yield quaternion
|
||||
q0 += q_dot1 * time_step_sec;
|
||||
q1 += q_dot2 * time_step_sec;
|
||||
q2 += q_dot3 * time_step_sec;
|
||||
q3 += q_dot4 * time_step_sec;
|
||||
|
||||
// Normalise quaternion
|
||||
recip_norm = inv_sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
|
||||
q0 *= recip_norm;
|
||||
q1 *= recip_norm;
|
||||
q2 *= recip_norm;
|
||||
q3 *= recip_norm;
|
||||
|
||||
orient->x = q1;
|
||||
orient->y = q2;
|
||||
orient->z = q3;
|
||||
orient->w = q0;
|
||||
}
|
||||
|
||||
static float inv_sqrt(float x)
|
||||
{
|
||||
// Fast inverse square-root
|
||||
// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
|
||||
float halfx = 0.5f * x;
|
||||
float y = x;
|
||||
long i = *(long*)&y;
|
||||
i = 0x5f3759df - (i>>1);
|
||||
y = *(float*)&i;
|
||||
y = y * (1.5f - (halfx * y * y));
|
||||
return y;
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT void chiaki_orientation_tracker_init(ChiakiOrientationTracker *tracker)
|
||||
{
|
||||
chiaki_orientation_init(&tracker->orient);
|
||||
tracker->timestamp = 0;
|
||||
tracker->first_sample = true;
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT void chiaki_orientation_tracker_update(ChiakiOrientationTracker *tracker,
|
||||
float gx, float gy, float gz, float ax, float ay, float az, uint32_t timestamp_us)
|
||||
{
|
||||
if(tracker->first_sample)
|
||||
{
|
||||
tracker->first_sample = false;
|
||||
tracker->timestamp = timestamp_us;
|
||||
return;
|
||||
}
|
||||
uint64_t delta_us = timestamp_us;
|
||||
if(delta_us < tracker->timestamp)
|
||||
delta_us += (1ULL << 32);
|
||||
delta_us -= tracker->timestamp;
|
||||
tracker->timestamp = timestamp_us;
|
||||
chiaki_orientation_update(&tracker->orient, gx, gy, gz, ax, ay, az, (float)delta_us / 1000000.0f);
|
||||
}
|
|
@ -44,7 +44,7 @@ void sigint(int s)
|
|||
|
||||
#define BAR_LENGTH 100
|
||||
#define BAR_MAX 2.0f
|
||||
#define BAR_MAX_GYRO 180.0f
|
||||
#define BAR_MAX_GYRO M_PI
|
||||
|
||||
void print_state()
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ void print_state()
|
|||
}
|
||||
bool cov = ((vals.v[b] < 0.0f) == (cur < 0.0f)) && fabsf(vals.v[b]) > fabsf(cur);
|
||||
float next = BAR_VAL(bi + 1);
|
||||
#define MARK_VAL (b > 2 ? 90.0f : 1.0f)
|
||||
#define MARK_VAL (b > 2 ? 0.5f * M_PI : 1.0f)
|
||||
bool mark = cur < -MARK_VAL && next >= -MARK_VAL || prev < MARK_VAL && cur >= MARK_VAL;
|
||||
buf[i++] = cov ? (mark ? '#' : '=') : (mark ? '.' : ' ');
|
||||
#undef BAR_VAL
|
||||
|
|
|
@ -80,7 +80,7 @@ typedef struct setsu_event_t
|
|||
struct
|
||||
{
|
||||
float accel_x, accel_y, accel_z; // unit is 1G
|
||||
float gyro_x, gyro_y, gyro_z; // unit is deg/sec
|
||||
float gyro_x, gyro_y, gyro_z; // unit is rad/sec
|
||||
uint32_t timestamp; // microseconds
|
||||
} motion;
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -22,6 +23,8 @@
|
|||
#define SETSU_LOG(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
#define DEG2RAD (2.0f * M_PI / 360.0f)
|
||||
|
||||
typedef struct setsu_avail_device_t
|
||||
{
|
||||
struct setsu_avail_device_t *next;
|
||||
|
@ -686,9 +689,9 @@ static void device_drain(Setsu *setsu, SetsuDevice *dev, SetsuEventCb cb, void *
|
|||
event.motion.accel_x = (float)dev->motion.accel_x / (float)dev->motion.accel_res_x;
|
||||
event.motion.accel_y = (float)dev->motion.accel_y / (float)dev->motion.accel_res_y;
|
||||
event.motion.accel_z = (float)dev->motion.accel_z / (float)dev->motion.accel_res_z;
|
||||
event.motion.gyro_x = (float)dev->motion.gyro_x / (float)dev->motion.gyro_res_x;
|
||||
event.motion.gyro_y = (float)dev->motion.gyro_y / (float)dev->motion.gyro_res_y;
|
||||
event.motion.gyro_z = (float)dev->motion.gyro_z / (float)dev->motion.gyro_res_z;
|
||||
event.motion.gyro_x = DEG2RAD * (float)dev->motion.gyro_x / (float)dev->motion.gyro_res_x;
|
||||
event.motion.gyro_y = DEG2RAD * (float)dev->motion.gyro_y / (float)dev->motion.gyro_res_y;
|
||||
event.motion.gyro_z = DEG2RAD * (float)dev->motion.gyro_z / (float)dev->motion.gyro_res_z;
|
||||
event.motion.timestamp = dev->motion.timestamp;
|
||||
SEND_EVENT();
|
||||
dev->motion.dirty = false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue