Skip to content

Commit 3c278c7

Browse files
committed
Full rewrite
1 parent 33dc369 commit 3c278c7

File tree

2 files changed

+190
-119
lines changed

2 files changed

+190
-119
lines changed

CMakeLists.txt

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,33 @@ cmake_minimum_required(VERSION 2.6)
22
project(differential_brakes)
33

44
set(SDK_XPLANE "" CACHE PATH "Path to X-Plane SDK")
5-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
5+
set(CMAKE_CXX_STANDARD 11)
6+
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
67

78
add_library(differential_brakes SHARED differential_brakes.cpp)
89
target_include_directories(differential_brakes SYSTEM PUBLIC ${SDK_XPLANE}/CHeaders ${SDK_XPLANE}/CHeaders/XPLM)
910

10-
set_target_properties(differential_brakes
11-
PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/version-script.txt -shared -rdynamic -nodefaultlibs -undefined_warning -fPIC"
12-
COMPILE_FLAGS "-Wall -O2 -pipe -fPIC -DLIN -DXPLM200 -DXPLM210 -fvisibility=hidden"
13-
LIBRARY_OUTPUT_NAME "lin.xpl"
14-
PREFIX "" SUFFIX "")
11+
if (UNIX)
12+
set_target_properties(differential_brakes
13+
PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/version-script.txt -shared -rdynamic -nodefaultlibs -undefined_warning -fPIC"
14+
COMPILE_FLAGS "-Wall -O2 -pipe -fPIC -DLIN -DXPLM200 -DXPLM210 -fvisibility=hidden"
15+
LIBRARY_OUTPUT_NAME "lin.xpl"
16+
PREFIX "" SUFFIX "")
17+
elseif(WIN32)
18+
set_target_properties(differential_brakes
19+
PROPERTIES
20+
COMPILE_FLAGS "-DIBM -DXPLM200 -DXPLM210 -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS"
21+
RUNTIME_OUTPUT_NAME "win.xpl"
22+
PREFIX "" SUFFIX "")
23+
24+
if( CMAKE_SIZEOF_VOID_P EQUAL 8)
25+
target_link_libraries(differential_brakes ${SDK_XPLANE}/Libraries/Win/XPLM_64.lib)
26+
else()
27+
target_link_libraries(differential_brakes ${SDK_XPLANE}/Libraries/Win/XPLM.lib)
28+
endif()
29+
else()
30+
message(ERROR "Unsupported platform")
31+
endif()
32+
33+
add_executable(diff_brake_test differential_brakes.cpp)
34+
target_compile_definitions(diff_brake_test PRIVATE DIFF_BRAKES_TEST)

differential_brakes.cpp

Lines changed: 164 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,149 @@
11

2+
#include <algorithm>
23
#include <cstring>
4+
#include <cmath>
35

6+
#ifdef DIFF_BRAKES_TEST
7+
#include <iostream>
8+
#else
49
#include <XPLMPlugin.h>
510
#include <XPLMDataAccess.h>
611
#include <XPLMProcessing.h>
712
#include <XPLMUtilities.h>
813

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
1715

18-
static int BothBrakesCommand( XPLMCommandRef inCommand,
19-
XPLMCommandPhase inPhase,
20-
void * inRefCon )
16+
namespace
2117
{
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+
}
5062

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+
}
52121
}
53122

54123
PLUGIN_API int XPluginStart ( char * outName, char * outSignature, char * outDescription ) {
55124

56-
left_brake = XPLMFindCommand("sim/flight_controls/left_brake");
57-
right_brake = XPLMFindCommand("sim/flight_controls/right_brake");
58125
both_brakes = XPLMCreateCommand("sim/flight_controls/both_brakes", "Brake left and right, differential brake depending on the rudder input");
59126

127+
left_brake_ratio = XPLMFindDataRef("sim/cockpit2/controls/left_brake_ratio");
128+
right_brake_ratio = XPLMFindDataRef("sim/cockpit2/controls/right_brake_ratio");
60129
yaw_position = XPLMFindDataRef("sim/joystick/yoke_heading_ratio");
61130

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+
62141
XPLMRegisterCommandHandler( both_brakes,
63142
BothBrakesCommand,
64143
0,
65144
(void*)0);
66145

67-
if (left_brake && right_brake && both_brakes && yaw_position) {
146+
if (both_brakes && left_brake_ratio && right_brake_ratio && yaw_position) {
68147
strcpy(outName, "differential_brakes");
69148
strcpy(outSignature, "differential_brakes by Ennio Barbaro");
70149
strcpy(outDescription, "Apply left and/or right brake depending on joystick yaw input.");
@@ -78,6 +157,9 @@ PLUGIN_API void XPluginStop ( void ) {
78157
BothBrakesCommand,
79158
0,
80159
(void*)0);
160+
161+
XPLMDestroyFlightLoop(flight_loop_id);
162+
flight_loop_active = false;
81163
}
82164

83165
PLUGIN_API void XPluginEnable ( void ) {
@@ -88,80 +170,49 @@ PLUGIN_API void XPluginDisable ( void ) {
88170
XPLMCommandButtonRelease( xplm_joy_rgt_brake );
89171
}
90172

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;
97173

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+
)
101180
{
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;
128190
}
191+
#endif //_MSC_VER
129192

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
133194

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
165216
}
166217

167-
#endif
218+
#endif //

0 commit comments

Comments
 (0)