1 /*---------------------------------------------------------------------------*
2  Project:  horizon
3  File:     hid_GyroscopeReader.h
4 
5  Copyright 2010 Nintendo.  All rights reserved.
6 
7  These coded instructions, statements, and computer programs contain
8  proprietary information of Nintendo of America Inc. and/or Nintendo
9  Company Ltd., and are protected by Federal copyright law.  They may
10  not be disclosed to third parties or copied or duplicated in any form,
11  in whole or in part, without the prior written consent of Nintendo.
12 
13  $Rev: $
14  *---------------------------------------------------------------------------*/
15 
16 /*! @file
17  @brief        GyroscopeReaderクラスを定義します
18 
19  */
20 
21 #ifndef NN_HID_CTR_GYROSCOPEREADER_H_
22 #define NN_HID_CTR_GYROSCOPEREADER_H_
23 
24 #include <nn/Handle.h>
25 #include <nn/Result.h>
26 #include <nn/types.h>
27 #include <nn/hid/CTR/hid_Result.h>
28 #include <nn/hid/CTR/hid_Api.h>
29 #include <nn/hid/CTR/hid_Gyroscope.h>
30 #include <nn/hid/CTR/hid_AccelerometerReader.h>
31 #include <nn/hid/CTR/hid_DeviceStatus.h>
32 #include <nn/util/util_SizedEnum.h>
33 #include <nn/util/util_NonCopyable.h>
34 
35 
36 namespace nn
37 {
38 namespace hid
39 {
40 namespace CTR
41 {
42 
43 /*!
44    @brief ゼロ点のドリフト修正の強度を設定する列挙体です
45 */
46 enum ZeroDriftMode
47 {
48     GYROSCOPE_ZERODRIFT_LOOSE, //!< センサの値がある程度変動していても、安定しているとみなして修正が行われるモードです。
49     GYROSCOPE_ZERODRIFT_STANDARD,//!< GYROSCOPE_ZERODRIFT_LOOSE と GYROSCOPE_ZERODRIFT_TIGHT の中間にあたるモードです。
50     GYROSCOPE_ZERODRIFT_TIGHT,//!< センサの値が定められた閾値以内の変動でないと、安定しているとみなさない厳密な修正が行われるモードです。
51     GYROSCOPE_ZERODRIFT_NUM
52 };
53 
54 
55 /*!
56     @brief ジャイロセンサのサンプリングデータを読み込むクラスです。
57 
58         注意) ジャイロセンサのサンプリングは平均 10 msec 周期で行われます。
59 
60         ジャイロセンサのサンプリングは、本クラスのインスタンスを生成した段階から行われるため、
61         サンプリングデータを読み込めるのは、インスタンス生成後 10 msec 経過した後になります。
62         また、内部にAccelerometerReaderのインスタンスを保持しているため、ジャイロセンサを使用する際には加速度センサも自動的に起動状態となります。
63 
64         nn::hid::GyroscopeReader::EnableAxisRotation( ) を使用することで、加工した出力値を得ることができます。
65         加工によって、センサが傾いて配置されているような出力値を得ることができます。
66         詳細は関数のリファレンスを参照してください。
67 
68         ジャイロセンサの軸は以下のようになっています。<BR>
69         X+:十字ボタンの左方向<BR>
70         Y+:タッチパネルの実装面方向<BR>
71         Z+:十字ボタンの上方向<BR>
72 */
73 class GyroscopeReader: private nn::util::NonCopyable<GyroscopeReader>
74 {
75 public:
76 
77 
78     /*!
79     @brief          コンストラクタです。
80 
81                     インスタンスを生成する前に @ref nn::hid::CTR::Initialize( ) で初期化してください。
82                     @param[in]  pAccelerometrReader    AccelerometerReaderへの参照を指定すると、参照するAccelerometerReaderの出力値を利用した補正を行います。
83                                                        デフォルトではNULLが渡され、この場合内部に保持するデフォルトのAccelerometerReaderによって補正を行います。
84 
85     */
86     GyroscopeReader(AccelerometerReader* pAccelerometerReader = NULL, Gyroscope& gyroscope = GetGyroscope());
87 
88     /*!
89     @brief          デストラクタです。
90 
91     */
92     ~GyroscopeReader();
93 
94     /*!
95       @brief        ジャイロセンサのサンプリングデータを新しいものから順に読み込みます。以前に読み込んだデータは読み込まれません。
96 
97       @param[out]   pBufs       新しいものから順にサンプリングデータが読み込まれます。
98       @param[out]   pReadLen    読み込んだサンプリングデータの数です。
99       @param[in]    bufLen      pBufs に読み込めるサンプリングデータの数を指定します。
100       @return       なし。
101 
102     */
103     void Read(GyroscopeStatus* pBufs, s32* pReadLen, s32 bufLen);
104 
105     /*!
106       @brief        最新のジャイロセンサのサンプリングデータを読み込みます。 nn::hid::CTR::GyroscopeReader::Read( ) とちがい同じサンプリングデータを読み込むことが出来ます。
107 
108       @param[out]   pBuf        サンプリングデータが読み込まれます。
109       @return       サンプリングデータの読み込み結果を返します。<BR>
110                       true ・・・ 読み込めました。<BR>
111                       false ・・・ 読み込めませんでした。(GyroscopeReaderのインスタンス生成後あるいはスリープ復帰後の最初のサンプリングが行われ次第、読み込めます。)
112 
113     */
114     bool ReadLatest(GyroscopeStatus* pBuf);
115 
116     /*!
117      @brief        内部状態を初期化します。
118 
119                    このとき、各種補正処理の設定も以下のようになります。
120 
121                    ゼロ点の遊び    無効になります。<BR>
122                    加速度の補正    有効になります。<BR>
123                    ゼロ点のドリフト補正    GYROSCOPE_ZERODRIFT_STANDARD に設定されます。<BR>
124                    角速度の倍率    1.0 に設定されます。
125 
126      @return       なし。
127      */
128     void Reset();
129 
130     /*!
131      @brief        Read 関数で得られる GyroscopeStatus 構造体の angle を任意の値にリセットします。
132      @param[in]    ax      ピッチ方向の角度。角度は 1.0 を 360度とした値です。
133      @param[in]    ay      ヨー方向の角度。角度は 1.0 を 360度とした値です。
134      @param[in]    az      ロール方向の角度。角度は 1.0 を 360度とした値です。
135      @return       なし。
136      */
137     void SetAngle(f32 ax, f32 ay, f32 az);
138 
139     /*!
140      @brief        Read 関数で得られる GyroscopeStatus 構造体の direction を任意の値にリセットします。
141      @param[in]    direction     設定する任意の3次元姿勢。
142      @return       なし。
143      */
144     void SetDirection(const Direction& direction);
145 
146     /*!
147      @brief        Read 関数で得られる GyroscopeStatus 構造体の direction を内部で計算する際に使用する角速度の値にかける倍率を設定します。
148 
149                    たとえば、magification を 2.0f に設定した場合、90度回転させると GyroscopeStatus 構造体の direction は180度回転した姿勢として計算されます。
150 
151      @param[in]    magnification     三次元姿勢を計算する際に使用する角速度にかける倍率。
152      @return       なし。
153      */
154     void SetDirectionMagnification(f32 magnification);
155 
156     /*!
157      @brief        角速度を計算する際に掛ける倍率を各方向ごとに設定します。
158      @param[in]    pitch   pitch方向の角速度を計算する際に掛ける倍率。
159      @param[in]    yaw     yaw方向の角速度を計算する際に掛ける倍率。
160      @param[in]    roll    roll方向の角速度を計算する際に掛ける倍率。
161      @return       なし。
162      */
163     void SetAngleMagnification(f32 pitch, f32 yaw, f32 roll);
164 
165     /* ------------------------------------------------------------------------
166      各種補正機能をコントロールする関数
167      ------------------------------------------------------------------------ */
168     /* ゼロ点遊びに関するコントロール関数 */
169 
170     /*!
171      @brief        ゼロ点の遊びを有効にします。
172      @return       なし。
173      */
174     void EnableZeroPlay();
175 
176     /*!
177      @brief        ゼロ点の遊びを無効にします。
178      @return       なし。
179      */
180     void DisableZeroPlay();
181 
182     /*!
183      @brief        ゼロ点の遊びが有効になっているか調べます。
184      @return       有効な場合にtrue,無効な場合にfalseが帰ります。
185      */
186     bool IsEnableZeroPlay() const;
187 
188     /*!
189      @brief        ゼロ点の遊びによる補正処理の働き具合を返します。
190 
191                    ゼロ点の遊びが無効の場合は0を返します。
192 
193      @return       無効の場合は常に0が返ります。有効の場合は0以上の値が返ります。この値は補正処理の働き具合を示します。
194 
195                    現在の角速度が設定した遊びの値に近いほど0に近づき、遊びの範囲を越える速度になると0になります。
196      */
197     f32 GetZeroPlayEffect() const;
198 
199 
200     /*!
201      @brief        静止時(ゼロ点)の遊びを設定します。
202 
203                    遊びを設けると小さな動きに反応しなくなります。
204 
205                    設定した遊びはすべての方向に対して適用されます。
206 
207      @param[in]    radius  ゼロ点の遊び具合。1.0f を 360 dps とした値を設定します。
208      @return       なし。
209      */
210     void SetZeroPlayParam(f32 radius);
211 
212     /*!
213      @brief        ゼロ点の遊びを取得します。
214 
215                    遊びは 1.0f を 360 dps とした値になります。
216 
217      @param[out]   radius 現在のゼロ点の遊び具合をコピーするバッファ。
218      @return       なし。
219      */
220     void GetZeroPlayParam(f32& radius) const;
221 
222     /*!
223      @brief        ゼロ点の遊びを初期化します。
224 
225                    初期値は 0.005f となります。
226 
227      @return       なし。
228      */
229     void ResetZeroPlayParam();
230 
231 
232     /*ゼロ点ドリフト修正に関するコントロール関数*/
233 
234     /*!
235      @brief        ゼロ点のドリフト修正を有効にします。
236      @return       なし。
237      */
238     void EnableZeroDrift();
239 
240     /*!
241      @brief        ゼロ点のドリフト修正を無効にします。
242      @return       なし。
243      */
244     void DisableZeroDrift();
245 
246     /*!
247      @brief        ゼロ点のドリフト修正が有効になっているか調べます。
248 
249                    ゼロ点のドリフト修正は初期状態では有効となっています。
250 
251      @return       有効な場合にtrue,無効な場合にfalseを返します。
252      */
253     bool IsEnableZeroDrift() const;
254 
255     /*!
256      @brief        ゼロ点のドリフト修正の効き具合を取得します。
257 
258                    この値は補正処理の働き具合を示し、1に近づくほどそのときの角速度で安定していることを意味します。
259 
260      @return       無効の場合は負の値が返ります。有効の場合はゼロ以上の値が返ります。この値は補正処理の働き具合を示します。
261 
262                    1に近づくほどそのときの角速度で安定していることを意味します。
263 
264                    また、ゼロが返される期間は修正処理は行われません。
265      */
266     f32 GetZeroDriftEffect() const;
267 
268     /*!
269      @brief        ゼロ点のドリフト修正モードを初期化します。
270 
271                    初期値は GYROSCOPE_ZERODRIFT_STANDARD に設定されます。
272 
273      @return       なし。
274      */
275     void ResetZeroDriftMode();
276 
277     /*!
278      @brief        ゼロ点のドリフト修正モードを設定します。
279 
280                    設定した内容はすべての方向に対して適用されます。
281 
282                    GYROSCOPE_ZERODRIFT_LOOSE の場合、センサーの値がある程度変動していても安定しているとみなし
283                    ゼロ点の値を修正しようとしますので、等速度運動時にも修正される場合があります。
284 
285                    そのような場合はより条件が厳しいモードに設定することで改善される場合があります。
286 
287                    デフォルトは GYROSCOPE_ZERODRIFT_STANDARD に設定されています。
288 
289      @param[in]    mode    ゼロ点のドリフト修正モード
290      @return       なし。
291      */
292     void SetZeroDriftMode(const ZeroDriftMode& mode);
293 
294     /*!
295      @brief        ゼロ点のドリフト修正モードを取得します。
296      @param[out]   mode    現在のゼロ点のドリフト修正モードをコピーするバッファ。
297      @return       なし。
298      */
299     void GetZeroDriftMode(ZeroDriftMode& mode) const;
300 
301 
302 
303 
304     /*加速度による補正に関するコントロール関数*/
305 
306     /*!
307      @brief        加速度補正を有効にします。
308 
309                    加速度補正はCTRの静止時に加速度センサの値を用いてジャイロセンサの姿勢計算を補正する機能です。
310 
311                    加速度補正が有効であるとき、ジャイロセンサと補正に使用する加速度センサの軸回転に関する設定が共通である必要があります。
312 
313                    詳細は nn::hid::GyroscopeReader::EnableAxisRotation( ) を参照してください。
314 
315      @return       なし。
316      */
317     void EnableAccRevise();
318 
319     /*!
320      @brief        加速度補正を無効にします。
321      @return       なし。
322      */
323     void DisableAccRevise();
324 
325     /*!
326      @brief        加速度補正が有効になっているか調べます。
327 
328                    加速度補正は初期状態では有効となっています。
329 
330      @return       有効な場合にtrue,無効な場合にfalseを返します。
331      */
332     bool IsEnableAccRevise() const;
333 
334     /*!
335      @brief        加速度補正処理の働き具合が返されます。
336      @return       加速度補正処理が無効の場合は常に0を返します。有効の場合は0以上の値が返ります。
337 
338                    この値は補正処理の働き具合を示し、1に近いほどRead関数・ReadLatest関数で得られるGyroscopeStatus.directionの方向を加速度の方向に近づけるように補正がかかっています。
339      */
340     f32 GetAccReviseEffect() const;
341 
342     /*!
343      @brief        加速度補正具合を設定します。
344 
345                    設定した内容はすべての方向に対して適用されます。
346 
347      @param[in]    revisePower    加速度補正の重み。0 から 1 の間の値を設定してください。値が大きいほど急激に補正がかかります。
348      @param[in]    reviseRange    加速度補正の有効範囲。重力加速度を中心にこの範囲内の加速度センサの値を補正計算に使用します。
349 
350                                   1.0f は重力加速度の大きさを意味します。
351 
352                                   つまり、0.4f を指定した場合は 0.6f から 1.4f の範囲に収まる加速度センサの値を補正計算に使用します。
353      @return       なし。
354      */
355     void SetAccReviseParam(f32 revisePower, f32 reviseRange);
356 
357     /*!
358      @brief        加速度補正具合を取得します。
359      @param[out]   revisePower    現在の加速度補正具合をコピーするバッファ。
360      @param[out]   reviseRange    現在の加速度補正の有効半径をコピーするバッファ。
361      @return       なし。
362      */
363     void GetAccReviseParam(f32& revisePower, f32& reviseRange) const;
364 
365     /*!
366      @brief        加速度補正具合を初期化します。
367 
368                    初期値は加速度補正処理の重み(revisePower)が 0.030f、加速度補正の有効半径(reviseRange)が 0.400f となります。
369 
370      @return       なし。
371      */
372     void ResetAccReviseParam();
373 
374 
375     /*!
376      @brief        ジャイロセンサの軸回転を有効にします。
377 
378                    軸回転が有効なとき、nn::hid::CTR::GyroscopeReader::SetRotationAxis( ) で設定された回転行列使用し、サンプリングデータに回転変換処理を行った値が出力されるようになります。
379 
380                    この処理によって、CTR内にセンサが傾いて配置されているかのように扱うことができます。
381 
382                    軸回転を行い、かつ加速度補正も行う場合には、加速度センサの設定に注意する必要があります。<BR>
383                    この場合には、参照しているAccelerometerReaderの軸回転とジャイロセンサの軸回転の設定が共通でなければいけません。<BR>
384                    デフォルトのAccelerometerReaderを使用している場合には nn::hid::CTR::GyroscopeReader::EnableAxisRotation( ), nn::hid::CTR::GyroscopeReader::DisableAxisRotation( ),
385                    nn::hid::CTR::GyroscopeReader::SetAxisRotationMatrix( ), nn::hid::CTR::GyroscopeReader::ResetAxisRotationMatrix( ) の各関数コール時にSDK側でデフォルトの
386                    @ref nn::hid::CTR::AccelerometerReaderの対応する関数をコールして設定を共通化しますが、コンストラクタで独自の@ref nn::hid::CTR::AccelerometerReaderインスタンスを
387                    指定した場合には、これらの設定をアプリ側で揃える必要があります。<BR>
388                    軸回転の設定が共通でない場合、加速度補正が不適切に働く可能性がありますのでご注意ください。
389 
390                    初期値は無効になっています。
391      */
392     void EnableAxisRotation();
393 
394     /*!
395      @brief       ジャイロセンサの軸回転を無効にします。
396 
397                   初期値は無効になっています。
398      */
399     void DisableAxisRotation();
400 
401     /*!
402      @brief       ジャイロセンサの軸回転が有効か無効か調べます。
403      @return      軸回転が有効であればtrue,無効であればfalseを返します。
404      */
405     bool IsEnableAxisRotation();
406 
407     /*!
408      @brief       ジャイロセンサの軸回転で使用する回転行列を設定します。
409      */
410     void SetAxisRotationMatrix(nn::math::MTX34 mtx);
411 
412     /*!
413      @brief       ジャイロセンサの軸回転で使用する回転行列を取得します。
414 
415      @return      設定されている回転行列
416      */
417     nn::math::MTX34 GetAxisRotationMatrix();
418 
419     /*!
420      @brief       ジャイロセンサの軸回転で使用する回転行列を初期化します。
421                   この時回転行列は nn::math::MTX34 の単位行列に設定され、これは軸回転が無効な場合と同等です。
422      */
423     void ResetAxisRotationMatrix();
424 
425 private :
426     void GetZeroDriftParam(f32& radius, s32& count, f32& power) const;
427     void SetZeroDriftParam(f32 radius, s32 count, f32 power);
428     f32 ReviseDirection_Acceleration(Direction& rev_dir, const nn::math::VEC3& acc);
429     void CalculateGyroscopeAxisStatus(
430         f32 *destSpeed,
431         s32 *nearSamplingNum,
432         f32 *zeroOffset,
433         s32 srcSpeed,
434         f32 speedScale,
435         s32* oldValueArray);
436     void CalculateDirection();
437     void InitializeCalibrationData();
438 
439 public :
440     /*! @brief  ドリフト修正カウントの最大数 2のn乗 */
441     static const u32 GYROSCOPE_DRIFT_COUNT_MAX = 256;
442 
443 
444 private :
445     static const s32 GYROSCOPE_BUFFER_SIZE = 8;
446 
447     AccelerometerReader m_DefaultAccelerometerReader;
448 
449     GyroscopeStatus m_CurrentStatus;
450     AccelerometerReader* m_pAccelerometerReader;
451 
452     nn::math::VEC3 m_SpeedOld;
453     nn::math::VEC3 m_SpeedVector;
454     nn::math::VEC3 m_SpeedScale;
455     f32         m_DirectionMagnification;           // 姿勢計算時の倍率
456 
457     f32         m_Period;           // 計算用係数
458     f32         m_FreqDegree;          // 計算用係数
459     f32         m_FreqRadian;          // 計算用係数
460 
461     bool        m_EnableZeroPlay;       // ゼロ点に遊びを設けるか
462     bool        m_EnableZeroDrift;      // ゼロ点自動補正するか
463     bool        m_EnableAccRevise;      // 加速度で姿勢補正するか
464     bool        m_EnableRotate;
465 
466     f32         m_ZeroPlayRadius;   // ゼロ点遊び半径 (1 = 360deg/sec)
467     f32         m_ZeroDriftRadius;  // ドリフトカウント許容半径 (1 = 360deg/sec)
468     s32         m_ZeroDriftCount;      // ドリフト修正カウント
469     f32         m_ZeroDriftPower;      // ドリフト修正パワー
470     f32         m_AccRevisePower;      // 加速度補正力
471     f32         m_AccReviseRange;   // 加速度補正有効半径
472 
473     f32         m_ZeroPlayEffect;        // 遊び円の内側具合 0:外側 ~ 1:中心
474     f32         m_ZeroDriftEffect;        // ドリフト修正カウントの続き具合 (0~1)
475     f32         m_AccRevEffect;      // 加速度補正がどれくらいかかっているか
476 
477     nn::math::VEC3   m_CalibrationZero;  // キャリブレーション値
478     f64         m_CalibrationScale[3];  // キャリブレーション値
479 
480     nn::math::VEC3   m_CountZero;        // ゼロ点を示すカウント値
481     s32         m_CountIdx;         // 最新が格納されているバッファインデクス
482     s32         m_CountT[3][GYROSCOPE_DRIFT_COUNT_MAX];      // XYZハードウェア値
483     f32         m_DpsPitchMagnification;      // pitch方向の角速度計算時の倍率
484     f32         m_DpsYawMagnification;        // yaw方向の角速度計算時の倍率
485     f32         m_DpsRollMagnification;       // roll方向の角速度計算時の倍率
486     NN_PADDING4;
487 
488     /*from Low*/
489     Gyroscope&          m_Gyroscope;
490     s32                 m_IndexOfRead;
491     s64                 m_TickOfRead;
492 
493     /*rotate axis*/
494     nn::math::MTX34     m_RotateMtx;
495 
496 };
497 
498 } // namespace CTR {
499 } // namespace hid {
500 } // namespace nn {
501 
502 #endif // #ifndef NN_HID_CTR_GYROSCOPEREADER_H_
503