Last active
March 2, 2025 11:01
-
-
Save GOROman/e044a2de4636df5ba37884f20b882b76 to your computer and use it in GitHub Desktop.
#がいためIMU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**************************************************************************** | |
* examples/cxd5602pwbimu/cxd5602pwbimu_main.c | |
* | |
* Copyright 2025 Sony Semiconductor Solutions Corporation | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in | |
* the documentation and/or other materials provided with the | |
* distribution. | |
* 3. Neither the name of Sony Semiconductor Solutions Corporation nor | |
* the names of its contributors may be used to endorse or promote | |
* products derived from this software without specific prior written | |
* permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
* | |
****************************************************************************/ | |
/**************************************************************************** | |
* Included Files | |
****************************************************************************/ | |
#include <nuttx/config.h> | |
#include <sys/ioctl.h> | |
#include <time.h> | |
#include <inttypes.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <signal.h> | |
#include <poll.h> | |
#include <errno.h> | |
#include <nuttx/sensors/cxd5602pwbimu.h> | |
#include <math.h> | |
/**************************************************************************** | |
* Pre-processor Definitions | |
****************************************************************************/ | |
#define CXD5602PWBIMU_DEVPATH "/dev/imu0" | |
#define itemsof(a) (sizeof(a)/sizeof(a[0])) | |
/* 重力加速度 (m/s^2) */ | |
#define GRAVITY_EARTH 9.80665f | |
/* 角度変換 */ | |
#define DEG_TO_RAD (M_PI / 180.0f) | |
#define RAD_TO_DEG (180.0f / M_PI) | |
/* カルマンフィルタのパラメータ */ | |
#define KF_ACCEL_NOISE 0.05f /* 加速度計測ノイズ */ | |
#define KF_GYRO_NOISE 0.01f /* ジャイロ計測ノイズ */ | |
#define KF_ACCEL_BIAS_NOISE 0.005f /* 加速度バイアスノイズ */ | |
#define KF_GYRO_BIAS_NOISE 0.003f /* ジャイロバイアスノイズ */ | |
#define KF_INIT_COV 1000.0f /* 初期共分散 */ | |
/**************************************************************************** | |
* Private values | |
****************************************************************************/ | |
/* クォータニオン構造体 */ | |
typedef struct { | |
float w, x, y, z; | |
} quaternion_t; | |
/* オイラー角構造体 */ | |
typedef struct { | |
float roll; /* x軸周りの回転 (ラジアン) */ | |
float pitch; /* y軸周りの回転 (ラジアン) */ | |
float yaw; /* z軸周りの回転 (ラジアン) */ | |
} euler_t; | |
/* 3次元ベクトル構造体 */ | |
typedef struct { | |
float x, y, z; | |
} vector3_t; | |
/* カルマンフィルタ状態 */ | |
typedef struct { | |
/* 状態ベクトル */ | |
quaternion_t q; /* 姿勢クォータニオン */ | |
vector3_t gyro_bias; /* ジャイロバイアス */ | |
vector3_t vel; /* 速度 */ | |
vector3_t pos; /* 位置 */ | |
/* 共分散行列 (簡略化のため対角成分のみ) */ | |
float P_q[4]; /* クォータニオン共分散 */ | |
float P_gyro_bias[3]; /* ジャイロバイアス共分散 */ | |
float P_vel[3]; /* 速度共分散 */ | |
float P_pos[3]; /* 位置共分散 */ | |
/* 前回の時間 */ | |
float last_time; | |
/* 初期化フラグ */ | |
int initialized; | |
} kalman_state_t; | |
/**************************************************************************** | |
* Private Functions | |
****************************************************************************/ | |
/* クォータニオンの初期化 */ | |
static void quaternion_init(quaternion_t *q) | |
{ | |
q->w = 1.0f; | |
q->x = 0.0f; | |
q->y = 0.0f; | |
q->z = 0.0f; | |
} | |
/* クォータニオンの正規化 */ | |
static void quaternion_normalize(quaternion_t *q) | |
{ | |
float norm = sqrtf(q->w * q->w + q->x * q->x + q->y * q->y + q->z * q->z); | |
if (norm > 0.0f) | |
{ | |
q->w /= norm; | |
q->x /= norm; | |
q->y /= norm; | |
q->z /= norm; | |
} | |
} | |
/* クォータニオンからオイラー角への変換 */ | |
static void quaternion_to_euler(const quaternion_t *q, euler_t *euler) | |
{ | |
/* ロール (x軸周り) */ | |
euler->roll = atan2f(2.0f * (q->w * q->x + q->y * q->z), | |
1.0f - 2.0f * (q->x * q->x + q->y * q->y)); | |
/* ピッチ (y軸周り) */ | |
float sinp = 2.0f * (q->w * q->y - q->z * q->x); | |
if (fabsf(sinp) >= 1.0f) | |
{ | |
euler->pitch = copysignf(M_PI / 2.0f, sinp); /* 90度に制限 */ | |
} | |
else | |
{ | |
euler->pitch = asinf(sinp); | |
} | |
/* ヨー (z軸周り) */ | |
euler->yaw = atan2f(2.0f * (q->w * q->z + q->x * q->y), | |
1.0f - 2.0f * (q->y * q->y + q->z * q->z)); | |
} | |
/* クォータニオンの積 q = q1 * q2 */ | |
static void quaternion_multiply(const quaternion_t *q1, const quaternion_t *q2, quaternion_t *result) | |
{ | |
result->w = q1->w * q2->w - q1->x * q2->x - q1->y * q2->y - q1->z * q2->z; | |
result->x = q1->w * q2->x + q1->x * q2->w + q1->y * q2->z - q1->z * q2->y; | |
result->y = q1->w * q2->y - q1->x * q2->z + q1->y * q2->w + q1->z * q2->x; | |
result->z = q1->w * q2->z + q1->x * q2->y - q1->y * q2->x + q1->z * q2->w; | |
} | |
/* 角速度からクォータニオン変化率を計算 */ | |
static void gyro_to_quaternion_derivative(const quaternion_t *q, const vector3_t *gyro, quaternion_t *dq) | |
{ | |
dq->w = -0.5f * (q->x * gyro->x + q->y * gyro->y + q->z * gyro->z); | |
dq->x = 0.5f * (q->w * gyro->x + q->y * gyro->z - q->z * gyro->y); | |
dq->y = 0.5f * (q->w * gyro->y - q->x * gyro->z + q->z * gyro->x); | |
dq->z = 0.5f * (q->w * gyro->z + q->x * gyro->y - q->y * gyro->x); | |
} | |
/* クォータニオンによるベクトル回転 v' = q * v * q^-1 */ | |
static void quaternion_rotate_vector(const quaternion_t *q, const vector3_t *v, vector3_t *result) | |
{ | |
quaternion_t p = {0, v->x, v->y, v->z}; | |
quaternion_t q_inv = {q->w, -q->x, -q->y, -q->z}; | |
quaternion_t temp, temp2; | |
quaternion_multiply(q, &p, &temp); | |
quaternion_multiply(&temp, &q_inv, &temp2); | |
result->x = temp2.x; | |
result->y = temp2.y; | |
result->z = temp2.z; | |
} | |
/* カルマンフィルタの初期化 */ | |
static void kalman_filter_init(kalman_state_t *kf) | |
{ | |
/* クォータニオンの初期化 */ | |
quaternion_init(&kf->q); | |
/* バイアスの初期化 */ | |
kf->gyro_bias.x = 0.0f; | |
kf->gyro_bias.y = 0.0f; | |
kf->gyro_bias.z = 0.0f; | |
/* 速度と位置の初期化 */ | |
kf->vel.x = 0.0f; | |
kf->vel.y = 0.0f; | |
kf->vel.z = 0.0f; | |
kf->pos.x = 0.0f; | |
kf->pos.y = 0.0f; | |
kf->pos.z = 0.0f; | |
/* 共分散行列の初期化 */ | |
for (int i = 0; i < 4; i++) | |
{ | |
kf->P_q[i] = KF_INIT_COV; | |
} | |
for (int i = 0; i < 3; i++) | |
{ | |
kf->P_gyro_bias[i] = KF_INIT_COV; | |
kf->P_vel[i] = KF_INIT_COV; | |
kf->P_pos[i] = KF_INIT_COV; | |
} | |
kf->initialized = 0; | |
} | |
/* カルマンフィルタの更新 */ | |
static void kalman_filter_update(kalman_state_t *kf, | |
float gx, float gy, float gz, | |
float ax, float ay, float az, | |
float timestamp) | |
{ | |
float dt; | |
vector3_t gyro, accel, accel_earth, accel_motion; | |
quaternion_t dq, q_pred; | |
/* 初回の場合、時間を初期化 */ | |
if (!kf->initialized) | |
{ | |
kf->last_time = timestamp; | |
kf->initialized = 1; | |
return; | |
} | |
/* 時間差分の計算 */ | |
dt = timestamp - kf->last_time; | |
kf->last_time = timestamp; | |
if (dt <= 0.0f || dt > 0.1f) | |
{ | |
/* 異常な時間差分は無視 */ | |
return; | |
} | |
/* センサーデータの取得 */ | |
gyro.x = gx - kf->gyro_bias.x; | |
gyro.y = gy - kf->gyro_bias.y; | |
gyro.z = gz - kf->gyro_bias.z; | |
accel.x = ax; | |
accel.y = ay; | |
accel.z = az; | |
/* 予測ステップ */ | |
/* クォータニオンの更新 */ | |
gyro_to_quaternion_derivative(&kf->q, &gyro, &dq); | |
q_pred.w = kf->q.w + dq.w * dt; | |
q_pred.x = kf->q.x + dq.x * dt; | |
q_pred.y = kf->q.y + dq.y * dt; | |
q_pred.z = kf->q.z + dq.z * dt; | |
quaternion_normalize(&q_pred); | |
/* 共分散の更新 */ | |
for (int i = 0; i < 4; i++) | |
{ | |
kf->P_q[i] += KF_GYRO_NOISE * dt; | |
} | |
for (int i = 0; i < 3; i++) | |
{ | |
kf->P_gyro_bias[i] += KF_GYRO_BIAS_NOISE * dt; | |
} | |
/* 姿勢の更新 */ | |
kf->q = q_pred; | |
/* 加速度を地球座標系に変換 */ | |
quaternion_rotate_vector(&kf->q, &accel, &accel_earth); | |
/* 重力成分の除去 */ | |
accel_motion.x = accel_earth.x; | |
accel_motion.y = accel_earth.y; | |
accel_motion.z = accel_earth.z - GRAVITY_EARTH; | |
/* 速度の更新 */ | |
kf->vel.x += accel_motion.x * dt; | |
kf->vel.y += accel_motion.y * dt; | |
kf->vel.z += accel_motion.z * dt; | |
/* 位置の更新 */ | |
kf->pos.x += kf->vel.x * dt; | |
kf->pos.y += kf->vel.y * dt; | |
kf->pos.z += kf->vel.z * dt; | |
/* 速度と位置の共分散更新 */ | |
for (int i = 0; i < 3; i++) | |
{ | |
kf->P_vel[i] += KF_ACCEL_NOISE * dt * dt; | |
kf->P_pos[i] += kf->P_vel[i] * dt * dt; | |
} | |
/* 補正ステップ - 観測更新 */ | |
/* 静止状態の検出(加速度の大きさが重力に近いかチェック) */ | |
float accel_magnitude = sqrtf(ax * ax + ay * ay + az * az); | |
float accel_diff = fabsf(accel_magnitude - GRAVITY_EARTH); | |
/* 静止状態と判断できる場合、姿勢を補正 */ | |
if (accel_diff < 0.5f) /* 閾値: 0.5 m/s^2 */ | |
{ | |
/* 加速度から推定される重力方向 */ | |
vector3_t gravity_measured = {ax, ay, az}; | |
float gravity_norm = sqrtf(ax * ax + ay * ay + az * az); | |
/* 正規化 */ | |
if (gravity_norm > 0.0f) | |
{ | |
gravity_measured.x /= gravity_norm; | |
gravity_measured.y /= gravity_norm; | |
gravity_measured.z /= gravity_norm; | |
} | |
/* 現在の姿勢から予測される重力方向 */ | |
vector3_t gravity_predicted = {0.0f, 0.0f, 1.0f}; /* 地球座標系での重力方向 */ | |
vector3_t gravity_body; | |
/* 地球座標系から機体座標系への変換(クォータニオンの逆回転) */ | |
quaternion_t q_inv = {kf->q.w, -kf->q.x, -kf->q.y, -kf->q.z}; | |
quaternion_rotate_vector(&q_inv, &gravity_predicted, &gravity_body); | |
/* 測定値と予測値の差(クロス積)から回転軸を計算 */ | |
vector3_t correction; | |
correction.x = gravity_measured.y * gravity_body.z - gravity_measured.z * gravity_body.y; | |
correction.y = gravity_measured.z * gravity_body.x - gravity_measured.x * gravity_body.z; | |
correction.z = gravity_measured.x * gravity_body.y - gravity_measured.y * gravity_body.x; | |
/* カルマンゲインの計算 */ | |
/* 観測ノイズ共分散(加速度計の信頼度) */ | |
float R_accel = 0.1f + 10.0f * accel_diff; /* 加速度の変動が大きいほど信頼度を下げる */ | |
/* 姿勢のカルマンゲイン計算 */ | |
float K_q[4]; | |
for (int i = 0; i < 4; i++) | |
{ | |
/* K = P / (P + R) */ | |
K_q[i] = kf->P_q[i] / (kf->P_q[i] + R_accel); | |
/* 共分散の更新 P = (1 - K) * P */ | |
kf->P_q[i] = (1.0f - K_q[i]) * kf->P_q[i]; | |
} | |
/* ジャイロバイアスのカルマンゲイン計算 */ | |
float K_gyro_bias[3]; | |
for (int i = 0; i < 3; i++) | |
{ | |
/* バイアスは姿勢よりもゆっくり更新 */ | |
K_gyro_bias[i] = kf->P_gyro_bias[i] / (kf->P_gyro_bias[i] + R_accel * 10.0f); | |
/* 共分散の更新 */ | |
kf->P_gyro_bias[i] = (1.0f - K_gyro_bias[i]) * kf->P_gyro_bias[i]; | |
} | |
/* 速度のカルマンゲイン計算(静止状態では速度は0に近づける) */ | |
float K_vel[3]; | |
for (int i = 0; i < 3; i++) | |
{ | |
K_vel[i] = kf->P_vel[i] / (kf->P_vel[i] + R_accel * 0.5f); | |
/* 共分散の更新 */ | |
kf->P_vel[i] = (1.0f - K_vel[i]) * kf->P_vel[i]; | |
} | |
/* 姿勢の補正 */ | |
quaternion_t q_correction; | |
q_correction.w = 1.0f; | |
q_correction.x = correction.x * K_q[1] * 0.5f; | |
q_correction.y = correction.y * K_q[2] * 0.5f; | |
q_correction.z = correction.z * K_q[3] * 0.5f; | |
/* 正規化 */ | |
quaternion_normalize(&q_correction); | |
/* 姿勢の更新 */ | |
quaternion_t q_updated; | |
quaternion_multiply(&kf->q, &q_correction, &q_updated); | |
quaternion_normalize(&q_updated); | |
kf->q = q_updated; | |
/* ジャイロバイアスの更新 */ | |
kf->gyro_bias.x += correction.x * K_gyro_bias[0]; | |
kf->gyro_bias.y += correction.y * K_gyro_bias[1]; | |
kf->gyro_bias.z += correction.z * K_gyro_bias[2]; | |
/* 速度ドリフトの補正(静止状態では速度は0に近づける) */ | |
kf->vel.x *= (1.0f - K_vel[0]); | |
kf->vel.y *= (1.0f - K_vel[1]); | |
kf->vel.z *= (1.0f - K_vel[2]); | |
} | |
} | |
/* 角速度と加速度の単位変換 */ | |
static void convert_sensor_data(cxd5602pwbimu_data_t *data, int adrange, int gdrange, | |
float *gx, float *gy, float *gz, | |
float *ax, float *ay, float *az) | |
{ | |
/* 角速度の単位変換 (raw -> rad/s) */ | |
float gyro_scale; | |
switch (gdrange) | |
{ | |
case 125: gyro_scale = 125.0f / 32768.0f * DEG_TO_RAD; break; | |
case 250: gyro_scale = 250.0f / 32768.0f * DEG_TO_RAD; break; | |
case 500: gyro_scale = 500.0f / 32768.0f * DEG_TO_RAD; break; | |
case 1000: gyro_scale = 1000.0f / 32768.0f * DEG_TO_RAD; break; | |
case 2000: gyro_scale = 2000.0f / 32768.0f * DEG_TO_RAD; break; | |
case 4000: gyro_scale = 4000.0f / 32768.0f * DEG_TO_RAD; break; | |
default: gyro_scale = 125.0f / 32768.0f * DEG_TO_RAD; | |
} | |
*gx = data->gx * gyro_scale; | |
*gy = data->gy * gyro_scale; | |
*gz = data->gz * gyro_scale; | |
/* 加速度の単位変換 (raw -> m/s^2) */ | |
float accel_scale; | |
switch (adrange) | |
{ | |
case 2: accel_scale = 2.0f / 32768.0f * GRAVITY_EARTH; break; | |
case 4: accel_scale = 4.0f / 32768.0f * GRAVITY_EARTH; break; | |
case 8: accel_scale = 8.0f / 32768.0f * GRAVITY_EARTH; break; | |
case 16: accel_scale = 16.0f / 32768.0f * GRAVITY_EARTH; break; | |
default: accel_scale = 2.0f / 32768.0f * GRAVITY_EARTH; | |
} | |
*ax = data->ax * accel_scale; | |
*ay = data->ay * accel_scale; | |
*az = data->az * accel_scale; | |
} | |
static int start_sensing(int fd, int rate, int adrange, int gdrange, | |
int nfifos) | |
{ | |
cxd5602pwbimu_range_t range; | |
int ret; | |
/* | |
* Set sampling rate. Available values (Hz) are below. | |
* | |
* 15 (default), 30, 60, 120, 240, 480, 960, 1920 | |
*/ | |
ret = ioctl(fd, SNIOC_SSAMPRATE, rate); | |
if (ret) | |
{ | |
printf("ERROR: Set sampling rate failed. %d\n", errno); | |
return 1; | |
} | |
/* | |
* Set dynamic ranges for accelerometer and gyroscope. | |
* Available values are below. | |
* | |
* accel: 2 (default), 4, 8, 16 | |
* gyro: 125 (default), 250, 500, 1000, 2000, 4000 | |
*/ | |
range.accel = adrange; | |
range.gyro = gdrange; | |
ret = ioctl(fd, SNIOC_SDRANGE, (unsigned long)(uintptr_t)&range); | |
if (ret) | |
{ | |
printf("ERROR: Set dynamic range failed. %d\n", errno); | |
return 1; | |
} | |
/* | |
* Set hardware FIFO threshold. | |
* Increasing this value will reduce the frequency with which data is | |
* received. | |
*/ | |
ret = ioctl(fd, SNIOC_SFIFOTHRESH, nfifos); | |
if (ret) | |
{ | |
printf("ERROR: Set sampling rate failed. %d\n", errno); | |
return 1; | |
} | |
/* | |
* Start sensing, user can not change the all of configurations. | |
*/ | |
ret = ioctl(fd, SNIOC_ENABLE, 1); | |
if (ret) | |
{ | |
printf("ERROR: Enable failed. %d\n", errno); | |
return 1; | |
} | |
return 0; | |
} | |
/**************************************************************************** | |
* Public Functions | |
****************************************************************************/ | |
/**************************************************************************** | |
* sensor_main | |
****************************************************************************/ | |
int main(int argc, FAR char *argv[]) | |
{ | |
int fd; | |
int ret; | |
struct pollfd fds[1]; | |
struct timespec start, now, delta; | |
cxd5602pwbimu_data_t *outbuf = NULL; | |
cxd5602pwbimu_data_t *p = NULL; | |
cxd5602pwbimu_data_t *last; | |
kalman_state_t kf; | |
float gx, gy, gz; /* 角速度 (rad/s) */ | |
float ax, ay, az; /* 加速度 (m/s^2) */ | |
euler_t euler = {0.0f, 0.0f, 0.0f}; /* オイラー角(初期値は0) */ | |
int running_time = 10; /* 実行時間(秒) */ | |
/* コマンドライン引数から実行時間を取得 */ | |
if (argc > 1) | |
{ | |
running_time = atoi(argv[1]); | |
if (running_time <= 0) | |
{ | |
running_time = 10; | |
} | |
} | |
/* Sensing parameters, see start sensing function. */ | |
printf("IMUセンシング開始 - 数値積分による絶対座標推定\n"); | |
printf("実行時間: %d秒\n", running_time); | |
/* 高精度な動き分析のためのパラメータ */ | |
const int samplerate = 960; /* サンプリングレート (Hz) */ | |
const int adrange = 4; /* 加速度レンジ (±4G) */ | |
const int gdrange = 500; /* 角速度レンジ (±500dps) */ | |
const int nfifos = 1; /* FIFOしきい値 */ | |
/* カルマンフィルタの初期化 */ | |
kalman_filter_init(&kf); | |
fd = open(CXD5602PWBIMU_DEVPATH, O_RDONLY); | |
if (fd < 0) | |
{ | |
printf("ERROR: デバイス %s のオープンに失敗しました。 %d\n", CXD5602PWBIMU_DEVPATH, errno); | |
return 1; | |
} | |
outbuf = (cxd5602pwbimu_data_t *)malloc(sizeof(cxd5602pwbimu_data_t) * samplerate * running_time); | |
if (outbuf == NULL) | |
{ | |
printf("ERROR: 出力バッファの割り当てに失敗しました。\n"); | |
close(fd); | |
return 1; | |
} | |
last = outbuf + samplerate * running_time; | |
fds[0].fd = fd; | |
fds[0].events = POLLIN; | |
ret = start_sensing(fd, samplerate, adrange, gdrange, nfifos); | |
if (ret) | |
{ | |
close(fd); | |
free(outbuf); | |
return ret; | |
} | |
memset(&now, 0, sizeof(now)); | |
/* ヘッダー出力 */ | |
printf("時間(秒),温度(℃),ロール(度),ピッチ(度),ヨー(度),速度X(m/s),速度Y(m/s),速度Z(m/s),位置X(mm),位置Y(mm),位置Z(mm)\n"); | |
for (p = outbuf; p < last; p++) | |
{ | |
ret = poll(fds, 1, 1000); | |
if (ret < 0) | |
{ | |
if (errno != EINTR) | |
{ | |
printf("ERROR: pollに失敗しました。 %d\n", errno); | |
} | |
break; | |
} | |
if (ret == 0) | |
{ | |
printf("タイムアウト!\n"); | |
continue; | |
} | |
if (p == outbuf) | |
{ | |
/* 最初のセンシング遅延を除去するため、最初のデータ取得から時間測定を開始 */ | |
clock_gettime(CLOCK_MONOTONIC, &start); | |
} | |
if (fds[0].revents & POLLIN) | |
{ | |
ret = read(fd, p, sizeof(*p)); | |
if (ret != sizeof(*p)) | |
{ | |
printf("ERROR: 読み取りサイズが一致しません! %d\n", ret); | |
continue; | |
} | |
/* センサーデータを物理単位に変換 */ | |
convert_sensor_data(p, adrange, gdrange, &gx, &gy, &gz, &ax, &ay, &az); | |
/* カルマンフィルタで姿勢、速度、位置を更新 */ | |
float timestamp = p->timestamp / 19200000.0f; /* 秒単位に変換 */ | |
kalman_filter_update(&kf, gx, gy, gz, ax, ay, az, timestamp); | |
/* クォータニオンからオイラー角に変換 */ | |
quaternion_to_euler(&kf.q, &euler); | |
/* 結果を表示(位置はmmに変換) */ | |
printf("%.6f,%.2f,%.2f,%.2f,%.2f,%.4f,%.4f,%.4f,%.2f,%.2f,%.2f\n", | |
timestamp, | |
p->temp, | |
euler.roll * RAD_TO_DEG, /* ロール角(度) */ | |
euler.pitch * RAD_TO_DEG, /* ピッチ角(度) */ | |
euler.yaw * RAD_TO_DEG, /* ヨー角(度) */ | |
kf.vel.x, kf.vel.y, kf.vel.z, /* 速度(m/s) */ | |
kf.pos.x * 1000.0f, kf.pos.y * 1000.0f, kf.pos.z * 1000.0f); /* 位置(mm) */ | |
} | |
clock_gettime(CLOCK_MONOTONIC, &now); | |
clock_timespec_subtract(&now, &start, &delta); | |
if (delta.tv_sec >= running_time) | |
{ | |
break; | |
} | |
} | |
/* 最新の書き込み位置を保存 */ | |
last = p; | |
close(fd); | |
/* 統計情報の表示 */ | |
clock_timespec_subtract(&now, &start, &delta); | |
printf("\n計測統計:\n"); | |
printf("経過時間: %ld.%09ld 秒\n", delta.tv_sec, delta.tv_nsec); | |
printf("取得サンプル数: %d\n", last - outbuf); | |
printf("実効サンプリングレート: %.2f Hz\n", (float)(last - outbuf) / ((float)delta.tv_sec + delta.tv_nsec / 1000000000.0f)); | |
printf("最終位置: X=%.2f mm, Y=%.2f mm, Z=%.2f mm\n", | |
kf.pos.x * 1000.0f, kf.pos.y * 1000.0f, kf.pos.z * 1000.0f); | |
printf("最終姿勢: ロール=%.2f°, ピッチ=%.2f°, ヨー=%.2f°\n", | |
euler.roll * RAD_TO_DEG, euler.pitch * RAD_TO_DEG, euler.yaw * RAD_TO_DEG); | |
printf("完了しました。\n"); | |
/* 追加: リソースのクリーンアップ */ | |
free(outbuf); | |
return 0; | |
} |
Author
GOROman
commented
Mar 1, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment