1
1
2
+ #include < algorithm>
2
3
#include < cstring>
4
+ #include < cmath>
3
5
6
+ #ifdef DIFF_BRAKES_TEST
7
+ #include < iostream>
8
+ #else
4
9
#include < XPLMPlugin.h>
5
10
#include < XPLMDataAccess.h>
6
11
#include < XPLMProcessing.h>
7
12
#include < XPLMUtilities.h>
8
13
9
- // Switch betweeen version that uses the left_brake and right_brake command,
10
- // and version that writes to the dataref directly
11
- #if 0
12
- static XPLMCommandRef left_brake = nullptr,
13
- right_brake = nullptr,
14
- both_brakes = nullptr;
15
-
16
- static XPLMDataRef yaw_position = nullptr;
14
+ #endif // DIFF_BRAKES_TEST
17
15
18
- static int BothBrakesCommand( XPLMCommandRef inCommand,
19
- XPLMCommandPhase inPhase,
20
- void * inRefCon )
16
+ namespace
21
17
{
22
- static bool left_on = false, right_on = false;
23
- bool need_left = false, need_right = false;
24
-
25
- float yaw = XPLMGetDataf(yaw_position);
26
-
27
- switch (inPhase)
28
- {
29
- case xplm_CommandBegin:
30
- case xplm_CommandContinue:
31
- need_left = (yaw < 0.9);
32
- need_right = (yaw > -0.9);
33
- break;
34
- case xplm_CommandEnd:
35
- need_left = need_right = false;
36
- break;
37
- }
38
-
39
- if ( need_left && !left_on )
40
- XPLMCommandButtonPress( xplm_joy_lft_brake );
41
- if ( !need_left && left_on )
42
- XPLMCommandButtonRelease( xplm_joy_lft_brake );
43
-
44
- if ( need_right && !right_on )
45
- XPLMCommandButtonPress( xplm_joy_rgt_brake );
46
- if ( !need_right && right_on )
47
- XPLMCommandButtonRelease( xplm_joy_rgt_brake );
48
-
49
- left_on = need_left, right_on = need_right;
18
+ /* *
19
+ * Try to smooth the brake command.
20
+ */
21
+ class brake_filter
22
+ {
23
+ public:
24
+ float step (bool signal, float dt)
25
+ {
26
+ if (prev_s_ != signal)
27
+ {
28
+ int_e_ = 0 .0f ;
29
+ prev_s_ = signal;
30
+ }
31
+
32
+ const float e = (signal ? 1 .1f : -0 .1f ) - x_;
33
+ const float de = (e - prev_e_) / dt;
34
+ prev_e_ = e;
35
+ int_e_ += e * dt;
36
+
37
+ const float Kp = 0 .4f ;
38
+ const float Ki = 2 .0f ;
39
+ const float Kd = 0 .01f ;
40
+
41
+ return x_ = std::max (0 .0f , std::min (1 .0f , x_ + (Kp * e + Ki * int_e_ + Kd * de) * dt ) );
42
+ }
43
+
44
+ private:
45
+ float x_ = 0 .0f ;
46
+ float prev_e_ = 0 .0f ;
47
+ float int_e_ = 0 .0f ;
48
+ bool prev_s_ = false ;
49
+ };
50
+
51
+ /* *
52
+ * Partition the braking action between left and right, depending on the yaw input
53
+ */
54
+ float differential_factor (float yaw)
55
+ {
56
+ const float differential_brake_limit = 0 .8f ;
57
+ return yaw < differential_brake_limit ?
58
+ 1 .0f :
59
+ (1 .0f - yaw) / (1 .0f - differential_brake_limit);
60
+ }
61
+ }
50
62
51
- return 0;
63
+ #ifndef DIFF_BRAKES_TEST
64
+ namespace
65
+ {
66
+ XPLMCommandRef both_brakes = nullptr ;
67
+ XPLMDataRef yaw_position = nullptr ,
68
+ left_brake_ratio = nullptr ,
69
+ right_brake_ratio = nullptr ;
70
+
71
+ bool flight_loop_active = false ;
72
+ bool brake_button_pressed = false ;
73
+ brake_filter filter;
74
+ XPLMFlightLoopID flight_loop_id;
75
+
76
+ int BothBrakesCommand (XPLMCommandRef inCommand,
77
+ XPLMCommandPhase inPhase,
78
+ void * inRefCon)
79
+ {
80
+ switch (inPhase)
81
+ {
82
+ case xplm_CommandBegin:
83
+ brake_button_pressed = true ;
84
+ if (!flight_loop_active)
85
+ {
86
+ XPLMScheduleFlightLoop (flight_loop_id, 0 .1f , 1 );
87
+ flight_loop_active = true ;
88
+ }
89
+ break ;
90
+ case xplm_CommandContinue:
91
+ break ;
92
+ case xplm_CommandEnd:
93
+ brake_button_pressed = false ;
94
+ break ;
95
+ }
96
+
97
+ return 0 ;
98
+ }
99
+
100
+ float FlightLoop (float inElapsedSinceLastCall,
101
+ float /* inElapsedTimeSinceLastFlightLoop*/ ,
102
+ int /* inCounter*/ ,
103
+ void * /* inRefcon*/ )
104
+ {
105
+ const float yaw = XPLMGetDataf (yaw_position);
106
+ const float left_press = differential_factor (yaw);
107
+ const float right_press = differential_factor (-yaw);
108
+
109
+ const float brake_action = filter.step (brake_button_pressed, inElapsedSinceLastCall);
110
+
111
+ XPLMSetDataf (left_brake_ratio, left_press * brake_action);
112
+ XPLMSetDataf (right_brake_ratio, right_press * brake_action);
113
+
114
+ if (brake_action <= 0 .0f && !brake_button_pressed)
115
+ {
116
+ flight_loop_active = false ;
117
+ return 0 .0f ;
118
+ }
119
+ return 0 .1f ;
120
+ }
52
121
}
53
122
54
123
PLUGIN_API int XPluginStart ( char * outName, char * outSignature, char * outDescription ) {
55
124
56
- left_brake = XPLMFindCommand("sim/flight_controls/left_brake");
57
- right_brake = XPLMFindCommand("sim/flight_controls/right_brake");
58
125
both_brakes = XPLMCreateCommand (" sim/flight_controls/both_brakes" , " Brake left and right, differential brake depending on the rudder input" );
59
126
127
+ left_brake_ratio = XPLMFindDataRef (" sim/cockpit2/controls/left_brake_ratio" );
128
+ right_brake_ratio = XPLMFindDataRef (" sim/cockpit2/controls/right_brake_ratio" );
60
129
yaw_position = XPLMFindDataRef (" sim/joystick/yoke_heading_ratio" );
61
130
131
+ XPLMCreateFlightLoop_t flight_loop_info =
132
+ {
133
+ sizeof (XPLMCreateFlightLoop_t),
134
+ xplm_FlightLoop_Phase_BeforeFlightModel,
135
+ FlightLoop,
136
+ nullptr
137
+ };
138
+
139
+ flight_loop_id = XPLMCreateFlightLoop (&flight_loop_info);
140
+
62
141
XPLMRegisterCommandHandler ( both_brakes,
63
142
BothBrakesCommand,
64
143
0 ,
65
144
(void *)0 );
66
145
67
- if (left_brake && right_brake && both_brakes && yaw_position) {
146
+ if (both_brakes && left_brake_ratio && right_brake_ratio && yaw_position) {
68
147
strcpy (outName, " differential_brakes" );
69
148
strcpy (outSignature, " differential_brakes by Ennio Barbaro" );
70
149
strcpy (outDescription, " Apply left and/or right brake depending on joystick yaw input." );
@@ -78,6 +157,9 @@ PLUGIN_API void XPluginStop ( void ) {
78
157
BothBrakesCommand,
79
158
0 ,
80
159
(void *)0 );
160
+
161
+ XPLMDestroyFlightLoop (flight_loop_id);
162
+ flight_loop_active = false ;
81
163
}
82
164
83
165
PLUGIN_API void XPluginEnable ( void ) {
@@ -88,80 +170,49 @@ PLUGIN_API void XPluginDisable ( void ) {
88
170
XPLMCommandButtonRelease ( xplm_joy_rgt_brake );
89
171
}
90
172
91
- #else
92
-
93
- static XPLMCommandRef both_brakes = nullptr ;
94
- static XPLMDataRef yaw_position = nullptr ,
95
- left_brake_ratio = nullptr ,
96
- right_brake_ratio = nullptr ;
97
173
98
- static int BothBrakesCommand ( XPLMCommandRef inCommand,
99
- XPLMCommandPhase inPhase,
100
- void * inRefCon )
174
+ #ifdef _MSC_VER
175
+ #include < windows.h>
176
+ BOOL APIENTRY DllMain (HANDLE hModule,
177
+ DWORD ul_reason_for_call,
178
+ LPVOID lpReserved
179
+ )
101
180
{
102
- auto filter = [](float yaw)
103
- {
104
- const float differential_brake_limit = 0.8 ;
105
- return yaw < differential_brake_limit ?
106
- 1.0 :
107
- (1.0 - yaw) / (1.0 - differential_brake_limit);
108
- };
109
-
110
- const float yaw = XPLMGetDataf (yaw_position);
111
- const float left_press = filter (yaw);
112
- const float right_press = filter (-yaw);
113
-
114
- switch (inPhase)
115
- {
116
- case xplm_CommandBegin:
117
- case xplm_CommandContinue:
118
- XPLMSetDataf ( left_brake_ratio, left_press );
119
- XPLMSetDataf ( right_brake_ratio, right_press );
120
- break ;
121
- case xplm_CommandEnd:
122
- XPLMSetDataf ( left_brake_ratio, 0.0 );
123
- XPLMSetDataf ( right_brake_ratio, 0.0 );
124
- break ;
125
- }
126
-
127
- return 0 ;
181
+ switch (ul_reason_for_call)
182
+ {
183
+ case DLL_PROCESS_ATTACH:
184
+ case DLL_THREAD_ATTACH:
185
+ case DLL_THREAD_DETACH:
186
+ case DLL_PROCESS_DETACH:
187
+ break ;
188
+ }
189
+ return TRUE ;
128
190
}
191
+ #endif // _MSC_VER
129
192
130
- PLUGIN_API int XPluginStart ( char * outName, char * outSignature, char * outDescription ) {
131
-
132
- both_brakes = XPLMCreateCommand (" sim/flight_controls/both_brakes" , " Brake left and right, differential brake depending on the rudder input" );
193
+ #else // DIFF_BRAKES_TEST
133
194
134
- left_brake_ratio = XPLMFindDataRef (" sim/cockpit2/controls/left_brake_ratio" );
135
- right_brake_ratio = XPLMFindDataRef (" sim/cockpit2/controls/right_brake_ratio" );
136
- yaw_position = XPLMFindDataRef (" sim/joystick/yoke_heading_ratio" );
137
-
138
- XPLMRegisterCommandHandler ( both_brakes,
139
- BothBrakesCommand,
140
- 0 ,
141
- (void *)0 );
142
-
143
- if (both_brakes && left_brake_ratio && right_brake_ratio && yaw_position) {
144
- strcpy (outName, " differential_brakes" );
145
- strcpy (outSignature, " differential_brakes by Ennio Barbaro" );
146
- strcpy (outDescription, " Apply left and/or right brake depending on joystick yaw input." );
147
- return 1 ;
148
- }
149
- return 0 ;
150
- }
151
-
152
- PLUGIN_API void XPluginStop ( void ) {
153
- XPLMUnregisterCommandHandler ( both_brakes,
154
- BothBrakesCommand,
155
- 0 ,
156
- (void *)0 );
157
- }
158
-
159
- PLUGIN_API void XPluginEnable ( void ) {
160
- }
161
-
162
- PLUGIN_API void XPluginDisable ( void ) {
163
- XPLMCommandButtonRelease ( xplm_joy_lft_brake );
164
- XPLMCommandButtonRelease ( xplm_joy_rgt_brake );
195
+ int main ()
196
+ {
197
+ auto rect_signal = [](float t) -> bool
198
+ {
199
+ const float period = 2 .0f ;
200
+
201
+ return fmod ( fabs (t), period) < period * 0 .75f ;
202
+ };
203
+
204
+ brake_filter filter;
205
+
206
+ const float dt = 0 .1f ;
207
+ for (float t = 0 .0f ; t < 10 .0f ; t += dt)
208
+ {
209
+ float x = filter.step (rect_signal (t), dt);
210
+ std::cout << " s = " << rect_signal (t) << " t = " << t << " brake = " << x << std::endl;
211
+ }
212
+
213
+ #ifdef _WIN32
214
+ system (" PAUSE" );
215
+ #endif // _WIN32
165
216
}
166
217
167
- #endif
218
+ #endif //
0 commit comments