phidgets_native 0.2.1 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +17 -2
- data/README.rdoc +9 -1
- data/Rakefile +7 -6
- data/examples/spatial.rb +3 -2
- data/examples/test_throttle.rb +40 -0
- data/ext/phidgets_native/extconf.rb +10 -3
- data/ext/phidgets_native/phidgets_native.c +124 -0
- data/ext/phidgets_native/phidgets_native.h +39 -0
- data/ext/phidgets_native/spatial.c +405 -9
- data/ext/phidgets_native/spatial_ruby.c +407 -1
- data/phidgets_native.gemspec +2 -1
- metadata +40 -24
@@ -3,6 +3,9 @@
|
|
3
3
|
const char MSG_COMPASS_CORRECTION_NOT_ARRAY[] = "compass correction must be a 13 element array";
|
4
4
|
const char MSG_COMPASS_CORRECTION_MUST_BE_FLOAT[] = "compass correction elements must be float or fixnum";
|
5
5
|
const char MSG_DATA_RATE_MUST_BE_NUM[] = "data rate must be fixnum";
|
6
|
+
const char MSG_AROUND_MUST_BE_NUMERIC[] = "rotation angles must be fixnums or floats";
|
7
|
+
const char MSG_IN_ORDER_MUST_BE_STRING[] = "rotation order must be a string";
|
8
|
+
const char MSG_INVALID_ROTATION_AXIS[] = "invalid rotation axis in rotation order, must be x, y, or z";
|
6
9
|
|
7
10
|
/*
|
8
11
|
* Document-class: PhidgetsNative::Spatial < PhidgetsNative::Device
|
@@ -13,6 +16,10 @@ const char MSG_DATA_RATE_MUST_BE_NUM[] = "data rate must be fixnum";
|
|
13
16
|
*/
|
14
17
|
|
15
18
|
void Init_phidgets_native_spatial(VALUE m_Phidget) {
|
19
|
+
// We need this for the orientation code mostly:
|
20
|
+
rb_funcall(rb_mKernel, rb_intern("require"), 1, rb_str_new2("matrix"));
|
21
|
+
|
22
|
+
// And now attach methods to the object:
|
16
23
|
VALUE c_Device = rb_const_get(m_Phidget, rb_intern("Device"));
|
17
24
|
|
18
25
|
VALUE c_Spatial = rb_define_class_under(m_Phidget,"Spatial",c_Device);
|
@@ -311,7 +318,134 @@ void Init_phidgets_native_spatial(VALUE m_Phidget) {
|
|
311
318
|
*/
|
312
319
|
rb_define_method(c_Spatial, "data_rate", spatial_data_rate_get, 0);
|
313
320
|
|
321
|
+
/*
|
322
|
+
* call-seq:
|
323
|
+
* direction_cosine_matrix( FixNum around_x, FixNum around_y, FixNum around_z, String in_order = 'xyz' ) -> Matrix
|
324
|
+
* This private method is used internally to return a single direction cosine
|
325
|
+
* Matrix that represents the combined translations provided around the x,y,
|
326
|
+
* and z axis. The optional in_order will translate around the axis in the
|
327
|
+
* order provided. Angles are expected to be in radians.
|
328
|
+
*/
|
329
|
+
rb_define_private_method(c_Spatial, "direction_cosine_matrix", spatial_direction_cosine_matrix, -1);
|
330
|
+
|
331
|
+
/*
|
332
|
+
* call-seq:
|
333
|
+
* accelerometer_to_roll_and_pitch -> Array
|
334
|
+
* This private method is used internally to return an array whose first double
|
335
|
+
* contains the roll and whose second contains the pitch component of the
|
336
|
+
* acceleration. Values are expressed in radians.
|
337
|
+
*/
|
338
|
+
rb_define_private_method(c_Spatial, "accelerometer_to_roll_and_pitch", spatial_accelerometer_to_roll_and_pitch, 0);
|
339
|
+
|
340
|
+
/*
|
341
|
+
* call-seq:
|
342
|
+
* gravity_to_roll_and_pitch -> Array
|
343
|
+
* This private method is used to return an array whose first double
|
344
|
+
* contains the roll and whose second contains the pitch component of gravity.
|
345
|
+
* Currently, this method merely calls and returns the accelerometer_to_roll_and_pitch
|
346
|
+
* method. Feel free to override this method with your own, for more accurate
|
347
|
+
* compass results. Values are expressed in radians.
|
348
|
+
*/
|
349
|
+
rb_define_private_method(c_Spatial, "gravity_to_roll_and_pitch", spatial_gravity_to_roll_and_pitch, 0);
|
350
|
+
|
351
|
+
/*
|
352
|
+
* Document-method: accelerometer_to_euler
|
353
|
+
* call-seq:
|
354
|
+
* accelerometer_to_euler -> Array
|
355
|
+
*
|
356
|
+
* This method returns a three element array of euler angles (yaw, roll, pitch)
|
357
|
+
* representing the vector of acceleration, as currently reflected by the
|
358
|
+
* spatial sensor.
|
359
|
+
*/
|
360
|
+
rb_define_method(c_Spatial, "accelerometer_to_euler", spatial_accelerometer_to_euler, 0);
|
361
|
+
|
362
|
+
/*
|
363
|
+
* Document-method: compass_bearing
|
364
|
+
* call-seq:
|
365
|
+
* compass_bearing -> Float
|
366
|
+
*
|
367
|
+
* This method returns a float representing the compass' bearing, perpendicular to
|
368
|
+
* the ground plane, in radians. A radian of 'pi' is where the usb cable plugs in,
|
369
|
+
* and a radian of 0 is the opposite end (front) of the device. Note that this
|
370
|
+
* method returns the 'magnetic' North, and not 'true' North. Also note that
|
371
|
+
* accuracy is highly determined by the private method 'gravity_to_roll_and_pitch'.
|
372
|
+
* Currently, gravity is merely assumed to be the output of the
|
373
|
+
* accelerometer_to_roll_and_pitch method. Feel free to extend the Spatial class
|
374
|
+
* and override the gravity_to_roll_and_pitch method, if you feel you have
|
375
|
+
* a better way to determine gravity. Your override's return will be used
|
376
|
+
* automatically by this method, once defined.
|
377
|
+
*/
|
378
|
+
rb_define_method(c_Spatial, "compass_bearing", spatial_compass_bearing, 0);
|
379
|
+
|
380
|
+
/*
|
381
|
+
* Document-method: compass_bearing_to_euler
|
382
|
+
* call-seq:
|
383
|
+
* compass_bearing_to_euler -> Float
|
384
|
+
*
|
385
|
+
* Probably this isn't too useful, but it returns a three element array, of which
|
386
|
+
* the third element is the compass_bearing.
|
387
|
+
*/
|
388
|
+
rb_define_method(c_Spatial, "compass_bearing_to_euler", spatial_compass_bearing_to_euler, 0);
|
389
|
+
|
390
|
+
/*
|
391
|
+
* Document-method: accelerometer_to_dcm
|
392
|
+
* call-seq:
|
393
|
+
* accelerometer_to_dcm -> Matrix
|
394
|
+
*
|
395
|
+
* This method returns a 3x3 Matrix containing a direction cosine Matrix which
|
396
|
+
* represents the rotation of the current accelerometer value.
|
397
|
+
*/
|
398
|
+
rb_define_method(c_Spatial, "accelerometer_to_dcm", spatial_accelerometer_to_dcm, 0);
|
399
|
+
|
400
|
+
/*
|
401
|
+
* Document-method: compass_bearing_to_dcm
|
402
|
+
* call-seq:
|
403
|
+
* compass_bearing_to_dcm -> Matrix
|
404
|
+
*
|
405
|
+
* This method returns a 3x3 direction cosine Matrix which represents the
|
406
|
+
* rotation of the current compass_bearing vector in 3d space.
|
407
|
+
*/
|
408
|
+
rb_define_method(c_Spatial, "compass_bearing_to_dcm", spatial_compass_bearing_to_dcm, 0);
|
409
|
+
|
410
|
+
/*
|
411
|
+
* Document-method: gyro_to_dcm
|
412
|
+
* call-seq:
|
413
|
+
* gyro_to_dcm -> Matrix
|
414
|
+
*
|
415
|
+
* This method returns a 3x3 direction cosine Matrix which represents the
|
416
|
+
* rotation of the current gyroscope vector.
|
417
|
+
*/
|
418
|
+
rb_define_method(c_Spatial, "gyro_to_dcm", spatial_gyro_to_dcm, 0);
|
419
|
+
|
420
|
+
/*
|
421
|
+
* Document-method: orientation_to_quaternion
|
422
|
+
* call-seq:
|
423
|
+
* orientation_to_quaternion -> Array
|
424
|
+
*
|
425
|
+
* This method returns a 4 element array consisting of floats, which represent
|
426
|
+
* the estimated AHRS orientation of the phidget.
|
427
|
+
*/
|
428
|
+
rb_define_method(c_Spatial, "orientation_to_quaternion", spatial_orientation_to_quaternion, 0);
|
429
|
+
|
430
|
+
/*
|
431
|
+
* Document-method: orientation_to_dcm
|
432
|
+
* call-seq:
|
433
|
+
* orientation_to_dcm -> Array
|
434
|
+
*
|
435
|
+
* This method returns a 3x3 direction cosine Matrix, which represent
|
436
|
+
* the estimated AHRS orientation of the phidget in 3d space.
|
437
|
+
*/
|
438
|
+
rb_define_method(c_Spatial, "orientation_to_dcm", spatial_orientation_to_dcm, 0);
|
314
439
|
|
440
|
+
/*
|
441
|
+
* Document-method: orientation_to_euler
|
442
|
+
* call-seq:
|
443
|
+
* orientation_to_euler -> Array
|
444
|
+
*
|
445
|
+
* This method returns a 3 element array, which represents the estimated
|
446
|
+
* AHRS orientation of the phidget in 3d space, in euler angles.
|
447
|
+
*/
|
448
|
+
rb_define_method(c_Spatial, "orientation_to_euler", spatial_orientation_to_euler, 0);
|
315
449
|
}
|
316
450
|
|
317
451
|
VALUE spatial_initialize(VALUE self, VALUE serial) {
|
@@ -323,6 +457,12 @@ VALUE spatial_initialize(VALUE self, VALUE serial) {
|
|
323
457
|
spatial_info->data_rate = DEFAULT_SPATIAL_DATA_RATE;
|
324
458
|
spatial_info->sample_rate = sample_create();
|
325
459
|
|
460
|
+
// Ahrs Defaults:
|
461
|
+
spatial_info->orientation_q[0] = 1.0;
|
462
|
+
spatial_info->orientation_q[1] = 0.0;
|
463
|
+
spatial_info->orientation_q[2] = 0.0;
|
464
|
+
spatial_info->orientation_q[3] = 0.0;
|
465
|
+
|
326
466
|
// Setup a spatial handle
|
327
467
|
CPhidgetSpatialHandle spatial = 0;
|
328
468
|
ensure(CPhidgetSpatial_create(&spatial));
|
@@ -446,6 +586,7 @@ VALUE spatial_zero_gyro(VALUE self) {
|
|
446
586
|
|
447
587
|
ensure(CPhidgetSpatial_zeroGyro((CPhidgetSpatialHandle) info->handle));
|
448
588
|
memset(spatial_info->gyroscope, 0, sizeof(double) * spatial_info->gyro_axes);
|
589
|
+
spatial_info->is_ahrs_initialized = false;
|
449
590
|
|
450
591
|
return Qnil;
|
451
592
|
}
|
@@ -481,9 +622,11 @@ VALUE spatial_compass_correction_set(VALUE self, VALUE compass_correction) {
|
|
481
622
|
}
|
482
623
|
|
483
624
|
spatial_info->is_compass_correction_known = true;
|
484
|
-
if (info->is_attached)
|
625
|
+
if (info->is_attached) {
|
485
626
|
spatial_set_compass_correction_by_array(
|
486
627
|
(CPhidgetSpatialHandle)info->handle, spatial_info->compass_correction);
|
628
|
+
spatial_info->is_ahrs_initialized = false;
|
629
|
+
}
|
487
630
|
}
|
488
631
|
|
489
632
|
return compass_correction;
|
@@ -531,3 +674,266 @@ VALUE spatial_data_rate_get(VALUE self) {
|
|
531
674
|
|
532
675
|
return INT2FIX(spatial_info->data_rate);
|
533
676
|
}
|
677
|
+
|
678
|
+
VALUE spatial_direction_cosine_matrix(int argc, VALUE *argv, VALUE self) {
|
679
|
+
VALUE around_x;
|
680
|
+
VALUE around_y;
|
681
|
+
VALUE around_z;
|
682
|
+
VALUE in_order;
|
683
|
+
|
684
|
+
const char *in_order_str = NULL;
|
685
|
+
double dbl_around_x;
|
686
|
+
double dbl_around_y;
|
687
|
+
double dbl_around_z;
|
688
|
+
|
689
|
+
rb_scan_args(argc, argv, "31", &around_x, &around_y, &around_z, &in_order);
|
690
|
+
|
691
|
+
if (TYPE(in_order) == T_STRING)
|
692
|
+
in_order_str = StringValueCStr(in_order);
|
693
|
+
else if( TYPE(in_order) != T_NIL)
|
694
|
+
rb_raise(rb_eTypeError, MSG_IN_ORDER_MUST_BE_STRING);
|
695
|
+
|
696
|
+
// Validate the inputs:
|
697
|
+
if ( (TYPE(around_x) == T_FLOAT) || (TYPE(around_x) == T_FIXNUM ) )
|
698
|
+
dbl_around_x = NUM2DBL(around_x);
|
699
|
+
else
|
700
|
+
rb_raise(rb_eTypeError, MSG_AROUND_MUST_BE_NUMERIC);
|
701
|
+
|
702
|
+
if ( (TYPE(around_y) == T_FLOAT) || (TYPE(around_y) == T_FIXNUM) )
|
703
|
+
dbl_around_y = NUM2DBL(around_y);
|
704
|
+
else
|
705
|
+
rb_raise(rb_eTypeError, MSG_AROUND_MUST_BE_NUMERIC);
|
706
|
+
|
707
|
+
if ( (TYPE(around_z) == T_FLOAT) || (TYPE(around_z) == T_FIXNUM) )
|
708
|
+
dbl_around_z = NUM2DBL(around_z);
|
709
|
+
else
|
710
|
+
rb_raise(rb_eTypeError, MSG_AROUND_MUST_BE_NUMERIC);
|
711
|
+
|
712
|
+
// Perform the actual rotation:
|
713
|
+
double mRetDcm[3][3] = {{1.0,0.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0}};
|
714
|
+
|
715
|
+
if (euler_to_3x3dcm((double *) &mRetDcm, dbl_around_x, dbl_around_y,
|
716
|
+
dbl_around_z, (in_order_str) ? in_order_str : NULL) != 0)
|
717
|
+
rb_raise(rb_eTypeError, MSG_INVALID_ROTATION_AXIS);
|
718
|
+
|
719
|
+
// Return our results:
|
720
|
+
return double3x3_to_matrix_rb((double (*)[3])&mRetDcm);
|
721
|
+
}
|
722
|
+
|
723
|
+
VALUE spatial_accelerometer_to_roll_and_pitch(VALUE self) {
|
724
|
+
SpatialInfo *spatial_info = device_type_info(self);
|
725
|
+
|
726
|
+
if (!spatial_info->is_acceleration_known) return Qnil;
|
727
|
+
|
728
|
+
double dOrientEuler[3];
|
729
|
+
spatial_orientation_from_accel_and_compass( (double *)&dOrientEuler,
|
730
|
+
spatial_info->acceleration[0], spatial_info->acceleration[1], spatial_info->acceleration[2],
|
731
|
+
spatial_info->compass[0], spatial_info->compass[1], spatial_info->compass[2]);
|
732
|
+
|
733
|
+
// Construct a splat-able return of roll and pitch:
|
734
|
+
VALUE aryRet = rb_ary_new2(2);
|
735
|
+
|
736
|
+
rb_ary_store(aryRet, 0, rb_float_new(dOrientEuler[1])); // Roll
|
737
|
+
rb_ary_store(aryRet, 1, rb_float_new(dOrientEuler[0])); // Pitch
|
738
|
+
|
739
|
+
return aryRet;
|
740
|
+
}
|
741
|
+
|
742
|
+
VALUE spatial_gravity_to_roll_and_pitch(VALUE self) {
|
743
|
+
VALUE aryRollPitch = rb_funcall(self, rb_intern("accelerometer_to_roll_and_pitch"), 0);
|
744
|
+
|
745
|
+
return aryRollPitch;
|
746
|
+
}
|
747
|
+
|
748
|
+
VALUE spatial_accelerometer_to_euler(VALUE self) {
|
749
|
+
SpatialInfo *spatial_info = device_type_info(self);
|
750
|
+
|
751
|
+
if (!spatial_info->is_acceleration_known)
|
752
|
+
return Qnil;
|
753
|
+
|
754
|
+
VALUE aryRollPitch = rb_funcall(self, rb_intern("accelerometer_to_roll_and_pitch"), 0);
|
755
|
+
|
756
|
+
VALUE roll = rb_ary_shift(aryRollPitch);
|
757
|
+
VALUE pitch = rb_ary_shift(aryRollPitch);
|
758
|
+
|
759
|
+
VALUE aryRet = rb_ary_new2(3);
|
760
|
+
|
761
|
+
rb_ary_store(aryRet, 0, rb_float_new(NUM2DBL(roll) * -1.00 + M_PI_2));
|
762
|
+
rb_ary_store(aryRet, 1, rb_float_new(0.0));
|
763
|
+
rb_ary_store(aryRet, 2, pitch);
|
764
|
+
|
765
|
+
return aryRet;
|
766
|
+
}
|
767
|
+
|
768
|
+
VALUE spatial_compass_bearing(VALUE self) {
|
769
|
+
// Get the Compass Values:
|
770
|
+
VALUE aryCompass = rb_funcall(self, rb_intern("compass"), 0);
|
771
|
+
|
772
|
+
if ( (TYPE(aryCompass) == T_NIL) || (RARRAY_LEN(aryCompass) != 3) )
|
773
|
+
return Qnil;
|
774
|
+
|
775
|
+
double dbl_comp_x = NUM2DBL(rb_ary_shift(aryCompass));
|
776
|
+
double dbl_comp_y = NUM2DBL(rb_ary_shift(aryCompass));
|
777
|
+
double dbl_comp_z = NUM2DBL(rb_ary_shift(aryCompass));
|
778
|
+
|
779
|
+
// Get the Acceleration Values (All we really need here is 'z'):
|
780
|
+
VALUE aryAccel = rb_funcall(self, rb_intern("accelerometer"), 0);
|
781
|
+
|
782
|
+
if ( (TYPE(aryAccel) == T_NIL) || (RARRAY_LEN(aryAccel) != 3) )
|
783
|
+
return Qnil;
|
784
|
+
|
785
|
+
double dbl_accel_x = NUM2DBL(rb_ary_shift(aryAccel));
|
786
|
+
double dbl_accel_y = NUM2DBL(rb_ary_shift(aryAccel));
|
787
|
+
double dbl_accel_z = NUM2DBL(rb_ary_shift(aryAccel));
|
788
|
+
|
789
|
+
// Get the Gravity Vector:
|
790
|
+
VALUE aryGrvRollPitch = rb_funcall(self, rb_intern("gravity_to_roll_and_pitch"), 0);
|
791
|
+
|
792
|
+
double dbl_grv_roll = NUM2DBL(rb_ary_shift(aryGrvRollPitch));
|
793
|
+
double dbl_grv_pitch = NUM2DBL(rb_ary_shift(aryGrvRollPitch));
|
794
|
+
|
795
|
+
/*
|
796
|
+
* Yaw Angle - about axis 2
|
797
|
+
* tan(yaw) = (mz * sin(roll) – my * cos(roll)) /
|
798
|
+
* (mx * cos(pitch) + my * sin(pitch) * sin(roll) + mz * sin(pitch) * cos(roll))
|
799
|
+
* Use Atan2 to get our range in (-180 - 180)
|
800
|
+
*
|
801
|
+
* Yaw angle == 0 degrees when axis 0 is pointing at magnetic north
|
802
|
+
*/
|
803
|
+
double dbl_yaw = atan2( (dbl_comp_z * sin(dbl_grv_roll)) - (dbl_comp_y * cos(dbl_grv_roll)),
|
804
|
+
(dbl_comp_x * cos(dbl_grv_pitch)) +
|
805
|
+
(dbl_comp_y * sin(dbl_grv_pitch) * sin(dbl_grv_roll)) +
|
806
|
+
(dbl_comp_z * sin(dbl_grv_pitch) * cos(dbl_grv_roll)) );
|
807
|
+
|
808
|
+
// And we're done:
|
809
|
+
return rb_float_new( (dbl_accel_z < 0) ? ( dbl_yaw - M_PI_2 ) : ( dbl_yaw - M_PI * 1.5 ) );
|
810
|
+
}
|
811
|
+
|
812
|
+
VALUE spatial_compass_bearing_to_euler(VALUE self) {
|
813
|
+
VALUE compass_bearing = rb_funcall(self, rb_intern("compass_bearing"), 0);
|
814
|
+
|
815
|
+
if (TYPE(compass_bearing) == T_NIL)
|
816
|
+
return Qnil;
|
817
|
+
|
818
|
+
VALUE aryRet = rb_ary_new2(3);
|
819
|
+
|
820
|
+
rb_ary_store(aryRet, 0, rb_float_new(0.0));
|
821
|
+
rb_ary_store(aryRet, 1, rb_float_new(0.0));
|
822
|
+
rb_ary_store(aryRet, 2, compass_bearing);
|
823
|
+
|
824
|
+
return aryRet;
|
825
|
+
}
|
826
|
+
|
827
|
+
VALUE spatial_accelerometer_to_dcm(VALUE self) {
|
828
|
+
VALUE aryAccelEu = rb_funcall(self, rb_intern("accelerometer_to_euler"), 0);
|
829
|
+
|
830
|
+
if ( (TYPE(aryAccelEu) == T_NIL) || (RARRAY_LEN(aryAccelEu) != 3) )
|
831
|
+
return Qnil;
|
832
|
+
|
833
|
+
VALUE angles[3];
|
834
|
+
for(unsigned int i=0; i<3; i++)
|
835
|
+
angles[i] = rb_ary_shift(aryAccelEu);
|
836
|
+
|
837
|
+
return rb_funcall(self, rb_intern("direction_cosine_matrix"), 3, angles[0], angles[1], angles[2]);
|
838
|
+
}
|
839
|
+
|
840
|
+
VALUE spatial_compass_bearing_to_dcm(VALUE self) {
|
841
|
+
VALUE aryCompassEu = rb_funcall(self, rb_intern("compass_bearing_to_euler"), 0);
|
842
|
+
|
843
|
+
if ( (TYPE(aryCompassEu) == T_NIL) || (RARRAY_LEN(aryCompassEu) != 3) )
|
844
|
+
return Qnil;
|
845
|
+
|
846
|
+
VALUE angles[3];
|
847
|
+
for(unsigned int i=0; i<3; i++)
|
848
|
+
angles[i] = rb_ary_shift(aryCompassEu);
|
849
|
+
|
850
|
+
return rb_funcall(self, rb_intern("direction_cosine_matrix"), 3, angles[0], angles[1], angles[2]);
|
851
|
+
}
|
852
|
+
|
853
|
+
VALUE spatial_gyro_to_dcm(VALUE self) {
|
854
|
+
SpatialInfo *spatial_info = device_type_info(self);
|
855
|
+
|
856
|
+
if ( (!spatial_info->is_gyroscope_known) || (spatial_info->gyro_axes != 3) )
|
857
|
+
return Qnil;
|
858
|
+
|
859
|
+
double mRetDcm[3][3];
|
860
|
+
memcpy(&mRetDcm, &spatial_info->gyroscope_dcm, sizeof(mRetDcm));
|
861
|
+
|
862
|
+
// Return our results:
|
863
|
+
return double3x3_to_matrix_rb((double (*)[3])&mRetDcm);
|
864
|
+
}
|
865
|
+
|
866
|
+
VALUE spatial_orientation_to_quaternion(VALUE self) {
|
867
|
+
SpatialInfo *spatial_info = device_type_info(self);
|
868
|
+
|
869
|
+
// NOTE: I'm reusing this conditional from the dcm test. I think we don't need
|
870
|
+
// to implement a separated is_orientation_known function as the two conditions
|
871
|
+
// are identical:
|
872
|
+
if ( (!spatial_info->is_gyroscope_known) || (spatial_info->gyro_axes != 3) )
|
873
|
+
return Qnil;
|
874
|
+
|
875
|
+
float fOrientationQ[4];
|
876
|
+
float fTranslatedQ[4];
|
877
|
+
double dblRetQ[4];
|
878
|
+
|
879
|
+
// Grabe the magwick quaternion:
|
880
|
+
memcpy(&fOrientationQ, &spatial_info->orientation_q, sizeof(fOrientationQ));
|
881
|
+
|
882
|
+
// Translate it into 'our' (aka opengl's) cordinate space:
|
883
|
+
spatial_madgeq_to_openglq((float *) &fOrientationQ, (float *) &fTranslatedQ);
|
884
|
+
|
885
|
+
// The Madgwick algorithem uses floats, and ruby wants doubles. Let's cast!
|
886
|
+
for(int i=0; i<4; i++)
|
887
|
+
dblRetQ[i] = (double) fTranslatedQ[i];
|
888
|
+
|
889
|
+
// Return our results:
|
890
|
+
return double_array_to_rb((double *) &dblRetQ, 4);
|
891
|
+
}
|
892
|
+
|
893
|
+
VALUE spatial_orientation_to_dcm(VALUE self) {
|
894
|
+
SpatialInfo *spatial_info = device_type_info(self);
|
895
|
+
|
896
|
+
if ( (!spatial_info->is_gyroscope_known) || (spatial_info->gyro_axes != 3) )
|
897
|
+
return Qnil;
|
898
|
+
|
899
|
+
float fOrientationQ[4];
|
900
|
+
float fTranslatedQ[4];
|
901
|
+
double dblRetDcm[3][3];
|
902
|
+
|
903
|
+
// Grabe the magwick quaternion:
|
904
|
+
memcpy(&fOrientationQ, &spatial_info->orientation_q, sizeof(fOrientationQ));
|
905
|
+
|
906
|
+
// Translate it into 'our' (aka opengl's) cordinate space:
|
907
|
+
spatial_madgeq_to_openglq((float *) &fOrientationQ, (float *) &fTranslatedQ);
|
908
|
+
|
909
|
+
quat_to_dcm((float *)&fTranslatedQ, (double (*)[3]) &dblRetDcm);
|
910
|
+
|
911
|
+
return double3x3_to_matrix_rb((double (*)[3])&dblRetDcm);
|
912
|
+
}
|
913
|
+
|
914
|
+
VALUE spatial_orientation_to_euler(VALUE self) {
|
915
|
+
SpatialInfo *spatial_info = device_type_info(self);
|
916
|
+
|
917
|
+
if ( (!spatial_info->is_gyroscope_known) || (spatial_info->gyro_axes != 3) )
|
918
|
+
return Qnil;
|
919
|
+
|
920
|
+
float fOrientationQ[4];
|
921
|
+
float fTranslatedQ[4];
|
922
|
+
float fEuler[3];
|
923
|
+
double dblRetEuler[3];
|
924
|
+
|
925
|
+
// Grabe the magwick quaternion:
|
926
|
+
memcpy(&fOrientationQ, &spatial_info->orientation_q, sizeof(fOrientationQ));
|
927
|
+
|
928
|
+
// Translate it into 'our' (aka opengl's) cordinate space:
|
929
|
+
spatial_madgeq_to_openglq((float *) &fOrientationQ, (float *) &fTranslatedQ);
|
930
|
+
|
931
|
+
quat_to_euler((float *)&fTranslatedQ, (float (*))&fEuler);
|
932
|
+
|
933
|
+
// The Madgwick algorithem uses floats, and ruby wants doubles. Let's cast!
|
934
|
+
for(int i=0; i<3; i++)
|
935
|
+
dblRetEuler[i] = (double) fEuler[i];
|
936
|
+
|
937
|
+
// Return our results:
|
938
|
+
return double_array_to_rb((double *) &dblRetEuler, 3);
|
939
|
+
}
|