MarkShot
09-01-2004, 09:59 PM
First, a little background ... I have been using TM controls since around 1992; before they were even programmable. I have a TM Cougar set up, but recently bought a set of CH controls. The Cougar's strong joystick tension (even reduced by changing springs) was not very friendly to my arthritis. So, I purchased CH controls, since my requirements were lots of buttons, programmability, and a light touch.
I decided to post this code here, since I was really suprised after purchasing my CH controls to find that there wasn't much user community support on the Web. So, as I show of support, I thought I might publish some useful code and insights.
Well, I embarked on my first CMS script programming exercise. It was for RBII3D. Some of those WWI planes require very significant control deflections to maintain level flight. Of course, WWI planes had no trimming functions and having to fly with extreme deflection all the time does get tedious (even if it is realistic). Although the FS does have two trim wheels, they are not very convenient to use.
The programming sample in the help file does have a trim function, but it is of very limited utility. The trim function presented does provide for defining a new logical center point for the controls. However, it does not provide the full range of axis values to the simulation being operated. Once trimmed, deflecting the stick in one direction will quickly reach the axis bound before the physical bound is reached, and deflection in the other direction will not reach the axis bound at all despite the physical bound being reached.
One can quickly see that the short comming of the example can easily be rectified by establishing a ratio between physical deflection of the stick and the logical values generated to the game after the new center points are taken into consideration. I tried for quite a while to implement that and couldn't understand why my program was failing. Then, it finally dawned on me (remember this was my very first project) that the CMS division operation only supports integral division (meaning it drops any decimals). This left me stuck as to how I could establish ratio I needed and perform the necessary scaling of physical deflection to logical deflection.
Finally, it dawned on me that if I performed all calculations scaled by a factor of ten that I could achieve reasonable accuracy despite only having integral division. Thus, physical to logical ratios could look like 1:1.3; meaning deflecting the physical stick by 1 unit would generate a logical value defection of 1.3. As can be seen, this yields calculation accurate to tenths. It was also necessary to introduce a small fudge factor into the calculations to address the truncation in the hundredths due to the simulated fractional division. This guaranteed that the full bounds of logical output will be available for control while still being scaled across the physical deflection.
The code is not very documented as I never intended to publish it and it is only my first effort.
The code supports the trimming of joystick axises and rudder.
(1) JS1.B7 is a quick trimming button. Deflect the controls and press the button. While holding it, recenter the controls and a new logical center is recorded.
(2) JS1.B5 is a quick reset button. Press it and all trimming is canceled.
(3) JS2. along with JS1.B4 {shift} are trimming adjustment buttons which allow you to slowly push the trim in either direction along the axis. Thus, you can fine tune the trim established with JS1.B7.
(4) JS2.B29 is a temporary trim cancelation when held pressed. This is useful if your plane is in a spin and you want to temporarily eliminate all trim while you deal with the spin.
(5) JS1.B3 also functions as a temporary trim cancellation, but it's implementation was specific for way RBII3D behaves. This DirectX button in RBII3D also uses the joystick to pan viewing {the only game that ever did it this way}. Thus, you need to temporarily disable trimming while panning, and your plane should have the auto-pilot mode enabled so it doesn't flip over.
ツ* IF ( NOT JS1.B7 ) THEN
ツ* ツ* IF ( [ A1 == 0 ] OR JS1.B3 OR JS2.B29 ) THEN
ツ* ツ* ツ* CMS.A1 = JS1.A1;
ツ* ツ* ELSE
ツ* ツ* ツ* IF ( [ JS1.A1 == 128 ] ) THEN
ツ* ツ* ツ* ツ* CMS.A1 = JS1.A1 + A1;
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A1 < 128 ] ) THEN
ツ* ツ* ツ* ツ* A11 = A1 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A21 = A11 + 1280; // scaled - left range
ツ* ツ* ツ* ツ* A31 = A21 / 128; // scaled - left ratio
ツ* ツ* ツ* ツ* A41 = JS1.A1 * A31; // scaled - left deflection
ツ* ツ* ツ* ツ* CMS.A1 = A41 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A1 > 128 ] ) THEN
ツ* ツ* ツ* ツ* A11 = A1 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A21 = 2550 - A11 + 1280 - 90; // scaled - right range (rounding correction)
ツ* ツ* ツ* ツ* A31 = A21 / 128; // scaled - right ratio
ツ* ツ* ツ* ツ* A41 = 1280 + A11 + ( ( JS1.A1 - 128 ) * A31 ); // scaled - right deflection
ツ* ツ* ツ* ツ* CMS.A1 = A41 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ENDIF
ツ* ツ* IF ( [ A2 == 0 ] OR JS1.B3 OR JS2.B29 ) THEN
ツ* ツ* ツ* CMS.A2 = JS1.A2;
ツ* ツ* ELSE
ツ* ツ* ツ* IF ( [ JS1.A2 == 128 ] ) THEN
ツ* ツ* ツ* ツ* CMS.A2 = JS1.A2 + A2;
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A2 < 128 ] ) THEN
ツ* ツ* ツ* ツ* A12 = A2 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A22 = A12 + 1280; // scaled - left range
ツ* ツ* ツ* ツ* A32 = A22 / 128; // scaled - left ratio
ツ* ツ* ツ* ツ* A42 = JS1.A2 * A32; // scaled - left deflection
ツ* ツ* ツ* ツ* CMS.A2 = A42 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A2 > 128 ] ) THEN
ツ* ツ* ツ* ツ* A12 = A2 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A22 = 2550 - A12 + 1280 - 90; // scaled - right range (rounding correction)
ツ* ツ* ツ* ツ* A32 = A22 / 128; // scaled - right ratio
ツ* ツ* ツ* ツ* A42 = 1280 + A12 + ( ( JS1.A2 - 128 ) * A32 ); // scaled - right deflection
ツ* ツ* ツ* ツ* CMS.A2 = A42 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ENDIF
ツ* ツ* IF ( [ A3 == 0 ] OR JS1.B3 OR JS2.B29 ) THEN
ツ* ツ* ツ* CMS.A3 = JS3.A3;
ツ* ツ* ELSE
ツ* ツ* ツ* IF ( [ JS1.A2 == 128 ] ) THEN
ツ* ツ* ツ* ツ* CMS.A3 = JS3.A3 + A3;
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS3.A3 < 128 ] ) THEN
ツ* ツ* ツ* ツ* A13 = A3 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A23 = A13 + 1280; // scaled - left range
ツ* ツ* ツ* ツ* A33 = A23 / 128; // scaled - left ratio
ツ* ツ* ツ* ツ* A43 = JS3.A3 * A33; // scaled - left deflection
ツ* ツ* ツ* ツ* CMS.A3 = A43 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS3.A3 > 128 ] ) THEN
ツ* ツ* ツ* ツ* A13 = A3 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A23 = 2550 - A13 + 1280 - 90; // scaled - right range (rounding correction)
ツ* ツ* ツ* ツ* A33 = A23 / 128; // scaled - right ratio
ツ* ツ* ツ* ツ* A43 = 1280 + A13 + ( ( JS3.A3 - 128 ) * A33 ); // scaled - right deflection
ツ* ツ* ツ* ツ* CMS.A3 = A43 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ENDIF
ツ* ツ* ツ*
ツ* ENDIF
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B16 );
ツ* ツ* ツ* IF ( [ A2 < 127 ] ) THEN
ツ* ツ* ツ* ツ* A2 = A2 + 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B14 );
ツ* ツ* ツ* IF ( [ (A2 + 128) != 0 ] ) THEN
ツ* ツ* ツ* ツ* A2 = A2 - 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B13 AND NOT JS1.B4 );
ツ* ツ* ツ* IF ( [ A1 < 127 ] ) THEN
ツ* ツ* ツ* ツ* A1 = A1 + 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B13 AND JS1.B4 );
ツ* ツ* ツ* IF ( [ A3 < 127 ] ) THEN
ツ* ツ* ツ* ツ* A3 = A3 + 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B15 AND NOT JS1.B4 );
ツ* ツ* ツ* IF ( [ (A1 + 128) != 0 ] ) THEN
ツ* ツ* ツ* ツ* A1 = A1 - 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B15 AND JS1.B4 );
ツ* ツ* ツ* IF ( [ (A3 + 128) != 0 ] ) THEN
ツ* ツ* ツ* ツ* A3 = A3 - 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ*
ツ* SEQUENCE
ツ* ツ* WAIT( JS1.B7 );
ツ* ツ* A1 = JS1.A1 - 128;
ツ* ツ* A2 = JS1.A2 - 128;
ツ* ツ* A3 = JS3.A3 - 128;
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WAIT( JS1.B5 );
ツ* ツ* A1 = 0;
ツ* ツ* A2 = 0;
ツ* ツ* A3 = 0;
ツ* ENDSEQUENCE
I decided to post this code here, since I was really suprised after purchasing my CH controls to find that there wasn't much user community support on the Web. So, as I show of support, I thought I might publish some useful code and insights.
Well, I embarked on my first CMS script programming exercise. It was for RBII3D. Some of those WWI planes require very significant control deflections to maintain level flight. Of course, WWI planes had no trimming functions and having to fly with extreme deflection all the time does get tedious (even if it is realistic). Although the FS does have two trim wheels, they are not very convenient to use.
The programming sample in the help file does have a trim function, but it is of very limited utility. The trim function presented does provide for defining a new logical center point for the controls. However, it does not provide the full range of axis values to the simulation being operated. Once trimmed, deflecting the stick in one direction will quickly reach the axis bound before the physical bound is reached, and deflection in the other direction will not reach the axis bound at all despite the physical bound being reached.
One can quickly see that the short comming of the example can easily be rectified by establishing a ratio between physical deflection of the stick and the logical values generated to the game after the new center points are taken into consideration. I tried for quite a while to implement that and couldn't understand why my program was failing. Then, it finally dawned on me (remember this was my very first project) that the CMS division operation only supports integral division (meaning it drops any decimals). This left me stuck as to how I could establish ratio I needed and perform the necessary scaling of physical deflection to logical deflection.
Finally, it dawned on me that if I performed all calculations scaled by a factor of ten that I could achieve reasonable accuracy despite only having integral division. Thus, physical to logical ratios could look like 1:1.3; meaning deflecting the physical stick by 1 unit would generate a logical value defection of 1.3. As can be seen, this yields calculation accurate to tenths. It was also necessary to introduce a small fudge factor into the calculations to address the truncation in the hundredths due to the simulated fractional division. This guaranteed that the full bounds of logical output will be available for control while still being scaled across the physical deflection.
The code is not very documented as I never intended to publish it and it is only my first effort.
The code supports the trimming of joystick axises and rudder.
(1) JS1.B7 is a quick trimming button. Deflect the controls and press the button. While holding it, recenter the controls and a new logical center is recorded.
(2) JS1.B5 is a quick reset button. Press it and all trimming is canceled.
(3) JS2. along with JS1.B4 {shift} are trimming adjustment buttons which allow you to slowly push the trim in either direction along the axis. Thus, you can fine tune the trim established with JS1.B7.
(4) JS2.B29 is a temporary trim cancelation when held pressed. This is useful if your plane is in a spin and you want to temporarily eliminate all trim while you deal with the spin.
(5) JS1.B3 also functions as a temporary trim cancellation, but it's implementation was specific for way RBII3D behaves. This DirectX button in RBII3D also uses the joystick to pan viewing {the only game that ever did it this way}. Thus, you need to temporarily disable trimming while panning, and your plane should have the auto-pilot mode enabled so it doesn't flip over.
ツ* IF ( NOT JS1.B7 ) THEN
ツ* ツ* IF ( [ A1 == 0 ] OR JS1.B3 OR JS2.B29 ) THEN
ツ* ツ* ツ* CMS.A1 = JS1.A1;
ツ* ツ* ELSE
ツ* ツ* ツ* IF ( [ JS1.A1 == 128 ] ) THEN
ツ* ツ* ツ* ツ* CMS.A1 = JS1.A1 + A1;
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A1 < 128 ] ) THEN
ツ* ツ* ツ* ツ* A11 = A1 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A21 = A11 + 1280; // scaled - left range
ツ* ツ* ツ* ツ* A31 = A21 / 128; // scaled - left ratio
ツ* ツ* ツ* ツ* A41 = JS1.A1 * A31; // scaled - left deflection
ツ* ツ* ツ* ツ* CMS.A1 = A41 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A1 > 128 ] ) THEN
ツ* ツ* ツ* ツ* A11 = A1 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A21 = 2550 - A11 + 1280 - 90; // scaled - right range (rounding correction)
ツ* ツ* ツ* ツ* A31 = A21 / 128; // scaled - right ratio
ツ* ツ* ツ* ツ* A41 = 1280 + A11 + ( ( JS1.A1 - 128 ) * A31 ); // scaled - right deflection
ツ* ツ* ツ* ツ* CMS.A1 = A41 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ENDIF
ツ* ツ* IF ( [ A2 == 0 ] OR JS1.B3 OR JS2.B29 ) THEN
ツ* ツ* ツ* CMS.A2 = JS1.A2;
ツ* ツ* ELSE
ツ* ツ* ツ* IF ( [ JS1.A2 == 128 ] ) THEN
ツ* ツ* ツ* ツ* CMS.A2 = JS1.A2 + A2;
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A2 < 128 ] ) THEN
ツ* ツ* ツ* ツ* A12 = A2 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A22 = A12 + 1280; // scaled - left range
ツ* ツ* ツ* ツ* A32 = A22 / 128; // scaled - left ratio
ツ* ツ* ツ* ツ* A42 = JS1.A2 * A32; // scaled - left deflection
ツ* ツ* ツ* ツ* CMS.A2 = A42 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS1.A2 > 128 ] ) THEN
ツ* ツ* ツ* ツ* A12 = A2 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A22 = 2550 - A12 + 1280 - 90; // scaled - right range (rounding correction)
ツ* ツ* ツ* ツ* A32 = A22 / 128; // scaled - right ratio
ツ* ツ* ツ* ツ* A42 = 1280 + A12 + ( ( JS1.A2 - 128 ) * A32 ); // scaled - right deflection
ツ* ツ* ツ* ツ* CMS.A2 = A42 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ENDIF
ツ* ツ* IF ( [ A3 == 0 ] OR JS1.B3 OR JS2.B29 ) THEN
ツ* ツ* ツ* CMS.A3 = JS3.A3;
ツ* ツ* ELSE
ツ* ツ* ツ* IF ( [ JS1.A2 == 128 ] ) THEN
ツ* ツ* ツ* ツ* CMS.A3 = JS3.A3 + A3;
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS3.A3 < 128 ] ) THEN
ツ* ツ* ツ* ツ* A13 = A3 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A23 = A13 + 1280; // scaled - left range
ツ* ツ* ツ* ツ* A33 = A23 / 128; // scaled - left ratio
ツ* ツ* ツ* ツ* A43 = JS3.A3 * A33; // scaled - left deflection
ツ* ツ* ツ* ツ* CMS.A3 = A43 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ツ* IF ( [ JS3.A3 > 128 ] ) THEN
ツ* ツ* ツ* ツ* A13 = A3 * 10; // scaled - offset
ツ* ツ* ツ* ツ* A23 = 2550 - A13 + 1280 - 90; // scaled - right range (rounding correction)
ツ* ツ* ツ* ツ* A33 = A23 / 128; // scaled - right ratio
ツ* ツ* ツ* ツ* A43 = 1280 + A13 + ( ( JS3.A3 - 128 ) * A33 ); // scaled - right deflection
ツ* ツ* ツ* ツ* CMS.A3 = A43 / 10; // actual - deflection output
ツ* ツ* ツ* ENDIF
ツ* ツ* ENDIF
ツ* ツ* ツ*
ツ* ENDIF
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B16 );
ツ* ツ* ツ* IF ( [ A2 < 127 ] ) THEN
ツ* ツ* ツ* ツ* A2 = A2 + 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B14 );
ツ* ツ* ツ* IF ( [ (A2 + 128) != 0 ] ) THEN
ツ* ツ* ツ* ツ* A2 = A2 - 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B13 AND NOT JS1.B4 );
ツ* ツ* ツ* IF ( [ A1 < 127 ] ) THEN
ツ* ツ* ツ* ツ* A1 = A1 + 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B13 AND JS1.B4 );
ツ* ツ* ツ* IF ( [ A3 < 127 ] ) THEN
ツ* ツ* ツ* ツ* A3 = A3 + 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B15 AND NOT JS1.B4 );
ツ* ツ* ツ* IF ( [ (A1 + 128) != 0 ] ) THEN
ツ* ツ* ツ* ツ* A1 = A1 - 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WHILE ( JS2.B15 AND JS1.B4 );
ツ* ツ* ツ* IF ( [ (A3 + 128) != 0 ] ) THEN
ツ* ツ* ツ* ツ* A3 = A3 - 1;
ツ* ツ* ツ* ENDIF;
ツ* ツ* ツ* DELAY (1);
ツ* ENDSEQUENCE
ツ*
ツ* SEQUENCE
ツ* ツ* WAIT( JS1.B7 );
ツ* ツ* A1 = JS1.A1 - 128;
ツ* ツ* A2 = JS1.A2 - 128;
ツ* ツ* A3 = JS3.A3 - 128;
ツ* ENDSEQUENCE
ツ* SEQUENCE
ツ* ツ* WAIT( JS1.B5 );
ツ* ツ* A1 = 0;
ツ* ツ* A2 = 0;
ツ* ツ* A3 = 0;
ツ* ENDSEQUENCE