Send calibration data (on keystroke, Linux cmdline only)
This commit is contained in:
parent
9d108fedb3
commit
61cab7d7cd
5 changed files with 139 additions and 3 deletions
18
imuread.c
18
imuread.c
|
|
@ -21,6 +21,23 @@ static void glut_display_callback(void)
|
||||||
glutSwapBuffers();
|
glutSwapBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void glut_keystroke_callback(unsigned char ch, int x, int y)
|
||||||
|
{
|
||||||
|
if (magcal.fFitErrorpc > 9.0) {
|
||||||
|
printf("Poor Calibration: ");
|
||||||
|
printf("soft iron fit error = %.1f%%\n", magcal.fFitErrorpc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("Magnetic Calibration: (%.1f%% fit error)\n", magcal.fFitErrorpc);
|
||||||
|
printf(" %7.2f %6.3f %6.3f %6.3f\n",
|
||||||
|
magcal.fV[0], magcal.finvW[0][0], magcal.finvW[0][1], magcal.finvW[0][2]);
|
||||||
|
printf(" %7.2f %6.3f %6.3f %6.3f\n",
|
||||||
|
magcal.fV[1], magcal.finvW[1][0], magcal.finvW[1][1], magcal.finvW[1][2]);
|
||||||
|
printf(" %7.2f %6.3f %6.3f %6.3f\n",
|
||||||
|
magcal.fV[2], magcal.finvW[2][0], magcal.finvW[2][1], magcal.finvW[2][2]);
|
||||||
|
send_calibration();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
raw_data_reset();
|
raw_data_reset();
|
||||||
|
|
@ -35,6 +52,7 @@ int main(int argc, char *argv[])
|
||||||
glutReshapeFunc(resize_callback);
|
glutReshapeFunc(resize_callback);
|
||||||
glutDisplayFunc(glut_display_callback);
|
glutDisplayFunc(glut_display_callback);
|
||||||
glutTimerFunc(TIMEOUT_MSEC, timer_callback, 0);
|
glutTimerFunc(TIMEOUT_MSEC, timer_callback, 0);
|
||||||
|
glutKeyboardFunc(glut_keystroke_callback);
|
||||||
|
|
||||||
if (!open_port(PORT)) die("Unable to open %s\n", PORT);
|
if (!open_port(PORT)) die("Unable to open %s\n", PORT);
|
||||||
glutMainLoop();
|
glutMainLoop();
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,11 @@ extern Quaternion_t current_orientation;
|
||||||
|
|
||||||
extern int open_port(const char *name);
|
extern int open_port(const char *name);
|
||||||
extern int read_serial_data(void);
|
extern int read_serial_data(void);
|
||||||
|
extern int write_serial_data(const void *ptr, int len);
|
||||||
extern void close_port(void);
|
extern void close_port(void);
|
||||||
void raw_data_reset(void);
|
void raw_data_reset(void);
|
||||||
void raw_data(const int16_t *data);
|
void raw_data(const int16_t *data);
|
||||||
|
int send_calibration(void);
|
||||||
void visualize_init(void);
|
void visualize_init(void);
|
||||||
void apply_calibration(int16_t rawx, int16_t rawy, int16_t rawz, Point_t *out);
|
void apply_calibration(int16_t rawx, int16_t rawy, int16_t rawz, Point_t *out);
|
||||||
void display_callback(void);
|
void display_callback(void);
|
||||||
|
|
@ -79,6 +81,7 @@ typedef struct {
|
||||||
float fB; // current geomagnetic field magnitude (uT)
|
float fB; // current geomagnetic field magnitude (uT)
|
||||||
float fFourBsq; // current 4*B*B (uT^2)
|
float fFourBsq; // current 4*B*B (uT^2)
|
||||||
float fFitErrorpc; // current fit error %
|
float fFitErrorpc; // current fit error %
|
||||||
|
float fFitErrorAge; // current fit error % (grows automatically with age)
|
||||||
float ftrV[3]; // trial value of hard iron offset z, y, z (uT)
|
float ftrV[3]; // trial value of hard iron offset z, y, z (uT)
|
||||||
float ftrinvW[3][3]; // trial inverse soft iron matrix size
|
float ftrinvW[3][3]; // trial inverse soft iron matrix size
|
||||||
float ftrB; // trial value of geomagnetic field magnitude in uT
|
float ftrB; // trial value of geomagnetic field magnitude in uT
|
||||||
|
|
|
||||||
5
magcal.c
5
magcal.c
|
|
@ -75,7 +75,7 @@ void MagCal_Run(void)
|
||||||
|
|
||||||
if (magcal.iValidMagCal) {
|
if (magcal.iValidMagCal) {
|
||||||
// age the existing fit error to avoid one good calibration locking out future updates
|
// age the existing fit error to avoid one good calibration locking out future updates
|
||||||
magcal.fFitErrorpc *= 1.02f;
|
magcal.fFitErrorAge *= 1.01f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// is enough data collected
|
// is enough data collected
|
||||||
|
|
@ -97,12 +97,13 @@ void MagCal_Run(void)
|
||||||
// 2: the calibration fit is reduced or
|
// 2: the calibration fit is reduced or
|
||||||
// 3: an improved solver was used giving a good trial calibration (4% or under)
|
// 3: an improved solver was used giving a good trial calibration (4% or under)
|
||||||
if ((magcal.iValidMagCal == 0) ||
|
if ((magcal.iValidMagCal == 0) ||
|
||||||
(magcal.ftrFitErrorpc <= magcal.fFitErrorpc) ||
|
(magcal.ftrFitErrorpc <= magcal.fFitErrorAge) ||
|
||||||
((isolver > magcal.iValidMagCal) && (magcal.ftrFitErrorpc <= 4.0F))) {
|
((isolver > magcal.iValidMagCal) && (magcal.ftrFitErrorpc <= 4.0F))) {
|
||||||
// accept the new calibration solution
|
// accept the new calibration solution
|
||||||
//printf("new magnetic cal, B=%.2f uT\n", magcal.ftrB);
|
//printf("new magnetic cal, B=%.2f uT\n", magcal.ftrB);
|
||||||
magcal.iValidMagCal = isolver;
|
magcal.iValidMagCal = isolver;
|
||||||
magcal.fFitErrorpc = magcal.ftrFitErrorpc;
|
magcal.fFitErrorpc = magcal.ftrFitErrorpc;
|
||||||
|
magcal.fFitErrorAge = magcal.ftrFitErrorpc;
|
||||||
magcal.fB = magcal.ftrB;
|
magcal.fB = magcal.ftrB;
|
||||||
magcal.fFourBsq = 4.0F * magcal.ftrB * magcal.ftrB;
|
magcal.fFourBsq = 4.0F * magcal.ftrB * magcal.ftrB;
|
||||||
for (i = X; i <= Z; i++) {
|
for (i = X; i <= Z; i++) {
|
||||||
|
|
|
||||||
56
rawdata.c
56
rawdata.c
|
|
@ -12,11 +12,12 @@ void raw_data_reset(void)
|
||||||
rawcount = OVERSAMPLE_RATIO;
|
rawcount = OVERSAMPLE_RATIO;
|
||||||
fInit_9DOF_GBY_KALMAN(&fusionstate, 100, OVERSAMPLE_RATIO);
|
fInit_9DOF_GBY_KALMAN(&fusionstate, 100, OVERSAMPLE_RATIO);
|
||||||
memset(&magcal, 0, sizeof(magcal));
|
memset(&magcal, 0, sizeof(magcal));
|
||||||
magcal.fV[1] = 10.0f;
|
|
||||||
magcal.fV[2] = 80.0f; // initial guess
|
magcal.fV[2] = 80.0f; // initial guess
|
||||||
magcal.finvW[0][0] = 1.0f;
|
magcal.finvW[0][0] = 1.0f;
|
||||||
magcal.finvW[1][1] = 1.0f;
|
magcal.finvW[1][1] = 1.0f;
|
||||||
magcal.finvW[2][2] = 1.0f;
|
magcal.finvW[2][2] = 1.0f;
|
||||||
|
magcal.fFitErrorpc = 100.0f;
|
||||||
|
magcal.fFitErrorAge = 100.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_magcal_data(const int16_t *data)
|
static void add_magcal_data(const int16_t *data)
|
||||||
|
|
@ -118,5 +119,58 @@ void raw_data(const int16_t *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t crc16(uint16_t crc, uint8_t data)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
crc ^= data;
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if (crc & 1) {
|
||||||
|
crc = (crc >> 1) ^ 0xA001;
|
||||||
|
} else {
|
||||||
|
crc = (crc >> 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t * copy_lsb_first(uint8_t *dst, float f)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
uint32_t n;
|
||||||
|
} data;
|
||||||
|
|
||||||
|
data.f = f;
|
||||||
|
*dst++ = data.n;
|
||||||
|
*dst++ = data.n >> 8;
|
||||||
|
*dst++ = data.n >> 16;
|
||||||
|
*dst++ = data.n >> 24;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_calibration(void)
|
||||||
|
{
|
||||||
|
uint8_t *p, buf[52];
|
||||||
|
uint16_t crc;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
*p++ = 117; // 2 byte signature
|
||||||
|
*p++ = 84;
|
||||||
|
for (i=0; i < 3; i++) {
|
||||||
|
p = copy_lsb_first(p, magcal.fV[i]); // 12 bytes offset/hardiron
|
||||||
|
}
|
||||||
|
for (i=0; i < 3; i++) {
|
||||||
|
for (j=0; j < 3; j++) {
|
||||||
|
p = copy_lsb_first(p, magcal.finvW[i][j]); // 36 bytes softiron
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crc = 0xFFFF;
|
||||||
|
for (i=0; i < 50; i++) {
|
||||||
|
crc = crc16(crc, buf[i]);
|
||||||
|
}
|
||||||
|
*p++ = crc; // 2 byte crc check
|
||||||
|
*p++ = crc >> 8;
|
||||||
|
return write_serial_data(buf, 52);
|
||||||
|
}
|
||||||
|
|
|
||||||
60
serialdata.c
60
serialdata.c
|
|
@ -240,6 +240,7 @@ static void newdata(const unsigned char *data, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(LINUX) || defined(MACOSX)
|
#if defined(LINUX) || defined(MACOSX)
|
||||||
|
|
||||||
static int portfd=-1;
|
static int portfd=-1;
|
||||||
|
|
@ -300,6 +301,34 @@ int read_serial_data(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int write_serial_data(const void *ptr, int len)
|
||||||
|
{
|
||||||
|
int n, written=0;
|
||||||
|
fd_set wfds;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
//printf("Write %d\n", len);
|
||||||
|
if (portfd < 0) return -1;
|
||||||
|
while (written < len) {
|
||||||
|
n = write(portfd, (const char *)ptr + written, len - written);
|
||||||
|
if (n < 0 && (errno == EAGAIN || errno == EINTR)) n = 0;
|
||||||
|
//printf("Write, n = %d\n", n);
|
||||||
|
if (n < 0) return -1;
|
||||||
|
if (n > 0) {
|
||||||
|
written += n;
|
||||||
|
} else {
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 5000;
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
FD_SET(portfd, &wfds);
|
||||||
|
n = select(portfd+1, NULL, &wfds, NULL, &tv);
|
||||||
|
if (n < 0 && errno == EINTR) n = 1;
|
||||||
|
if (n <= 0) return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
void close_port(void)
|
void close_port(void)
|
||||||
{
|
{
|
||||||
if (portfd >= 0) {
|
if (portfd >= 0) {
|
||||||
|
|
@ -425,6 +454,37 @@ int read_serial_data(void)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int write_serial_data(const void *ptr, int len)
|
||||||
|
{
|
||||||
|
DWORD num_written;
|
||||||
|
OVERLAPPED ov;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (ov.hEvent == NULL) return -1;
|
||||||
|
ov.Internal = ov.InternalHigh = 0;
|
||||||
|
ov.Offset = ov.OffsetHigh = 0;
|
||||||
|
if (WriteFile(port_handle, ptr, len, &num_written, &ov)) {
|
||||||
|
//printf("Write, immediate complete, num_written=%lu\n", num_written);
|
||||||
|
r = num_written;
|
||||||
|
} else {
|
||||||
|
if (GetLastError() == ERROR_IO_PENDING) {
|
||||||
|
if (GetOverlappedResult(port_handle, &ov, &num_written, TRUE)) {
|
||||||
|
//printf("Write, delayed, num_written=%lu\n", num_written);
|
||||||
|
r = num_written;
|
||||||
|
} else {
|
||||||
|
//printf("Write, delayed error\n");
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//printf("Write, error\n");
|
||||||
|
r = -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
CloseHandle(ov.hEvent);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void close_port(void)
|
void close_port(void)
|
||||||
{
|
{
|
||||||
CloseHandle(port_handle);
|
CloseHandle(port_handle);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue