]> git.mxchange.org Git - flightgear.git/blob - src/Network/ray.cxx
ea6b7e82db4094a683a6f797589a7217a11454b7
[flightgear.git] / src / Network / ray.cxx
1 // ray.cxx -- "RayWoodworth" motion chair support
2 //
3 // Written by Alexander Perry, started May 2000
4 //
5 // Copyright (C) 2000, Alexander Perry, alex.perry@ieee.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #include <simgear/debug/logstream.hxx>
25 #include <simgear/math/fg_geodesy.hxx>
26 #include <simgear/timing/fg_time.hxx>
27
28 #include <FDM/flight.hxx>
29
30 #include "iochannel.hxx"
31 #include "ray.hxx"
32
33
34 FGRAY::FGRAY() {
35         chair_rising = 0.0;
36         chair_height = 0.0;
37         chair_heading = 0.0;
38         chair_vertical[0] = 0.0;
39         chair_vertical[1] = 0.0;
40 //      chair_FILE = stderr;
41         chair_FILE = 0;
42 }
43
44
45 FGRAY::~FGRAY() {
46 }
47
48
49 // Ray Woodworth's motion chair has between 3 and 5 axes installed.
50 // It expects +/- 5V signals for full scale.  In channel order, axes are:
51 //      roll, pitch, yaw, sway, surge, heave
52 // The drivers are capable of generating (in the same order)
53 //      +/- 30deg, 30deg, 15deg, 12in, 12in, 12in
54 //
55 // In this code implementation, the voltage outputs are generated
56 // using a ComputerBoards DDA06/Jr card and the associated Linux driver.
57 // Data is written to the device /dev/dda06jr-A as byte triplets;
58 // The first byte is the channel number (0-5 respectively) and
59 // the remaining two bytes are an unsigned short for the signal.
60
61
62 bool FGRAY::gen_message() {
63     // cout << "generating RayWoodworth message" << endl;
64     FGInterface *f = cur_fdm_state;
65     int axis, subaxis;
66     const double fullscale[6] = { -0.8, -0.8, -0.25, /* radians */
67                                   -0.3, -0.3, -0.15  /* meters */ };
68
69     /* Figure out how big our timesteps are */
70     double dt = 0.05; /* seconds */
71
72     /* get basic information about gravity */
73     double grav_acc = -9.81;
74     double vert_acc = f->get_A_Z_pilot() * 0.3;
75     if ( -3.0 < vert_acc )
76         vert_acc = -3.0;
77
78     for ( axis = 0; axis < 3; axis++ )
79     {   /* Compute each angular axis together with the linear
80            axis which is coupled by smooth coordinated flight
81         */
82         double ang_pos;
83         double lin_pos, lin_acc;
84
85         /* Retrieve the desired components */
86         switch ( axis ) {
87         case 0: ang_pos = f->get_Phi();
88                 lin_acc = f->get_A_Y_pilot() * 0.3;
89                 break;
90         case 1: ang_pos = f->get_Theta();
91                 lin_acc = f->get_A_X_pilot() * 0.3;
92                 break;
93         case 2: ang_pos = f->get_Psi();
94                 lin_acc = grav_acc - vert_acc;
95                 break;
96         default:
97                 ang_pos = 0.0;
98                 lin_acc = 0.0;
99                 break;
100         }
101
102         /* Make sure the angles are reasonable onscale */
103         while ( ang_pos < -M_PI ) {
104                 ang_pos += 2 * M_PI;
105         }
106         while ( ang_pos > M_PI ) {
107                 ang_pos -= 2 * M_PI;
108         }
109
110         /* Tell interested parties what the situation is */
111         if (chair_FILE) {
112             fprintf ( chair_FILE, "RAY %s, %8.3f rad %8.3f m/s/s  =>",
113                       ((axis==0)?"Roll ":((axis==1)?"Pitch":"Yaw  ")),
114                       ang_pos, lin_acc );
115         }
116
117         /* The upward direction and axis are special cases */
118         if ( axis == 2 )
119         {
120         /* heave */
121                 /* Integrate vertical acceleration into velocity,
122                    diluted by 50% and with a 0.2 second high pass */
123                 chair_rising += ( lin_acc - chair_rising ) * dt * 0.5;
124                 /* Integrate velocity into position, 0.2 sec high pass */
125                 chair_height += ( chair_rising - chair_height ) * dt * 0.5;
126                 lin_pos = chair_height;
127
128         /* yaw */
129                 /* Make sure that we walk through North cleanly */
130                 if ( fabs ( ang_pos - chair_heading ) > M_PI )
131                 {       /* Need to swing chair by 360 degrees */
132                         if ( ang_pos < chair_heading )
133                                 chair_heading -= 2 * M_PI;
134                         else    chair_heading += 2 * M_PI;
135                 }
136                 /* Remove the chair heading from the true heading */
137                 ang_pos -= chair_heading;
138                 /* Wash out the error at 5 sec timeconstant because
139                    a standard rate turn is 3 deg/sec and the chair
140                    can represent 15 degrees full scale.  */
141                 chair_heading += ang_pos * dt * 0.2;
142                 /* If they turn fast, at 90 deg error subtract 30 deg */
143                 if ( fabs(ang_pos) > M_PI / 2 )
144                         chair_heading += ang_pos / 3;
145
146         } else
147         {       /* 3 second low pass to find attitude and gravity vector */
148                 chair_vertical[axis] += ( dt / 3 ) *
149                         ( lin_acc / vert_acc + ang_pos 
150                                 - chair_vertical[axis] );
151                 /* find out how much linear acceleration is left */
152                 lin_acc -= chair_vertical[axis] * vert_acc;
153                 /* reposition the pilot tilt relative to the chair */
154                 ang_pos -= chair_vertical[axis];
155                 /* integrate linear acceleration into a position */
156                 lin_pos = lin_acc; /* HACK */
157         }
158
159         /* Tell interested parties what we'll do */
160         if ( chair_FILE ) {
161             fprintf ( chair_FILE, "  %8.3f deg %8.3f cm.\n",
162                       ang_pos * 60.0, lin_pos * 100.0 );
163         }
164
165         /* Write the resulting numbers to the command buffer */
166         /* The first pass number is linear, second pass is angle */
167         for ( subaxis = axis; subaxis < 6; subaxis += 3 )
168         {       unsigned short *dac;
169                 /* Select the DAC in the command buffer */
170                 buf [ 3*subaxis ] = subaxis;
171                 dac = (unsigned short *) ( buf + 1 + 3*subaxis );
172                 /* Select the relevant number to put there */
173                 double propose = ( subaxis < 3 ) ? ang_pos : lin_pos;
174                 /* Scale to the hardware's full scale range */
175                 propose /= fullscale [ subaxis ];
176                 /* Use a sine shaped washout on all axes */
177                 if ( propose < -M_PI / 2 ) *dac = 0x0000; else
178                 if ( propose >  M_PI / 2 ) *dac = 0xFFFF; else
179                    *dac = (unsigned short) ( 32767 * 
180                                 ( 1.0 + sin ( propose ) ) );
181         }
182
183         /* That concludes the per-axis calculations */
184     }
185
186     /* Tell the caller what we did */
187     length = 18;
188
189     return true;
190 }
191
192
193 // parse RUL message
194 bool FGRAY::parse_message() {
195     FG_LOG( FG_IO, FG_ALERT, "RAY input not supported" );
196
197     return false;
198 }
199
200
201 // process work for this port
202 bool FGRAY::process() {
203     FGIOChannel *io = get_io_channel();
204
205     if ( get_direction() == out ) {
206         gen_message();
207         if ( ! io->write( buf, length ) ) {
208             FG_LOG( FG_IO, FG_ALERT, "Error writing data." );
209             return false;
210         }
211     } else if ( get_direction() == in ) {
212         FG_LOG( FG_IO, FG_ALERT, "in direction not supported for RAY." );
213         return false;
214     }
215
216     return true;
217 }