]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/heading_indicator_dg.cxx
efca5713b16046a004f87159c69e60653dfb233b
[flightgear.git] / src / Instrumentation / heading_indicator_dg.cxx
1 // heading_indicator_dg.cxx - a Directional Gyro (DG) compass.
2 // Based on the vacuum driven Heading Indicator Written by David Megginson,
3 // started 2002.
4 //
5 // Written by Vivian Meazza, started 2005.
6 //
7 // This file is in the Public Domain and comes with no warranty.
8
9 #ifdef HAVE_CONFIG_H
10 #  include "config.h"
11 #endif
12
13 #include <simgear/compiler.h>
14 #include <simgear/sg_inlines.h>
15 #include <simgear/math/SGMath.hxx>
16 #include <iostream>
17 #include <string>
18 #include <sstream>
19
20 #include <Main/fg_props.hxx>
21 #include <Main/util.hxx>
22
23 #include "heading_indicator_dg.hxx"
24
25 /** Macro calculating x^6 (faster than super-slow math/pow). */
26 #define POW6(x) (x*x*x*x*x*x)
27
28 HeadingIndicatorDG::HeadingIndicatorDG ( SGPropertyNode *node ) :
29     name("heading-indicator-dg"),
30     num(0)
31 {
32     int i;
33     for ( i = 0; i < node->nChildren(); ++i ) {
34         SGPropertyNode *child = node->getChild(i);
35         std::string cname = child->getName();
36         std::string cval = child->getStringValue();
37         if ( cname == "name" ) {
38             name = cval;
39         } else if ( cname == "number" ) {
40             num = child->getIntValue();
41         } else {
42             SG_LOG( SG_INSTR, SG_WARN, "Error in DG heading-indicator config logic" );
43             if ( name.length() ) {
44                 SG_LOG( SG_INSTR, SG_WARN, "Section = " << name );
45             }
46         }
47     }
48 }
49
50 HeadingIndicatorDG::HeadingIndicatorDG ()
51 {
52 }
53
54 HeadingIndicatorDG::~HeadingIndicatorDG ()
55 {
56 }
57
58 void
59 HeadingIndicatorDG::init ()
60 {
61     std::string branch;
62     branch = "/instrumentation/" + name;
63
64     _heading_in_node = fgGetNode("/orientation/heading-deg", true);
65     _yaw_rate_node   = fgGetNode("/orientation/yaw-rate-degps", true);
66      _g_node         = fgGetNode("/accelerations/pilot-g", true);
67
68     SGPropertyNode *node    = fgGetNode(branch.c_str(), num, true );
69     _offset_node            = node->getChild("offset-deg", 0, true);
70     _serviceable_node       = node->getChild("serviceable", 0, true);
71     _heading_bug_error_node = node->getChild("heading-bug-error-deg", 0, true);
72     _error_node             = node->getChild("error-deg", 0, true);
73     _nav1_error_node        = node->getChild("nav1-course-error-deg", 0, true);
74     _heading_out_node       = node->getChild("indicated-heading-deg", 0, true);
75     _align_node             = node->getChild("align-deg", 0, true);
76
77     _electrical_node = fgGetNode("/systems/electrical/outputs/DG", true);
78
79     reinit();
80 }
81
82 void
83 HeadingIndicatorDG::bind ()
84 {
85     std::ostringstream temp;
86     std::string branch;
87     temp << num;
88     branch = "/instrumentation/" + name + "[" + temp.str() + "]";
89
90     fgTie((branch + "/serviceable").c_str(),
91           &_gyro, &Gyro::is_serviceable, &Gyro::set_serviceable);
92     fgTie((branch + "/spin").c_str(),
93           &_gyro, &Gyro::get_spin_norm, &Gyro::set_spin_norm);
94 }
95
96 void
97 HeadingIndicatorDG::unbind ()
98 {
99     std::ostringstream temp;
100     std::string branch;
101     temp << num;
102     branch = "/instrumentation/" + name + "[" + temp.str() + "]";
103
104     fgUntie((branch + "/serviceable").c_str());
105     fgUntie((branch + "/spin").c_str());
106 }
107
108 void
109 HeadingIndicatorDG::reinit (void)
110 {
111     // reset errors/drift values
112     _align_node->setDoubleValue(0.0);
113     _error_node->setDoubleValue(0.0);
114     _offset_node->setDoubleValue(0.0);
115
116     _last_heading_deg = (_heading_in_node->getDoubleValue() +
117         _offset_node->getDoubleValue() + _align_node->getDoubleValue());
118
119     _gyro.reinit();
120 }
121
122 void
123 HeadingIndicatorDG::update (double dt)
124 {
125                                 // Get the spin from the gyro
126     _gyro.set_power_norm(_electrical_node->getDoubleValue());
127
128     _gyro.update(dt);
129     double spin = _gyro.get_spin_norm();
130
131                                 // Next, calculate time-based precession
132     double offset = _offset_node->getDoubleValue();
133     offset -= dt * (0.25 / 60.0); // 360deg/day
134     offset = SGMiscd::normalizePeriodic(-360.0,360.0,offset);
135     _offset_node->setDoubleValue(offset);
136
137                                 // No magvar - set the alignment manually
138     double align = _align_node->getDoubleValue();
139
140                                 // Movement-induced error
141     double yaw_rate = _yaw_rate_node->getDoubleValue();
142     double error = _error_node->getDoubleValue();
143     double g = _g_node->getDoubleValue();
144
145     if ( fabs ( yaw_rate ) > 5 ) {
146         error += 0.033 * -yaw_rate * dt ;
147     }
148
149     if ( g > 1.5 || g < -0.5){
150         error += 0.033 * g * dt;
151     }
152
153                                 // Next, calculate the indicated heading,
154                                 // introducing errors.
155     double factor = POW6(spin);
156     double heading = _heading_in_node->getDoubleValue();
157     if (spin < 0.9)
158     {
159         // when gyro spin is low, then any heading change results in
160         // increasing the error (spin=0 => indicator is stuck)
161         error += (_last_heading_deg - heading)*(1-factor);
162     }
163     _error_node->setDoubleValue(error);
164
165                                 // Now, we have to get the current
166                                 // heading and the last heading into
167                                 // the same range.
168     while ((heading - _last_heading_deg) > 180)
169         _last_heading_deg += 360;
170     while ((heading - _last_heading_deg) < -180)
171         _last_heading_deg -= 360;
172     heading = fgGetLowPass(_last_heading_deg, heading, dt * factor * 100);
173     _last_heading_deg = heading;
174
175     heading += offset + align + error;
176     heading = SGMiscd::normalizePeriodic(0.0,360.0,heading);
177
178     _heading_out_node->setDoubleValue(heading);
179
180                                  // calculate the difference between the indicated heading
181                                  // and the selected heading for use with an autopilot
182     static SGPropertyNode *bnode
183         = fgGetNode( "/autopilot/settings/heading-bug-deg", false );
184     if ( bnode ) {
185         double diff = bnode->getDoubleValue() - heading;
186         if ( diff < -180.0 ) { diff += 360.0; }
187         if ( diff > 180.0 ) { diff -= 360.0; }
188             _heading_bug_error_node->setDoubleValue( diff );
189     }
190                                  // calculate the difference between the indicated heading
191                                  // and the selected nav1 radial for use with an autopilot
192     SGPropertyNode *nnode
193         = fgGetNode( "/instrumentation/nav/radials/selected-deg", false );
194     if ( nnode ) {
195         double diff = nnode->getDoubleValue() - heading;
196         if ( diff < -180.0 ) { diff += 360.0; }
197         if ( diff > 180.0 ) { diff -= 360.0; }
198         _nav1_error_node->setDoubleValue( diff );
199     }
200 }
201
202 // end of heading_indicator_dg.cxx