Schematic and PCB layout for Dahl Design SW1 sim racing steering wheel. The PCB has been build and tested, working as intended.
Essentially two ATmega32U4 connected to a single USB output with a SL2.1A USB hub IC. The SL2.1A hub has two additional USB connections available, so possibitilies for adding additional MCUs or a screen, like VoCore or Nextion. This SL2.1A chip has been tested with a VoCore screen and three other peripherals, working perfectly. In case of adding a screen, I recommend a 100µF cap close to the +5V going to screen. I also recommend having a look at my PCB layout for placing decoupling capacitors and isolated ground plane for crystal resonators.
Included in this project is also ICSP headers for both MCUs, this is necessary to burn bootloader. I used an Arduino UNO as ISP programmer, simply burning the bootloader through Arduino IDE without any issues. The PCB is then recognized as two Arduino Leonardos.
There is room for all connections on a single ATmega32U4 in this project, but I split the LEDs from the buttons to make use of SimHub (https://www.simhubdash.com/) for LED control.
- The LEDs in my project are split up on several connectors since they are scattered around the steering wheel, not clustered together on a PCB.
- The button matrix in the schematic would only partly be supported by SimHub, and is instead coded through Arduino IDE using the popular joystick library. - - The matrix consists of 4 x encoders, 2 x 7-way switches, 3 x latching 2-way toggles, 2 x momentary 3-way toggles and 16 x buttons, four of them being paddle shifters. The project also includes 5 analog connections, 2 for clutches, 1 for clutch bite point adjustment (potentiometer) and 2 for 12-way switches, using 12-way switches connected to an external "stepped resistor" PCB.
- Last of all are debugging points and extra connection pads in case of adding new things to the wheel or for troubleshooting, not needed for proper function. Also LEDs to Arduino pin 12 on both MCUs to tell them appart with a simple blink sketch.
Feel free to use any element of this schematic, you'll find me in SimHub discord if you have any questions. I can also provide .stl or .step files for the build.
Finished product:
![20210817_224005.jpg](//image.easyeda.com/pullimage/eoIFaJ5gbGKcmtWVTjWEWu4YiO1PpjymQcx217qt.jpeg)
Code written and flashed with Arduino IDE. Requires libraries: Joystick, Multimap and MegunoLink:
```
/*
Dahl Design SW1 Firmware v1.9. By Andreas Dahl January 2022
Version 1.7 :
- First official release.
Version 1.8 :
- Improved logic for all encoders, now perfecly working; pulse on each detent 20 ms and no chance for triggering in the wrong direction.
Version 1.9 :
- Added debouncing on upshift and downshift switches.
*/
#include
#include
#include
#define BUTTONCOUNT 69
//Defining joystick parameters
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
BUTTONCOUNT, //Button count
0, //Hat switch count
true, //X axis -> Clutch paddles
true, //Y axis -> Clutch bite, only for dash visualization
false, //Z axis
false, //Rx axis
false, //Ry axis
false, //Rz axis
false, //Rudder
false, //Throttle
false, //Accelerator
false, //Brake
false); //Steering
//Row and column pins
uint8_t row[] = {11, 3, 2, 30, 4, 12, 6};
const uint8_t rowCount = sizeof(row) / sizeof(row[0]);
uint8_t col[] = {7, A0, 13, 5, 10, 9, 8};
const uint8_t colCount = sizeof(col) / sizeof(col[0]);
//Analog pins
int rotRPin = A1;
int rotLPin = A4;
int clutchRPin = A2;
int clutchLPin = A5;
int bitePin = A3;
//Status of all buttons
uint8_t state[rowCount][colCount] = {
{0, 0, 0, 0, 0, 0, 0}, //ROW 1,
{0, 0, 0, 0, 0, 0, 0}, //ROW 2
{0, 0, 0, 0, 0, 0, 0}, //ROW 3
{0, 0, 0, 0, 0, 0, 0}, //ROW 4
{0, 0, 0, 0, 0, 0, 0}, //ROW 5
{0, 0, 0, 0, 0, 0, 0}, //ROW 6
{0, 0, 0, 0, 0, 0, 0}, //ROW 7
};
/*
Row 1, column 1 - 7
status[0][0] ---> Right grip encoder A-channel *
status[0][1] ---> Right grip encoder B-channel *
status[0][2] ---> Right 3-way (ON)-OFF-(ON) push UP *
status[0][3] ---> Right 3-way (ON)-OFF-(ON) push DOWN *
status[0][4] ---> Right top 9N OFF-(ON) pushbutton *
status[0][5] ---> Right middle 9N OFF-(ON) pushbutton *
status[0][6] ---> Right lower 9N OFF-(ON) pushbutton *
Row 2, column 1-7
status[1][0] ---> Right 7-way down press
status[1][1] ---> Right 7-way left press
status[1][2] ---> Right 7-way encoder A-channel
status[1][3] ---> Right 7-way right press
status[1][4] ---> Right 7-way push button
status[1][5] ---> Right 7-way encoder B-channel
status[1][6] ---> Right 7-way up press
Row 3, column 1-7
status[2][0] ---> Middle top back-button *
status[2][1] ---> Right top back-button *
status[2][2] ---> Upshift paddle *
status[2][3] ---> Right accessory paddle *
status[2][4] ---> Launch control toggle *
status[2][5] ---> Right thumb encoder A-channel *
status[2][6] ---> Right thumb encoder B-channel *
Row 4, column 1-7
status[3][0] ---> Left grip encoder A-channel *
status[3][1] ---> Left grip encoder B-channel *
status[3][2] ---> Left 3-way (ON)-OFF-(ON) push UP *
status[3][3] ---> Left 3-way (ON)-OFF-(ON) push DOWN *
status[3][4] ---> Left top 9N OFF-(ON) pushbutton *
status[3][5] ---> Left middle 9N OFF-(ON) pushbutton *
status[3][6] ---> Left lower 9N OFF-(ON) pushbutton *
Row 5, column 1-7
status[4][0] ---> Left 7-way left press
status[4][1] ---> Left 7-way encoder A-channel
status[4][2] ---> Left 7-way encoder B-channel
status[4][3] ---> Left 7-way up press
status[4][4] ---> Left 7-way push button
status[4][5] ---> Left 7-way down press
status[4][6] ---> Left 7-way right press
Row 6, column 1-7
status[5][0] ---> Left thumb encoder A-channel *
status[5][1] ---> Left thumb encoder B-channel *
status[5][2] ---> Ignition toggle *
status[5][3] ---> Left top back-button *
status[5][4] ---> Left accessory paddle *
status[5][5] ---> Downshift paddle *
status[5][6] ---> Radio OFF-ON latching pushbutton *
//ROW 7, column 1-7
status[6][0] ---> Pit limiter 9N OFF-(ON) pushbutton *
status[6][1] ---> Bite point lock toggle switch *
status[6][2] ---> Engine start button *
status[1][0] ---> Col 4 empty
status[1][0] ---> Col 5 empty
status[1][0] ---> Col 6 empty
status[1][0] ---> Col 7 empty
*/
//List of buttons and button debounce timers
//Button 1 ---> [0][4] ---> Right top 9N OFF-(ON) pushbutton
//Button 2 ---> [0][5] ---> Right middle 9N OFF-(ON) pushbutton
//Button 3 ---> [0][6] ---> Right lower 9N OFF-(ON) pushbutton
//Button 4 ---> [3][4] ---> Left top 9N OFF-(ON) pushbutton
//Button 5 ---> [3][5] ---> Left middle 9N OFF-(ON) pushbutton
//Button 6 ---> [3][6] ---> Left lower 9N OFF-(ON) pushbutton
//Button 7 ---> [2][3] ---> Right accessory paddle
//Button 8 ---> [5][4] ---> Left accessory paddle
//Button 9 ---> [2][2] ---> Upshift paddle
//Button 10 ---> [5][5] ---> Downshift paddle
//Button 11 ---> [0][2] ---> Right 3-way (ON)-OFF-(ON) push UP
//Button 12 ---> [0][3] ---> Right 3-way (ON)-OFF-(ON) push DOWN
//Button 13 ---> [3][2] ---> Left 3-way (ON)-OFF-(ON) push UP
//Button 14 ---> [3][3] ---> Left 3-way (ON)-OFF-(ON) push DOWN
//Button 15 ---> [0][0] ---> Right grip encoder CCW
//Button 16 ---> [0][1] ---> Right grip encoder CW
//Button 17 ---> [3][0] ---> Left grip encoder CCW
//Button 18 ---> [3][1] ---> Left grip encoder CW
//Button 19 ---> [2][5] ---> Right thumb encoder CCW
//Button 20 ---> [2][6] ---> Right thumb encoder CW
//Button 21 ---> [5][0] ---> Left thumb encoder CW
//Button 22 ---> [5][1] ---> Left thumb encoder CCW
//Button 23 ---> [6][0] ---> Pit limiter 9N OFF-(ON) pushbutton
//Button 24 ---> [5][6] ---> Radio OFF-ON latching pushbutton
//Button 25 ---> [1][6] ---> Right 7-way up press
//Button 26 ---> [1][3] ---> Right 7-way right press
//Button 27 ---> [1][0] ---> Right 7-way down press
//Button 28 ---> [1][1] ---> Right 7-way left press
//Button 29 ---> [1][4] ---> Right 7-way push button
//Button 30 ---> [1][2] ---> Right 7-way encoder CCW
//Button 31 ---> [1][5] ---> Right 7-way encoder CW
//Button 32 ---> [4][3] ---> Left 7-way up press
//Button 33 ---> [4][6] ---> Left 7-way right press
//Button 34 ---> [4][5] ---> Left 7-way down press
//Button 35 ---> [4][0] ---> Left 7-way left press
//Button 36 ---> [4][4] ---> Left 7-way push button
//Button 37 ---> [4][1] ---> Left 7-way encoder CCW
//Button 38 ---> [4][2] ---> Left 7-way encoder CW
//Button 39 ---> [2][1] ---> Right top back-button
//Button 40 ---> [2][0] ---> Middle top back-button
//Button 41 ---> [5][3] ---> Left top back-button
//Button 42 ---> [2][4] ---> Launch control toggle
//Button 43 ---> [5][2] ---> Ignition toggle
//Button 44 ---> [6][2] ---> Engine start button
//Button 45 ---> [6][1] ---> Bite point lock toggle switch
// Global variables for buttons
// Button/encoder pulse duration
uint8_t encoderPulse = 20;
uint8_t funkyPulse = 20;
// Encoder variables
uint8_t enc1C = 0;
uint8_t enc1L = 0;
uint8_t enc1S = 0;
uint8_t enc1P = 0;
uint8_t enc1D = 0;
uint8_t enc2C = 0;
uint8_t enc2L = 0;
uint8_t enc2S = 0;
uint8_t enc2P = 0;
uint8_t enc2D = 0;
uint8_t enc3C = 0;
uint8_t enc3L = 0;
uint8_t enc3S = 0;
uint8_t enc3P = 0;
uint8_t enc3D = 0;
uint8_t enc4C = 0;
uint8_t enc4L = 0;
uint8_t enc4S = 0;
uint8_t enc4P = 0;
uint8_t enc4D = 0;
uint8_t upshiftState = 0;
uint8_t upshiftLock = 0;
uint8_t upshiftCounter = 0;
uint8_t downshiftState = 0;
uint8_t downshiftLock = 0;
uint8_t downshiftCounter = 0;
uint8_t funkystatus1 = 0;
uint8_t zerofetch1 = 0;
uint8_t onefetch1 = 0;
uint8_t funkycount1 = 0;
uint8_t funkycountN1 = 0;
uint8_t funkyStop1 = 0;
uint8_t funkystatus2 = 0;
uint8_t zerofetch2 = 0;
uint8_t onefetch2 = 0;
uint8_t funkycount2 = 0;
uint8_t funkycountN2 = 0;
uint8_t funkyStop2 = 0;
uint8_t b43Counter = 0; //Button 43 counter
uint8_t b43Active = 3; //Button 43 active state
uint8_t rotRC = 0;
uint8_t rotRL = 0;
uint8_t rotLC = 0;
uint8_t rotLL = 0;
// Clutch multiMap arrays
int inR [11] = {190, 195, 200, 210, 230, 270, 320, 370, 425, 490, 555};
int outR [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};
int inL [11] = {536, 620, 680, 730, 780, 820, 840, 850, 857, 861, 864};
int outL [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};
int inBite [11] = {3, 20, 40, 170, 400, 600, 900, 930, 960, 990, 1015};
int outBite [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};
int bite = 600;
uint8_t mapSize = 11;
unsigned long counter;
//Filter variable
ExponentialFilter filteredBite(5,0);
//-----------------------------------------------------------------------------
//-------------------------------SETUP-----------------------------------------
//-----------------------------------------------------------------------------
void setup () {
//Serial.begin(9600);
pinMode(rotRPin, INPUT);
pinMode(rotLPin, INPUT);
pinMode(clutchRPin, INPUT);
pinMode(clutchLPin, INPUT);
pinMode(bitePin, INPUT);
for (int i = 0; i encoderPulse) {
Joystick.setButton(42, 0);
b43Counter = 0;
b43Active = state[5][2];
}
//Button 44
Joystick.setButton(43, state[6][2]);
//Button 45
Joystick.setButton(44, state[6][1]);
}
void shifters()
{
//Button 9 - Upshift
if (state[2][2] != upshiftState)
{
upshiftLock = 1;
}
if (upshiftLock == 1)
{
upshiftCounter++;
}
if (upshiftCounter > 3 && state[2][2] != upshiftState)
{
upshiftState = state[2][2];
upshiftCounter = 0;
upshiftLock = 0;
}
Joystick.setButton(8, upshiftState);
//Button 10 - Downshift
if (state[5][5] != downshiftState)
{
downshiftLock = 1;
}
if (downshiftLock == 1)
{
downshiftCounter++;
}
if (downshiftCounter > 3 && state[5][5] != downshiftState)
{
downshiftState = state[5][5];
downshiftCounter = 0;
downshiftLock = 0;
}
Joystick.setButton(9, downshiftState);
}
void encoder1() {
//Right grip encoder
//EncS = status
//EncP = pulse trigger on/off
//EncL = last status
//EncC = counter, for pulse duration
//EncD = saving status for pulse
if (!state[0][0] && !state[0][1]) { //Refreshing switch position
enc1S = 1;
}
if (state[0][0] && !state[0][1]) {
enc1S = 2;
}
if (state[0][0] && state[0][1]) {
enc1S = 3;
}
if (!state[0][0] && state[0][1]) {
enc1S = 4;
}
if (enc1L != enc1S && !enc1P) { //Conditions for starting pulse
enc1P = 1;
enc1D = enc1S;
}
if (enc1P) { //Counting pulse duration, initiate button press
enc1C++;
if ((enc1D > enc1L && !(enc1D == 4 && enc1L == 1)) || enc1D == 1 && enc1L == 4) {
Joystick.pressButton(14);
} else {
Joystick.pressButton(15);
}
}
if (enc1C > encoderPulse) {
enc1C = 0;
enc1L = enc1S;
enc1P = 0;
Joystick.releaseButton(14);
Joystick.releaseButton(15);
}
}
void encoder2() {
//Left grip encoder
if (!state[3][0] && !state[3][1]) { //Refreshing switch position
enc2S = 1;
}
if (state[3][0] && !state[3][1]) {
enc2S = 2;
}
if (state[3][0] && state[3][1]) {
enc2S = 3;
}
if (!state[3][0] && state[3][1]) {
enc2S = 4;
}
if (enc2L != enc2S && !enc2P) { //Conditions for starting pulse
enc2P = 1;
enc2D = enc2S;
}
if (enc2P) { //Counting pulse duration, initiate button press
enc2C++;
if ((enc2D > enc2L && !(enc2D == 4 && enc2L == 1)) || enc2D == 1 && enc2L == 4) {
Joystick.pressButton(16);
} else {
Joystick.pressButton(17);
}
}
if (enc2C > encoderPulse) {
enc2C = 0;
enc2L = enc2S;
enc2P = 0;
Joystick.releaseButton(16);
Joystick.releaseButton(17);
}
}
void encoder3() {
//Right thumb encoder
if (!state[2][5] && !state[2][6]) { //Refreshing switch position
enc3S = 1;
}
if (state[2][5] && !state[2][6]) {
enc3S = 2;
}
if (state[2][5] && state[2][6]) {
enc3S = 3;
}
if (!state[2][5] && state[2][6]) {
enc3S = 4;
}
if (enc3L != enc3S && !enc3P) { //Conditions for starting pulse
enc3P = 1;
enc3D = enc3S;
}
if (enc3P) { //Counting pulse duration, initiate button press
enc3C++;
if ((enc3D > enc3L && !(enc3D == 4 && enc3L == 1)) || enc3D == 1 && enc3L == 4) {
Joystick.pressButton(18);
} else {
Joystick.pressButton(19);
}
}
if (enc3C > encoderPulse) {
enc3C = 0;
enc3L = enc3S;
enc3P = 0;
Joystick.releaseButton(18);
Joystick.releaseButton(19);
}
}
void encoder4() {
//Left thumb encoder
if (!state[5][0] && !state[5][1]) { //Refreshing switch position
enc4S = 1;
}
if (state[5][0] && !state[5][1]) {
enc4S = 2;
}
if (state[5][0] && state[5][1]) {
enc4S = 3;
}
if (!state[5][0] && state[5][1]) {
enc4S = 4;
}
if (enc4L != enc4S && !enc4P) { //Conditions for starting pulse
enc4P = 1;
enc4D = enc4S;
}
if (enc4P) { //Counting pulse duration, initiate button press
enc4C++;
if ((enc4D > enc4L && !(enc4D == 4 && enc4L == 1)) || enc4D == 1 && enc4L == 4) {
Joystick.pressButton(21);
} else {
Joystick.pressButton(20);
}
}
if (enc4C > encoderPulse) {
enc4C = 0;
enc4L = enc4S;
enc4P = 0;
Joystick.releaseButton(20);
Joystick.releaseButton(21);
}
}
void funky1() {
//Right funkyswitch
// Built-in debounce due to the switch being "10" or "01" between detents, triggering switch only when hitting the next steady detent.
if (!state[1][2] && !state[1][5]) {
funkystatus1 = 1;
}
if (!state[1][2] && state[1][5]) {
funkystatus1 = 2;
onefetch1 = 1;
}
if (state[1][2] && state[1][5]) {
funkystatus1 = 3;
}
if (state[1][2] && !state[1][5]) {
funkystatus1 = 4;
zerofetch1 = 1;
}
if ((zerofetch1 && funkystatus1 == 1) || (onefetch1 && funkystatus1 == 3)) {
funkycount1++;
if (funkycountN1 > 0) {funkyStop1 = 1;}
else {
Joystick.pressButton(29);
}
}
if ((zerofetch1 && funkystatus1 == 3) || (onefetch1 && funkystatus1 == 1)) {
funkycountN1++;
if (funkycount1 > 0) {funkyStop1 = 1;}
else {
Joystick.pressButton(30);
}
}
if ((funkycount1+funkycountN1) > funkyPulse || funkyStop1 ) {
funkycount1 = 0;
funkycountN1 = 0;
funkyStop1 = 0;
onefetch1 = 0;
zerofetch1 = 0;
Joystick.releaseButton(29);
Joystick.releaseButton(30);
}
}
void funky2() {
//Left funkyswitch
// Built-in debounce due to the switch being "10" or "01" between detents, triggering switch only when hitting the next steady detent.
if (!state[4][1] && !state[4][2]) {
funkystatus2 = 1;
}
if (!state[4][1] && state[4][2]) {
funkystatus2 = 2;
onefetch2 = 1;
}
if (state[4][1] && state[4][2]) {
funkystatus2 = 3;
}
if (state[4][1] && !state[4][2]) {
funkystatus2 = 4;
zerofetch2 = 1;
}
if ((zerofetch2 && funkystatus2 == 1) || (onefetch2 && funkystatus2 == 3)) {
funkycount2++;
if (funkycountN2 > 0) {funkyStop2 = 1;}
else {
Joystick.pressButton(36);
}
}
if ((zerofetch2 && funkystatus2 == 3) || (onefetch2 && funkystatus2 == 1)) {
funkycountN2++;
if (funkycount2 > 0) {funkyStop2 = 1;}
else {
Joystick.pressButton(37);
}
}
if ((funkycount2+funkycountN2) > funkyPulse || funkyStop2) {
funkycount2 = 0;
funkycountN2 = 0;
funkyStop2 = 0;
onefetch2 = 0;
zerofetch2 = 0;
Joystick.releaseButton(36);
Joystick.releaseButton(37);
}
}
void analog() {
//Analog inputs; clutches, bitepoint and 12-way switches
int rotR = analogRead(rotRPin); // Buttons 46 - 57 ---> 12-position switch right
int rotL = analogRead(rotLPin); // Buttons 58 - 69 ---> 12-position switch left
int clutchR = analogRead(clutchRPin);
int clutchL = analogRead(clutchLPin);
if (state[6][1]) {
bite = analogRead(bitePin);
}
//Right 12-way switch
rotR = map (rotR, 0, 1015, 0, 11);
if (rotR != rotRL) { //Debounce not needed on this switch, but adding 5 cycles just for the hell of it.
rotRC++;
}
if (rotRC > 5) {
rotRC = 0;
rotRL = rotR;
}
if (rotRL == 0) {
Joystick.pressButton(45);
} else {
Joystick.releaseButton(45);
}
if (rotRL == 1) {
Joystick.pressButton(46);
} else {
Joystick.releaseButton(46);
}
if (rotRL == 2) {
Joystick.pressButton(47);
} else {
Joystick.releaseButton(47);
}
if (rotRL == 3) {
Joystick.pressButton(48);
} else {
Joystick.releaseButton(48);
}
if (rotRL == 4) {
Joystick.pressButton(49);
} else {
Joystick.releaseButton(49);
}
if (rotRL == 5) {
Joystick.pressButton(50);
} else {
Joystick.releaseButton(50);
}
if (rotRL == 6) {
Joystick.pressButton(51);
} else {
Joystick.releaseButton(51);
}
if (rotRL == 7) {
Joystick.pressButton(52);
} else {
Joystick.releaseButton(52);
}
if (rotRL == 8) {
Joystick.pressButton(53);
} else {
Joystick.releaseButton(53);
}
if (rotRL == 9) {
Joystick.pressButton(54);
} else {
Joystick.releaseButton(54);
}
if (rotRL == 10) {
Joystick.pressButton(55);
} else {
Joystick.releaseButton(55);
}
if (rotRL == 11) {
Joystick.pressButton(56);
} else {
Joystick.releaseButton(56);
}
//Left 12-way switch
rotL = map (rotL, 0, 1015, 0, 11);
if (rotL != rotLL) { //This switch needs a proper debounce because of filter capacitor removed from the switch PCB (On first wheel build). Probably not needed on an intact switch.
rotLC++;
}
if (rotLC > 30) {
rotLC = 0;
rotLL = rotL;
}
if (rotLL == 0) {
Joystick.pressButton(57);
} else {
Joystick.releaseButton(57);
}
if (rotLL == 1) {
Joystick.pressButton(58);
} else {
Joystick.releaseButton(58);
}
if (rotLL == 2) {
Joystick.pressButton(59);
} else {
Joystick.releaseButton(59);
}
if (rotLL == 3) {
Joystick.pressButton(60);
} else {
Joystick.releaseButton(60);
}
if (rotLL == 4) {
Joystick.pressButton(61);
} else {
Joystick.releaseButton(61);
}
if (rotLL == 5) {
Joystick.pressButton(62);
} else {
Joystick.releaseButton(62);
}
if (rotLL == 6) {
Joystick.pressButton(63);
} else {
Joystick.releaseButton(63);
}
if (rotLL == 7) {
Joystick.pressButton(64);
} else {
Joystick.releaseButton(64);
}
if (rotLL == 8) {
Joystick.pressButton(65);
} else {
Joystick.releaseButton(65);
}
if (rotLL == 9) {
Joystick.pressButton(66);
} else {
Joystick.releaseButton(66);
}
if (rotLL == 10) {
Joystick.pressButton(67);
} else {
Joystick.releaseButton(67);
}
if (rotLL == 11) {
Joystick.pressButton(68);
} else {
Joystick.releaseButton(68);
}
//Clutch and bite logics
clutchR = multiMap(clutchR, inR, outR, mapSize); //No smoothening on clutch.
clutchR = 1023 - clutchR;
clutchL = multiMap(clutchL, inL, outL, mapSize); //Added smoothening on bite point
filteredBite.Filter(bite);
int smoothBite = filteredBite.Current();
int newBite = multiMap(smoothBite, inBite, outBite, mapSize);
Joystick.setYAxis(newBite);
float floatbite = newBite;
float fraction = floatbite / 1023;
clutchL = clutchL * fraction;
if (clutchL > clutchR) {
Joystick.setXAxis(clutchL);
} else {
Joystick.setXAxis(clutchR);
}
}
int multiMap(int val, int* _in, int* _out, uint8_t size)
{
// take care the value is within range
// val = constrain(val, _in[0], _in[size-1]);
if (val = _in[size - 1]) return _out[size - 1];
// search right interval
uint8_t pos = 1; // _in[0] allready tested
while (val > _in[pos]) pos++;
// this will handle all exact "points" in the _in array
if (val == _in[pos]) return _out[pos];
// interpolate in the right segment for the rest
return (val - _in[pos - 1]) * (_out[pos] - _out[pos - 1]) / (_in[pos] - _in[pos - 1]) + _out[pos - 1];
}
```