Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/wiimote/src/external/wiicpp/wiic/motionplus.c @ 9780

Last change on this file since 9780 was 9780, checked in by georgr, 10 years ago

WiiCpp library successfully (?) added - won't work without libbluetooth-dev

  • Property svn:executable set to *
File size: 8.1 KB
Line 
1/*
2 *      motionplus.c
3 *
4 *      Written By:
5 *              Gabriele Randelli       
6 *              Email: < randelli (--AT--) dis [--DOT--] uniroma1 [--DOT--] it >
7 *
8 *      Copyright 2010
9 *
10 *      This file is part of wiiC.
11 *
12 *      This program is free software; you can redistribute it and/or modify
13 *      it under the terms of the GNU General Public License as published by
14 *      the Free Software Foundation; either version 3 of the License, or
15 *      (at your option) any later version.
16 *
17 *      This program is distributed in the hope that it will be useful,
18 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
19 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 *      GNU General Public License for more details.
21 *
22 *      You should have received a copy of the GNU General Public License
23 *      along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 *
25 *      $Header$
26 *
27 */
28
29/**
30 *      @file
31 *      @brief Motion Plus expansion device.
32 */
33#include <stdio.h>
34#include <stdlib.h>
35#include <math.h>
36
37#include "definitions.h"
38#include "wiic_internal.h"
39#include "dynamics.h"
40#include "events.h"
41#include "motionplus.h"
42
43/**
44 *      @brief Convert raw data in deg/sec angular rates.
45 *
46 *      @param mp               A pointer to a motionplus_t structure.
47 *     
48 *      Subtract calibration data from raw data, and convert the difference in deg/sec
49 *      angular rates. The function also considers the fast/slow rotation mode
50 *      and performs very simple filtering for slow rotations.
51 */
52void calculate_gyro_rates(struct motion_plus_t* mp, struct ang3s_t* in, struct ang3f_t* out)
53{
54        short int tmp_r, tmp_p, tmp_y;
55        float tmp_roll, tmp_pitch, tmp_yaw;
56       
57        // We consider calibration data
58        tmp_r = in->roll - mp->cal_gyro.roll;
59        tmp_p = in->pitch - mp->cal_gyro.pitch;
60        tmp_y = in->yaw - mp->cal_gyro.yaw;
61
62        // We convert to degree/sec according to fast/slow mode
63        if(mp->acc_mode & 0x04)
64                tmp_roll = tmp_r / 20.0;
65        else
66                tmp_roll = tmp_r / 4.0;
67
68        if(mp->acc_mode & 0x02)
69                tmp_pitch = tmp_p / 20.0;
70        else
71                tmp_pitch = tmp_p / 4.0;
72               
73        if(mp->acc_mode & 0x01)
74                tmp_yaw = tmp_y / 20.0;
75        else
76                tmp_yaw = tmp_y / 4.0;
77       
78        out->roll = tmp_roll;
79        out->pitch = tmp_pitch;
80        out->yaw = tmp_yaw;
81}
82
83/**
84 *      @brief Handle Motion Plus event.
85 *
86 *      @param mp               A pointer to a motionplus_t structure.
87 *      @param msg              The message specified in the event packet.
88 */
89void motion_plus_event(struct motion_plus_t* mp, byte* msg) 
90{
91        // Check if the gyroscope is in fast or slow mode (0 if rotating fast, 1 if slow or still)
92        mp->acc_mode = ((msg[4] & 0x2) << 1) | ((msg[3] & 0x1) << 1) | ((msg[3] & 0x2) >> 1); 
93       
94        mp->a_raw_gyro.roll = ((msg[4] & 0xFC) << 6) | msg[1];
95        mp->a_raw_gyro.pitch = ((msg[5] & 0xFC) << 6) | msg[2];
96        mp->a_raw_gyro.yaw = ((msg[3] & 0xFC) << 6) | msg[0];
97
98        // First calibration
99        if((mp->a_raw_gyro.roll > 5000) && (mp->a_raw_gyro.pitch > 5000) && (mp->a_raw_gyro.yaw > 5000) && 
100                !(mp->cal_gyro.roll) && !(mp->cal_gyro.pitch) && !(mp->cal_gyro.yaw)) {
101                wiic_calibrate_motion_plus(mp); 
102        }
103       
104        if(mp->smooth)
105                motion_plus_apply_smoothing(mp);
106        else {
107                mp->raw_gyro.roll = mp->a_raw_gyro.roll;
108                mp->raw_gyro.pitch = mp->a_raw_gyro.pitch;
109                mp->raw_gyro.yaw = mp->a_raw_gyro.yaw;
110        }
111                               
112        // Calculate angular rates in deg/sec and performs some simple filtering (both unsmoothed and smoothed)
113        calculate_gyro_rates(mp,&(mp->a_raw_gyro),&(mp->a_gyro_rate));
114        calculate_gyro_rates(mp,&(mp->raw_gyro),&(mp->gyro_rate));
115}
116
117/**
118 *      @brief Apply smoothing to the Motion Plus gyroscopes.
119 *
120 *      @param mp               Pointer to a motion_plus_t structure.
121 *
122 */
123void motion_plus_apply_smoothing(struct motion_plus_t *mp)
124{
125        float alpha = mp->smooth_alpha;
126       
127        mp->raw_gyro.roll = alpha*mp->raw_gyro.roll + (1.0-alpha)*mp->a_raw_gyro.roll;
128        mp->raw_gyro.pitch = alpha*mp->raw_gyro.pitch + (1.0-alpha)*mp->a_raw_gyro.pitch;
129        mp->raw_gyro.yaw = alpha*mp->raw_gyro.yaw + (1.0-alpha)*mp->a_raw_gyro.yaw;
130}
131
132/**
133 *      @brief Handle the handshake from the Motion Plus.
134 *
135 *      @param wm               A pointer to a wiimote_t structure.
136 *      @param data             The data that should contain the Motion Plus ID to check.
137 *      @param len              The length of the data block, in bytes.
138 *
139 *      @return Returns 1 if handshake was successful, 0 if not.
140 */
141int motion_plus_handshake(struct wiimote_t* wm, byte* data, unsigned short len) 
142{
143        WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP);
144        WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_FAILED);
145        WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
146
147        unsigned int val = (data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5];
148
149        if(val == EXP_ID_CODE_MOTION_PLUS) {
150                /* handshake done */
151                wm->event = WIIC_MOTION_PLUS_INSERTED;
152                wm->exp.type = EXP_MOTION_PLUS;
153               
154                WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_EXP);
155                WIIMOTE_ENABLE_STATE(wm,WIIMOTE_STATE_MOTION_PLUS);
156               
157                // Init gyroscopes
158                wm->exp.mp.cal_gyro.roll = 0;
159                wm->exp.mp.cal_gyro.pitch = 0;
160                wm->exp.mp.cal_gyro.yaw = 0;
161                wm->exp.mp.orient.angle.roll = 0.0;
162                wm->exp.mp.orient.angle.pitch = 0.0;
163                wm->exp.mp.orient.angle.yaw = 0.0;
164                wm->exp.mp.raw_gyro.roll = wm->exp.mp.a_raw_gyro.roll = 0;
165                wm->exp.mp.raw_gyro.pitch = wm->exp.mp.a_raw_gyro.pitch = 0;
166                wm->exp.mp.raw_gyro.yaw = wm->exp.mp.a_raw_gyro.yaw = 0;
167                wm->exp.mp.gyro_rate.roll = wm->exp.mp.a_gyro_rate.roll = 0.0;
168                wm->exp.mp.gyro_rate.pitch = wm->exp.mp.a_gyro_rate.pitch = 0.0;
169                wm->exp.mp.gyro_rate.yaw = wm->exp.mp.a_gyro_rate.yaw = 0.0;
170                wm->exp.mp.raw_gyro_threshold = 15;
171                wm->exp.mp.smooth = 1;
172                wm->exp.mp.smooth_alpha = MP_SMOOTH_ALPHA;
173               
174                // Calibration (will be done as soon as we receive the first event)
175                WIIC_INFO("Please, wait for gyro calibration...\n");
176                sleep(1);
177        }
178        else {
179                WIIC_ERROR("Unable to activate Motion Plus");
180                wiic_set_motion_plus(wm,0);
181                return 0;
182        }
183       
184        return 1;
185}
186
187/**
188 *      @brief Control the Motion Plus support.
189 *
190 *      @param wm               Pointer to a wiimote_t structure.
191 *      @param status   Flag to control if the support should be enabled or not (1 to enable, 0 to disable).
192 */
193void wiic_set_motion_plus(struct wiimote_t *wm, int status)
194{
195        byte val;
196        byte* buf = 0;
197        byte* tmp = 0;
198
199        // If we're handshaking other expansions, than skip this
200        if(WIIMOTE_IS_SET(wm,WIIMOTE_STATE_EXP_HANDSHAKE))
201                return;
202
203        WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
204        if(status) {
205                // We initialize the motion plus
206                val = 0x55;
207                wiic_write_data(wm,WM_MOTION_PLUS_INIT,&val,1);
208                usleep(10000);
209
210                // We initialize the motion plus
211                val = 0x04;
212                wiic_write_data(wm,WM_MOTION_PLUS_ENABLE,&val,1);
213                usleep(10000);
214
215                // Callback to check if the init process performed right
216                tmp = (byte*)malloc(sizeof(byte)*6);
217                wiic_read_data_cb(wm, motion_plus_handshake, tmp, WM_MOTION_PLUS_ID_ADDR, 6);
218        }
219        else {
220                disable_expansion(wm);
221                WIIMOTE_DISABLE_STATE(wm,WIIMOTE_STATE_MOTION_PLUS);
222                val = 0x55;
223                wiic_write_data(wm,WM_MOTION_PLUS_DISABLE,&val,1);
224                WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP_HANDSHAKE);
225        }
226}
227
228
229/**
230 *      @brief Calibrate the Motion Plus gyroscopes.
231 *
232 *      @param mp               Pointer to a motion_plus_t structure.
233 *
234 *  This should be called only after receiving the first values
235 *      from the Motion Plus.
236 */
237void wiic_calibrate_motion_plus(struct motion_plus_t *mp)
238{
239        mp->cal_gyro.roll = mp->raw_gyro.roll = mp->a_raw_gyro.roll ;
240        mp->cal_gyro.pitch = mp->raw_gyro.pitch = mp->a_raw_gyro.pitch ;
241        mp->cal_gyro.yaw = mp->raw_gyro.yaw = mp->a_raw_gyro.yaw ;
242}
243
244
245/**
246 *      @brief Notification of Motion Plus disconnection.
247 *
248 *      @param mp       A pointer to a motion_plus_t structure.
249 */
250void motion_plus_disconnected(struct motion_plus_t* mp)
251{
252        WIIC_DEBUG("Motion plus disconnected");
253        memset(mp, 0, sizeof(struct motion_plus_t));
254}
255
256/**
257 *      @brief  Set the gyroscope event threshold.
258 *
259 *      @param wm                       Pointer to a wiimote_t structure.
260 *      @param threshold        The decimal place that should be considered a significant change.
261 */
262void wiic_set_mp_threshold(struct wiimote_t* wm, int threshold) {
263        if (!wm)        return;
264
265        wm->exp.mp.raw_gyro_threshold = threshold;
266}
267
268/**
269 *      @brief  Enable the gyroscope smoothing (through an exponential moving average)
270 *
271 *      @param wm                       Pointer to a wiimote_t structure.
272 *      @param status           1 to enable - 0 to disable
273 *  @param alpha                Alpha smoothness parameter (between 0.0 and 1.0)
274 */
275void wiic_set_mp_smooth(struct wiimote_t* wm, int status, float alpha) {
276        wm->exp.mp.smooth = status;
277        wm->exp.mp.smooth_alpha = alpha;
278}
Note: See TracBrowser for help on using the repository browser.