madradhu Posted September 20, 2019 Share Posted September 20, 2019 (edited) I'm starting in on my kerbtroller project, and I'm at the part where I'm working on getting the controller prototype and the game talking to each other, and I can't seem to get it working - there's Simpit references in KSP.log, but KerbalSimpitStageDemo that I loaded onto my arduino doesn't seem to do anything, and the built in LED stays on. Any ideas? Edited September 23, 2019 by madradhu Link to comment Share on other sites More sharing options...
LRTNZ Posted September 23, 2019 Share Posted September 23, 2019 @madradhu What do you mean by simply references in the log? Could you provide a copy of the log file somewhere for us to look over to see what the issue may be? Have you checked the serial port the Arduino is connected to is not in use by another program? Is the serial port the Arduino is using defined as the serial port in the config file for Kerbal simpit? Link to comment Share on other sites More sharing options...
madradhu Posted September 24, 2019 Share Posted September 24, 2019 23 hours ago, LRTNZ said: @madradhu What do you mean by simply references in the log? Could you provide a copy of the log file somewhere for us to look over to see what the issue may be? Have you checked the serial port the Arduino is connected to is not in use by another program? Is the serial port the Arduino is using defined as the serial port in the config file for Kerbal simpit? This I believe is the plugin loading, right at the top of KSP.log: [LOG 20:54:04.476] Load(Assembly): KerbalSimpit/KerbalSimpit [LOG 20:54:04.477] AssemblyLoader: Loading assembly at S:\SteamLibrary\steamapps\common\Kerbal Space Program\GameData\KerbalSimpit\KerbalSimpit.dll [LOG 20:54:04.507] AssemblyLoader: KSPAssembly 'KerbalSimpit' V1.3.0 [LOG 20:54:04.507] AssemblyLoader: KSPAssemblyDependency 'KerbalSimpitSerial' V1.0.0 [LOG 20:54:04.507] Load(Assembly): KerbalSimpit/KerbalSimpitSerial [LOG 20:54:04.507] AssemblyLoader: Loading assembly at S:\SteamLibrary\steamapps\common\Kerbal Space Program\GameData\KerbalSimpit\KerbalSimpitSerial.dll [LOG 20:54:04.508] AssemblyLoader: KSPAssembly 'KerbalSimpitSerial' V1.0.0 [LOG 20:54:04.508] Load(Assembly): KerbalSimpit/Mono.Posix [LOG 20:54:04.508] AssemblyLoader: Loading assembly at S:\SteamLibrary\steamapps\common\Kerbal Space Program\GameData\KerbalSimpit\Mono.Posix.dll It's pointed at the correct COM port in Settings.cfg, nothing else is using it as far as I can tell. I mocked up the simple debounce sketch physically on my arduino that KerbalSimpitStageDemo.ino references, but I can't seem to get it to work. Dunno if there's anything obvious to try. Link to comment Share on other sites More sharing options...
TygurDuck Posted December 22, 2019 Share Posted December 22, 2019 I do not get how to access the resourceMessage struct. I want to see my total and available LF (all really, but lets start with that.) Although I follow the example of altitude its just not doing anything. Code below. Lots of stuff wrong, I am sure. All I really need is to see how to access the resource information. Do I have to use Altnerate Resource Panel for it to work at all? #include <KerbalSimpit.h> KerbalSimpit mySimpit(Serial); int DS_pin = 11; int STCP_pin = 8; int SHCP_pin = 12; boolean registers[10]; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(DS_pin,OUTPUT); pinMode(STCP_pin,OUTPUT); pinMode(SHCP_pin,OUTPUT); pinMode(LED_BUILTIN,OUTPUT); //digitalWrite(LED_BUILTIN,HIGH); for(int i = 0; i<10; i++) { registers = LOW; writereg(); } while(!mySimpit.init()); { digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); } digitalWrite(LED_BUILTIN,HIGH); mySimpit.inboundHandler(messageHandler); mySimpit.registerChannel(LF_MESSAGE); //mySimpit.registerChannel(ALTITUDE_MESSAGE); } void writereg() { digitalWrite(STCP_pin, LOW); for(int i = 9; i>=0; i--) { digitalWrite(SHCP_pin, LOW); digitalWrite(DS_pin, registers); digitalWrite(SHCP_pin, HIGH); } digitalWrite(STCP_pin, HIGH);} void loop() { // put your main code here, to run repeatedly: mySimpit.update();} void messageHandler(byte messageType, byte msg[], byte msgSize) { if (msgSize == sizeof(resourceMessage)) { resourceMessage myLF; myLF = parseResource(msg); //float percentLF = myLF.available / myLF.total; if (myLF.available < 10) { digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); } }} Link to comment Share on other sites More sharing options...
Wasabi Posted February 21, 2020 Share Posted February 21, 2020 I can't figure out what WHEEL_MESSAGE is used for. What does it contain that ROTATION_MESSAGE doesn't? https://kerbalsimpit-arduino.readthedocs.io/en/stable/payloadstructs.html?highlight=wheelmessage#_CPPv312wheelMessage Link to comment Share on other sites More sharing options...
Mofates Posted March 27, 2020 Share Posted March 27, 2020 On 2/21/2020 at 3:39 PM, Wasabi said: I can't figure out what WHEEL_MESSAGE is used for. What does it contain that ROTATION_MESSAGE doesn't? https://kerbalsimpit-arduino.readthedocs.io/en/stable/payloadstructs.html?highlight=wheelmessage#_CPPv312wheelMessage Wasabi, The Wheel_Message is used to control rovers or wheel motors (Think -- ground based vehicles). The Rotation_Message is for just that - rotational parameters (think space/airborne). myWheel.throttle = buttonCurrent[i]; myWheel.steer = buttonCurrent[j]; myWheel.mask = 3; mySimpit.send(WHEEL_MESSAGE, myWheel); Link to comment Share on other sites More sharing options...
Mofates Posted March 28, 2020 Share Posted March 28, 2020 On 12/22/2019 at 2:27 PM, TygurDuck said: I do not get how to access the resourceMessage struct. I want to see my total and available LF (all really, but lets start with that.) Although I follow the example of altitude its just not doing anything. Code below. Lots of stuff wrong, I am sure. All I really need is to see how to access the resource information. Do I have to use Altnerate Resource Panel for it to work at all? #include <KerbalSimpit.h> KerbalSimpit mySimpit(Serial); int DS_pin = 11; int STCP_pin = 8; int SHCP_pin = 12; boolean registers[10]; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(DS_pin,OUTPUT); pinMode(STCP_pin,OUTPUT); pinMode(SHCP_pin,OUTPUT); pinMode(LED_BUILTIN,OUTPUT); //digitalWrite(LED_BUILTIN,HIGH); for(int i = 0; i<10; i++) { registers = LOW; writereg(); } while(!mySimpit.init()); { digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); } digitalWrite(LED_BUILTIN,HIGH); mySimpit.inboundHandler(messageHandler); mySimpit.registerChannel(LF_MESSAGE); //mySimpit.registerChannel(ALTITUDE_MESSAGE); } void writereg() { digitalWrite(STCP_pin, LOW); for(int i = 9; i>=0; i--) { digitalWrite(SHCP_pin, LOW); digitalWrite(DS_pin, registers); digitalWrite(SHCP_pin, HIGH); } digitalWrite(STCP_pin, HIGH);} void loop() { // put your main code here, to run repeatedly: mySimpit.update();} void messageHandler(byte messageType, byte msg[], byte msgSize) { if (msgSize == sizeof(resourceMessage)) { resourceMessage myLF; myLF = parseResource(msg); //float percentLF = myLF.available / myLF.total; if (myLF.available < 10) { digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); } }} I have recently only been able to achieve Controller to KSP communications. My controller works fine but I can no longer get data from the KSP Client. just a suggestion - loops and timing checks are much better than repeated hard coded delays. Link to comment Share on other sites More sharing options...
Mofates Posted March 28, 2020 Share Posted March 28, 2020 On 12/22/2019 at 2:27 PM, TygurDuck said: I do not get how to access the resourceMessage struct. I want to see my total and available LF (all really, but lets start with that.) Although I follow the example of altitude its just not doing anything. Code below. Lots of stuff wrong, I am sure. All I really need is to see how to access the resource information. Do I have to use Altnerate Resource Panel for it to work at all? #include <KerbalSimpit.h> KerbalSimpit mySimpit(Serial); int DS_pin = 11; int STCP_pin = 8; int SHCP_pin = 12; boolean registers[10]; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(DS_pin,OUTPUT); pinMode(STCP_pin,OUTPUT); pinMode(SHCP_pin,OUTPUT); pinMode(LED_BUILTIN,OUTPUT); //digitalWrite(LED_BUILTIN,HIGH); for(int i = 0; i<10; i++) { registers = LOW; writereg(); } while(!mySimpit.init()); { digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); } digitalWrite(LED_BUILTIN,HIGH); mySimpit.inboundHandler(messageHandler); mySimpit.registerChannel(LF_MESSAGE); //mySimpit.registerChannel(ALTITUDE_MESSAGE); } void writereg() { digitalWrite(STCP_pin, LOW); for(int i = 9; i>=0; i--) { digitalWrite(SHCP_pin, LOW); digitalWrite(DS_pin, registers); digitalWrite(SHCP_pin, HIGH); } digitalWrite(STCP_pin, HIGH);} void loop() { // put your main code here, to run repeatedly: mySimpit.update();} void messageHandler(byte messageType, byte msg[], byte msgSize) { if (msgSize == sizeof(resourceMessage)) { resourceMessage myLF; myLF = parseResource(msg); //float percentLF = myLF.available / myLF.total; if (myLF.available < 10) { digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); } }} I sorted out my comm issues between KSP and my controller. I threw together a basic sketch that 'tries' to do what you were attempting. It will blink the builtinLED when the fuel level is below 10.0. PLEASE make sure that you have the correct COM port assigned in the settings.cfg file in the plugindata directory D:\SteamLibrary\SteamApps\common\Kerbal Space Program\GameData\KerbalSimpit\PluginData #include <KerbalSimpitMessageTypes.h> #include <PayloadStructs.h> #include <KerbalSimpit.h> KerbalSimpit mySimpit(Serial); float fuel = 10.0; unsigned int lastBlink = 0; int blinkPeriod = 500; bool blinkBool = false; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(LED_BUILTIN,OUTPUT); digitalWrite(LED_BUILTIN,LOW); //TURN THE LED OFF UNTIL WE CONNECT WITH KSP delay(100); while(!mySimpit.init()); { delay(100); } digitalWrite(LED_BUILTIN,HIGH); // SHOWS WERE CONNECTED! delay(500); mySimpit.inboundHandler(messageHandler); mySimpit.registerChannel(10); // 10 is the value for LF -- Outputs a resourceMessage } void loop() { // put your main code here, to run repeatedly: mySimpit.update(); checkFuelLevel(); } void messageHandler(byte messageType, byte msg[], byte msgSize) { if (msgSize == sizeof(resourceMessage)) { resourceMessage myLF; myLF = parseResource(msg); //float percentLF = myLF.available / myLF.total; fuel = myLF.available; } } void checkFuelLevel(){ unsigned int nowCheck = millis(); if( fuel < 10.0 ){ // CHECK FOR FUEL LOW if( nowCheck > ( lastBlink + blinkPeriod ) ){ lastBlink = nowCheck; digitalWrite(LED_BUILTIN, blinkBool); blinkBool = !blinkBool; } }else{ digitalWrite(LED_BUILTIN,HIGH); } } Link to comment Share on other sites More sharing options...
LRTNZ Posted May 20, 2020 Share Posted May 20, 2020 On 12/23/2019 at 8:27 AM, TygurDuck said: I do not get how to access the resourceMessage struct. I want to see my total and available LF (all really, but lets start with that.) Although I follow the example of altitude its just not doing anything. Code below. Lots of stuff wrong, I am sure. All I really need is to see how to access the resource information. Do I have to use Altnerate Resource Panel for it to work at all? #include <KerbalSimpit.h> KerbalSimpit mySimpit(Serial); int DS_pin = 11; int STCP_pin = 8; int SHCP_pin = 12; boolean registers[10]; void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(DS_pin,OUTPUT); pinMode(STCP_pin,OUTPUT); pinMode(SHCP_pin,OUTPUT); pinMode(LED_BUILTIN,OUTPUT); //digitalWrite(LED_BUILTIN,HIGH); for(int i = 0; i<10; i++) { registers = LOW; writereg(); } while(!mySimpit.init()); { digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); } digitalWrite(LED_BUILTIN,HIGH); mySimpit.inboundHandler(messageHandler); mySimpit.registerChannel(LF_MESSAGE); //mySimpit.registerChannel(ALTITUDE_MESSAGE); } void writereg() { digitalWrite(STCP_pin, LOW); for(int i = 9; i>=0; i--) { digitalWrite(SHCP_pin, LOW); digitalWrite(DS_pin, registers); digitalWrite(SHCP_pin, HIGH); } digitalWrite(STCP_pin, HIGH);} void loop() { // put your main code here, to run repeatedly: mySimpit.update();} void messageHandler(byte messageType, byte msg[], byte msgSize) { if (msgSize == sizeof(resourceMessage)) { resourceMessage myLF; myLF = parseResource(msg); //float percentLF = myLF.available / myLF.total; if (myLF.available < 10) { digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(300); digitalWrite(LED_BUILTIN,LOW); delay(300); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); digitalWrite(LED_BUILTIN,HIGH); delay(100); digitalWrite(LED_BUILTIN,LOW); delay(100); } }} @TygurDuck The big issue is that you are running blocking code - this is where you prevent the processor from doing anything else, as it is stuck in a delay. @Mofates your demo code using the boolean operators and the timer code is how I would recommend to do it. There is one really big issue though - that is, you have about 65 seconds of useful time to use it, before you will probably encounter some really weird timing bugs, when lastBlink rolls over back to zero. An unsigned int on an arduino has a maximum value of 65,535. As you are storing milliseconds, that comes to just over a minute, until it rolls over. You need to be using an unsigned long, which can hold a maximum value of 4,294,967,295 - if you manage to exceed that, you really need to stop playing Link to comment Share on other sites More sharing options...
PSU_Jedi Posted May 21, 2020 Share Posted May 21, 2020 Hello @stibbons! I really appreciate the work you've done here and it's been really exciting building my own Kontrol box for KSP. I have successfully gotten a load of buttons to work, plus throttle. I'm working through translating my 3-axis analog joystick inputs now to the format that Simpit needs. I wanted to ask if you had any plans to incorporate more of the overall game commands into your mod. For instance, I've put Quicksave, Load, Pause, Time Warp, and Map functions on my Kontrol box. At this time I don't see any such functionality built into Simpit, so it looks like I'm going to have to emulate an HID with a second arduino board to accomplish that. Thanks! Link to comment Share on other sites More sharing options...
PSU_Jedi Posted June 4, 2020 Share Posted June 4, 2020 (edited) All, I just finished constructing my prototype control box and everything was working individually until I put it all together. Now it freezes up about 5-10 seconds into game play and seems to stop transmitting data to the computer. I've checked the circuit connections and have found no shorts or faulty connections. Running tests with serial monitor shows that the Arduino is continuously outputting data in these situations. What I've noticed when I play the game is that the Rx LED on the Arduino is constantly lit up, which makes me think that it's locking up because it's getting inundated with information from the USB port. Do the message channels continually broadcast? TIA. EDIT: Further testing revealed that it is the interaction of the analog joysticks that seems to cause everything to freeze up. I commented out the portion of the code below where the joysticks live and everything else worked flawlessly without freezing. The joysticks work on their own when I troubleshoot with serial monitor, and both power and ground are commonly wired with the joysticks in parallel with the other buttons and switches, so it's not a physical connection issue. It seems to be something with the Simpit code sending/receiving too much data when the joysticks are used that causes it to lock up. What am I doing in the joystick code that's causing this? // Sets up the Arduino Mega to handle the analog joysticks, Action Groups, switches and buttons #include <KerbalSimpit.h> #include <KerbalSimpitMessageTypes.h> #include <PayloadStructs.h> #include <ezButton.h> // loads ezButton library for button debounce #include <Rotary.h> rotationMessage myRotation; translationMessage myTranslation; const int ROT_X = A0; // assigns rotation joystick X-axis to pin Analog 0 const int ROT_Y = A1; // assigns rotation joystick Y-axis to pin Analog 1 const int ROT_Z = A2; // assigns rotation joystick Z-axis to pin Analog 2 const int TRANS_X = A3; // assigns translation joystick X-axis to pin Analog 3 const int TRANS_Y = A4; // assigns translation joystick Y-axis to pin Analog 4 const int TRANS_Z = A5; // assigns translation joystick Z-axis to pin Analog 5 const int STAGE_BTN = 2; // assigns the Staging button to pin 2 const int RCS_LED = 3; // assigns the RCS indicator LED to pin 3 const int BRAKES_LED = 4; // assigns the Brakes indicator LED to pin 4 const int GEAR_LED = 5; // assigns the Landing Gear indicator LED to pin 5 const int LIGHTS_LED = 6; // assigns the Lights indicator LED to pin 6 const int SAS_LED = 7; // assigns the SAS indicator LED to pin 7 const int THROT_CLK = 22; // assigns the Throttle rotary encoder CLK output ("A") to pin 22 const int THROT_DT = 23; // assigns the Throttle rotary encoder DT output ("B") to pin 23 const int THROT_BTN = 24; // assigns the Throttle rotary encoder Switch output to pin 24 const int THROT_CUT = 25; // assigns the Throttle Cut button output to pin 25 const int SAS_CLK = 32; // assigns the SAS rotary encoder CLK output ("A") to pin 32 const int SAS_DT = 33; // assigns the SAS rotary encoder DT output ("B") to pin 33 const int SAS_SWITCH = 34; // assigns the SAS switch output to pin 34 const int RCS_SWITCH = 35; // assigns the RCS switch output to pin 35 const int BRAKES_SWITCH = 36; // assigns the Brakes switch output to pin 36 const int GEAR_SWITCH = 37; // assigns the Gear switch output to pin 37 const int LIGHTS_SWITCH = 38; // assigns the Lights switch output to pin 38 const int ABORT_BTN = 39; // assigns the Abort switch output to pin 38 const int AG_01 = 41; // assigns the Action Group 1 switch output to pin 41 const int AG_02 = 42; // assigns the Action Group 2 switch output to pin 42 const int AG_03 = 43; // assigns the Action Group 3 switch output to pin 43 const int AG_04 = 44; // assigns the Action Group 4 switch output to pin 44 const int AG_05 = 45; // assigns the Action Group 5 switch output to pin 45 const int AG_06 = 46; // assigns the Action Group 6 switch output to pin 46 const int AG_07 = 47; // assigns the Action Group 7 switch output to pin 47 const int AG_08 = 48; // assigns the Action Group 8 switch output to pin 48 const int AG_09 = 49; // assigns the Action Group 9 switch output to pin 49 const int AG_10 = 50; // assigns the Action Group 10 switch output to pin 50 int sas_Counter = 1; // initializes SAS Mode counter value variable at 1 int currentSASStateCLK; int lastSASStateCLK; int throt_Counter = 0; // initializes Throttle counter value variable at 0 int currentThrotStateCLK; int lastThrotStateCLK; int rot_X_Read; int rot_Y_Read; int rot_Z_Read; int rot_X_Mapped; int rot_Y_Mapped; int rot_Z_Mapped; int trans_X_Read; int trans_Y_Read; int trans_Z_Read; int trans_X_Mapped; int trans_Y_Mapped; int trans_Z_Mapped; int debounce_Time = 25; KerbalSimpit mySimpit(Serial); ezButton buttonSTAGE(STAGE_BTN); ezButton buttonTHROT(THROT_BTN); ezButton buttonTHROT_CUT(THROT_CUT); ezButton buttonSAS(SAS_SWITCH); ezButton buttonRCS(RCS_SWITCH); ezButton buttonBRAKES(BRAKES_SWITCH); ezButton buttonGEAR(GEAR_SWITCH); ezButton buttonLIGHTS(LIGHTS_SWITCH); ezButton buttonABORT(ABORT_BTN); ezButton buttonAG_01(AG_01); ezButton buttonAG_02(AG_02); ezButton buttonAG_03(AG_03); ezButton buttonAG_04(AG_04); ezButton buttonAG_05(AG_05); ezButton buttonAG_06(AG_06); ezButton buttonAG_07(AG_07); ezButton buttonAG_08(AG_08); ezButton buttonAG_09(AG_09); ezButton buttonAG_10(AG_10); Rotary throtRotary = Rotary(THROT_DT, THROT_CLK); Rotary sasRotary = Rotary(SAS_DT, SAS_CLK); void setup() { Serial.begin(115200); // begins the serial connection to the computer through USB pinMode(ROT_X, INPUT); // defines inputs and outputs on Arduino pins pinMode(ROT_Y, INPUT); pinMode(ROT_Z, INPUT); pinMode(TRANS_X, INPUT); pinMode(TRANS_Y, INPUT); pinMode(TRANS_Z, INPUT); pinMode(STAGE_BTN, INPUT_PULLUP); pinMode(SAS_LED, OUTPUT); pinMode(RCS_LED, OUTPUT); pinMode(BRAKES_LED, OUTPUT); pinMode(GEAR_LED, OUTPUT); pinMode(LIGHTS_LED, OUTPUT); pinMode(SAS_CLK, INPUT); pinMode(SAS_DT, INPUT); pinMode(SAS_SWITCH, INPUT); pinMode(THROT_CLK, INPUT); pinMode(THROT_DT, INPUT); pinMode(THROT_BTN, INPUT); pinMode(SAS_SWITCH, INPUT_PULLUP); pinMode(RCS_SWITCH, INPUT_PULLUP); pinMode(BRAKES_SWITCH, INPUT_PULLUP); pinMode(GEAR_SWITCH, INPUT_PULLUP); pinMode(LIGHTS_SWITCH, INPUT_PULLUP); pinMode(ABORT_BTN, INPUT_PULLUP); pinMode(AG_01, INPUT_PULLUP); pinMode(AG_02, INPUT_PULLUP); pinMode(AG_03, INPUT_PULLUP); pinMode(AG_04, INPUT_PULLUP); pinMode(AG_05, INPUT_PULLUP); pinMode(AG_06, INPUT_PULLUP); pinMode(AG_07, INPUT_PULLUP); pinMode(AG_08, INPUT_PULLUP); pinMode(AG_09, INPUT_PULLUP); pinMode(AG_10, INPUT_PULLUP); buttonSTAGE.setDebounceTime(debounce_Time); // sets debounce times for buttons buttonTHROT.setDebounceTime(debounce_Time); buttonTHROT_CUT.setDebounceTime(debounce_Time); buttonSAS.setDebounceTime(debounce_Time); buttonRCS.setDebounceTime(debounce_Time); buttonBRAKES.setDebounceTime(debounce_Time); buttonGEAR.setDebounceTime(debounce_Time); buttonLIGHTS.setDebounceTime(debounce_Time); buttonABORT.setDebounceTime(debounce_Time); buttonAG_01.setDebounceTime(debounce_Time); buttonAG_02.setDebounceTime(debounce_Time); buttonAG_03.setDebounceTime(debounce_Time); buttonAG_04.setDebounceTime(debounce_Time); buttonAG_05.setDebounceTime(debounce_Time); buttonAG_06.setDebounceTime(debounce_Time); buttonAG_07.setDebounceTime(debounce_Time); buttonAG_08.setDebounceTime(debounce_Time); buttonAG_09.setDebounceTime(debounce_Time); buttonAG_10.setDebounceTime(debounce_Time); digitalWrite(SAS_LED, HIGH); // turns on all the LEDs while the handshake process is happening digitalWrite(RCS_LED, HIGH); digitalWrite(BRAKES_LED, HIGH); digitalWrite(GEAR_LED, HIGH); digitalWrite(LIGHTS_LED, HIGH); while (!mySimpit.init()) { // initializes (handshakes) with Simpit mod delay(100); } digitalWrite(SAS_LED, LOW); // turns off all the LEDs once the handshake process is complete digitalWrite(RCS_LED, LOW); digitalWrite(BRAKES_LED, LOW); digitalWrite(GEAR_LED, LOW); digitalWrite(LIGHTS_LED, LOW); mySimpit.inboundHandler(messageHandler); // declares the message handler to read incoming messages from Simpit mod mySimpit.registerChannel(ACTIONSTATUS_MESSAGE); // subscribes to the Action Status message channel mySimpit.registerChannel(ROTATION_MESSAGE); // subscribes to the Rotation message channel mySimpit.registerChannel(TRANSLATION_MESSAGE); // subscribes to the Translation message channel } void loop() { mySimpit.update(); // necessary updates and loops for called functions buttonSTAGE.loop(); buttonTHROT.loop(); buttonTHROT_CUT.loop(); buttonSAS.loop(); buttonRCS.loop(); buttonBRAKES.loop(); buttonGEAR.loop(); buttonLIGHTS.loop(); buttonABORT.loop(); buttonAG_01.loop(); buttonAG_02.loop(); buttonAG_03.loop(); buttonAG_04.loop(); buttonAG_05.loop(); buttonAG_06.loop(); buttonAG_07.loop(); buttonAG_08.loop(); buttonAG_09.loop(); buttonAG_10.loop(); throt_Counter = constrain(throt_Counter, 0, 32767); // sets upper and lower limits for counter variables for rotary encoders sas_Counter = constrain(sas_Counter, 1, 10); rot_X_Read = analogRead(ROT_X); // takes a reading for the X-axis; from testing determined X-min = 330, X-mid = 505, X-max = 693 if (rot_X_Read < 510 && rot_X_Read > 500) { // determines if the X-axis pot is in the middle deadzone to eliminate jitter rot_X_Mapped = 0; } if (rot_X_Read <= 500) { // determines if X-axis pot is in the negative portion of its motion rot_X_Mapped = map(rot_X_Read, 330, 500, -32768, 0); // sets the mapping for the negative portion of the axis } if (rot_X_Read >= 510) { // determined if X-axis pot is in the positive portion of its motion rot_X_Mapped = map(rot_X_Read, 510, 693, 0, 32767); // sets the mapping for the positive portion of the axis } rot_X_Mapped = constrain(rot_X_Mapped, -32768, 32767); // constrains the mapped value of the X-axis reading to valid results myRotation.mask = 2; // applies the bitmask required to only send roll information to Simpit myRotation.roll = rot_X_Mapped; // applies the X-axis value as the rotation roll value mySimpit.send(ROTATION_MESSAGE, myRotation); // sends the roll value to Simpit delay(1); rot_Y_Read = analogRead(ROT_Y); if (rot_Y_Read < 518 && rot_Y_Read > 508) { rot_Y_Mapped = 0; } if (rot_Y_Read <= 508) { rot_Y_Mapped = map(rot_Y_Read, 344, 508, -32768, 0); } if (rot_Y_Read >= 518) { rot_Y_Mapped = map(rot_Y_Read, 518, 680, 0, 32767); } rot_Y_Mapped = constrain(rot_Y_Mapped, -32768, 32767); myRotation.mask = 1; myRotation.pitch = rot_Y_Mapped; mySimpit.send(ROTATION_MESSAGE, myRotation); delay(1); rot_Z_Read = analogRead(ROT_Z); if (rot_Z_Read < 520 && rot_Z_Read > 510) { rot_Z_Mapped = 0; } if (rot_Z_Read <= 510) { rot_Z_Mapped = map(rot_Z_Read, 296, 510, -32768, 0); } if (rot_Z_Read >= 520) { rot_Z_Mapped = map(rot_Z_Read, 520, 733, 0, 32767); } rot_Z_Mapped = constrain(rot_Z_Mapped, -32768, 32767); myRotation.mask = 4; myRotation.yaw = rot_Z_Mapped; mySimpit.send(ROTATION_MESSAGE, myRotation); delay(1); trans_X_Read = analogRead(TRANS_X); // takes a reading for the X-axis; from testing determined X-min = 330, X-mid = 505, X-max = 693 if (trans_X_Read < 510 && trans_X_Read > 500) { // determines if the X-axis pot is in the middle deadzone to eliminate jitter trans_X_Mapped = 0; } if (trans_X_Read <= 500) { // determines if X-axis pot is in the negative portion of its motion trans_X_Mapped = map(trans_X_Read, 330, 500, -32768, 0); // sets the mapping for the negative portion of the axis } if (trans_X_Read >= 510) { // determined if X-axis pot is in the positive portion of its motion trans_X_Mapped = map(trans_X_Read, 510, 693, 0, 32767); // sets the mapping for the positive portion of the axis } trans_X_Mapped = constrain(trans_X_Mapped, -32768, 32767); // constrains the mapped value of the X-axis reading to valid results myTranslation.mask = 1; // applies the bitmask required to only send X information to Simpit myTranslation.X = trans_X_Mapped; // applies the X-axis value as the X translation value mySimpit.send(TRANSLATION_MESSAGE, myTranslation); // sends the x translation value to Simpit delay(1); trans_Y_Read = analogRead(TRANS_Y); if (trans_Y_Read < 518 && trans_Y_Read > 508) { trans_Y_Mapped = 0; } if (trans_Y_Read <= 508) { trans_Y_Mapped = map(trans_Y_Read, 344, 508, -32768, 0); } if (trans_Y_Read >= 518) { trans_Y_Mapped = map(trans_Y_Read, 518, 680, 0, 32767); } trans_Y_Mapped = constrain(trans_Y_Mapped, -32768, 32767); myTranslation.mask = 2; myTranslation.Y = trans_Y_Mapped; mySimpit.send(TRANSLATION_MESSAGE, myTranslation); delay(1); trans_Z_Read = analogRead(TRANS_Z); if (trans_Z_Read < 520 && trans_Z_Read > 510) { trans_Z_Mapped = 0; } if (trans_Z_Read <= 510) { trans_Z_Mapped = map(trans_Z_Read, 296, 510, -32768, 0); } if (trans_Z_Read >= 520) { trans_Z_Mapped = map(trans_Z_Read, 520, 733, 0, 32767); } trans_Z_Mapped = constrain(trans_Z_Mapped, -32768, 32767); myTranslation.mask = 4; myTranslation.Z = trans_Z_Mapped; mySimpit.send(TRANSLATION_MESSAGE, myTranslation); delay(1); if (buttonSTAGE.isPressed()) { mySimpit.toggleAction(STAGE_ACTION); } if (buttonTHROT.isPressed()) { throt_Counter = 32767; mySimpit.send(THROTTLE_MESSAGE, throt_Counter); } if (buttonTHROT_CUT.isPressed()) { throt_Counter = 0; mySimpit.send(THROTTLE_MESSAGE, throt_Counter); } if (buttonSAS.isPressed()) { mySimpit.toggleAction(SAS_ACTION); } if (buttonRCS.isPressed()) { // declares action if the RCS button is pressed (toggles RCS on/off) mySimpit.toggleAction(RCS_ACTION); } if (buttonBRAKES.isPressed()) { // declares action if the Brakes button is pressed (toggles Brakes on/off) mySimpit.toggleAction(BRAKES_ACTION); } if (buttonGEAR.isPressed()) { // declares action if the Gear button is pressed (toggles Gear up/down) mySimpit.toggleAction(GEAR_ACTION); } if (buttonLIGHTS.isPressed()) { // declares action if the Lights button is pressed (toggles Lights on/off) mySimpit.toggleAction(LIGHT_ACTION); } if (buttonABORT.isPressed()) { // declares action if the Abort button is pressed (activates the Abort action group) mySimpit.toggleAction(ABORT_ACTION); } if (buttonAG_01.isPressed()) { // declares action if the Action Group 1 is pressed (toggles Action Group 1) mySimpit.toggleCAG(1); } if (buttonAG_02.isPressed()) { // declares action if the Action Group 2 is pressed (toggles Action Group 2) mySimpit.toggleCAG(2); } if (buttonAG_03.isPressed()) { // declares action if the Action Group 3 is pressed (toggles Action Group 3) mySimpit.toggleCAG(3); } if (buttonAG_04.isPressed()) { // declares action if the Action Group 4 is pressed (toggles Action Group 4) mySimpit.toggleCAG(4); } if (buttonAG_05.isPressed()) { // declares action if the Action Group 5 is pressed (toggles Action Group 5) mySimpit.toggleCAG(5); } if (buttonAG_05.isPressed()) { // declares action if the Action Group 6 is pressed (toggles Action Group 6) mySimpit.toggleCAG(6); } if (buttonAG_07.isPressed()) { // declares action if the Action Group 7 is pressed (toggles Action Group 7) mySimpit.toggleCAG(7); } if (buttonAG_08.isPressed()) { // declares action if the Action Group 8 is pressed (toggles Action Group 8) mySimpit.toggleCAG(8); } if (buttonAG_09.isPressed()) { // declares action if the Action Group 9 is pressed (toggles Action Group 9) mySimpit.toggleCAG(9); } if (buttonAG_10.isPressed()) { // declares action if the Action Group 10 is pressed (toggles Action Group 10) mySimpit.toggleCAG(10); } unsigned char throtResult = throtRotary.process(); if (throtResult == DIR_CW && (throt_Counter <= 32349)) { throt_Counter = throt_Counter + 327; // increments the Throttle counter by ~1% mySimpit.send(THROTTLE_MESSAGE, throt_Counter); // sends the new throttle setting to Simpit } if (throtResult == DIR_CCW && (throt_Counter >= 327)) { throt_Counter = throt_Counter - 327; // decrements the Throttle counter by ~1% mySimpit.send(THROTTLE_MESSAGE, throt_Counter); // sends the new throttle setting to Simpit } unsigned char sasResult = sasRotary.process(); if (sasResult == DIR_CW) { sas_Counter++; // increments the SAS counter by 1 mySimpit.send(28, (unsigned char*) &sas_Counter, 1); // sends the new SAS mode setting to Simpit } if (sasResult == DIR_CCW) { sas_Counter--; // decrements the SAS Counter by 1 mySimpit.send(28, (unsigned char*) &sas_Counter, 1); // sends the new SAS mode setting to Simpit } } void messageHandler(byte messageType, byte msg[], byte msgSize) { // sets up the message handler to receive messages from Simpit switch(messageType) { case ACTIONSTATUS_MESSAGE: // defines the set of actions for messages coming from ACTIONSTATUS_MESSAGE byte actions = msg[0]; // assigns the ACTIONSTATUS_MESSAGE to the variable actions if (actions & SAS_ACTION) { // checks to see if SAS is turned on digitalWrite(SAS_LED, HIGH); // turns on the SAS LED indicator if SAS is on } else { digitalWrite(SAS_LED, LOW); // set SAS LED indicator off if SAS is off } if (actions & GEAR_ACTION) { // checks to see if Gear is down digitalWrite(GEAR_LED, HIGH); // turns on Gear LED indicator if gear is down } else { digitalWrite(GEAR_LED, LOW); // set the Gear indicator off if gear is up } if (actions & LIGHT_ACTION) { // checks to see if Lights are on digitalWrite(LIGHTS_LED, HIGH); // turns on Lights LED indicator if lights are on } else { digitalWrite(LIGHTS_LED, LOW); // set Lights indicator off if lights are off } if (actions & RCS_ACTION) { // checks to see if RCS is active digitalWrite(RCS_LED, HIGH); // turns on the RCS LED indicator if RCS is active } else { digitalWrite(RCS_LED, LOW); // set RCS indicator off if RCS is inactive } if (actions & BRAKES_ACTION) { // checks to see if Brakes are on digitalWrite(BRAKES_LED, HIGH); // turns on Brakes LED indicator if brakes are on } else { digitalWrite(BRAKES_LED, LOW); // set Brakes indicator off if brakes are off } break; } } UPDATE: Here is the joystick portion of the code that I finally got to work: int rot_X_Read = analogRead(ROT_X); // takes a reading for the X-axis; from testing determined X-min = 330, X-mid = 505, X-max = 693 if (rot_X_Read < 510 && rot_X_Read > 500) { // determines if the X-axis pot is in the middle deadzone to eliminate jitter rot_X_Mapped = 0; } if (rot_X_Read <= 500) { // determines if X-axis pot is in the negative portion of its motion rot_X_Mapped = map(rot_X_Read, 330, 500, -32768, 0); // sets the mapping for the negative portion of the axis } if (rot_X_Read >= 510) { // determined if X-axis pot is in the positive portion of its motion rot_X_Mapped = map(rot_X_Read, 510, 693, 0, 32767); // sets the mapping for the positive portion of the axis } int rot_Y_Read = analogRead(ROT_Y); if (rot_Y_Read < 518 && rot_Y_Read > 508) { rot_Y_Mapped = 0; } if (rot_Y_Read <= 508) { rot_Y_Mapped = map(rot_Y_Read, 344, 508, -32768, 0); } if (rot_Y_Read >= 518) { rot_Y_Mapped = map(rot_Y_Read, 518, 680, 0, 32767); } int rot_Z_Read = analogRead(ROT_Z); if (rot_Z_Read < 520 && rot_Z_Read > 510) { rot_Z_Mapped = 0; } if (rot_Z_Read <= 510) { rot_Z_Mapped = map(rot_Z_Read, 296, 510, -32768, 0); } if (rot_Z_Read >= 520) { rot_Z_Mapped = map(rot_Z_Read, 520, 733, 0, 32767); } myRotation.mask = 1|2|4; myRotation.pitch = rot_Y_Mapped; myRotation.roll = rot_X_Mapped; // applies the X-axis value as the rotation roll value myRotation.yaw = rot_Z_Mapped; mySimpit.send(ROTATION_MESSAGE, myRotation); // sends the roll value to Simpit int trans_X_Read = analogRead(TRANS_X); // takes a reading for the X-axis; from testing determined X-min = 330, X-mid = 505, X-max = 693 if (trans_X_Read < 510 && trans_X_Read > 500) { // determines if the X-axis pot is in the middle deadzone to eliminate jitter trans_X_Mapped = 0; } if (trans_X_Read <= 500) { // determines if X-axis pot is in the negative portion of its motion trans_X_Mapped = map(trans_X_Read, 330, 500, -32768, 0); // sets the mapping for the negative portion of the axis } if (trans_X_Read >= 510) { // determined if X-axis pot is in the positive portion of its motion trans_X_Mapped = map(trans_X_Read, 510, 693, 0, 32767); // sets the mapping for the positive portion of the axis } int trans_Y_Read = analogRead(TRANS_Y); if (trans_Y_Read < 518 && trans_Y_Read > 508) { trans_Y_Mapped = 0; } if (trans_Y_Read <= 508) { trans_Y_Mapped = map(trans_Y_Read, 344, 508, -32768, 0); } if (trans_Y_Read >= 518) { trans_Y_Mapped = map(trans_Y_Read, 518, 680, 0, 32767); } int trans_Z_Read = analogRead(TRANS_Z); if (trans_Z_Read < 520 && trans_Z_Read > 510) { trans_Z_Mapped = 0; } if (trans_Z_Read <= 510) { trans_Z_Mapped = map(trans_Z_Read, 296, 510, -32768, 0); } if (trans_Z_Read >= 520) { trans_Z_Mapped = map(trans_Z_Read, 520, 733, 0, 32767); } myTranslation.mask = 1|2|4; myTranslation.X = trans_X_Mapped; // applies the X-axis value as the X translation value myTranslation.Y = trans_Y_Mapped; myTranslation.Z = trans_Z_Mapped; mySimpit.send(TRANSLATION_MESSAGE, myTranslation); // sends the x translation value to Simpit Edited June 5, 2020 by PSU_Jedi Update Link to comment Share on other sites More sharing options...
stibbons Posted June 29, 2020 Author Share Posted June 29, 2020 Back after an extended break from all things Kerbal with some small maintenance releases. Arduino library is now up to 1.4.0. This release has some minor changes to the function definitions, to work with recent Arduino releases. I've tested with Arduino 1.8.13, on macOS. Kerbal Simpit plugin has been updated to (coincidentally) 1.4.0 as well. This release builds against KSP 1.9.1, and removes a lot of old code that's now bundled with Unity. CKAN and AVC should find the new plugin now. Arduino is waiting for a library manager rescan, and I promise for sure I'll actually check to make sure it updated tomorrow. No real changes apart from just blowing off the dust, but I expect to find some time to catch up a little more in coming weeks. Link to comment Share on other sites More sharing options...
stibbons Posted July 1, 2020 Author Share Posted July 1, 2020 Because I happened to be awake at the right time, version 1.4.1 is available, built against KSP 1.10.0. Should pop up in the next CKAN index run. Link to comment Share on other sites More sharing options...
Mofates Posted July 14, 2020 Share Posted July 14, 2020 (edited) On 5/19/2020 at 9:51 PM, LRTNZ said: @TygurDuck The big issue is that you are running blocking code - this is where you prevent the processor from doing anything else, as it is stuck in a delay. @Mofates your demo code using the boolean operators and the timer code is how I would recommend to do it. There is one really big issue though - that is, you have about 65 seconds of useful time to use it, before you will probably encounter some really weird timing bugs, when lastBlink rolls over back to zero. An unsigned int on an arduino has a maximum value of 65,535. As you are storing milliseconds, that comes to just over a minute, until it rolls over. You need to be using an unsigned long, which can hold a maximum value of 4,294,967,295 - if you manage to exceed that, you really need to stop playing @LRTNZyes, of course it should have been an unsigned long! I have no idea what part of my brain saw a squirrel while I was writing that. : ) Edited July 14, 2020 by Mofates Fixed @Tag Link to comment Share on other sites More sharing options...
stibbons Posted July 14, 2020 Author Share Posted July 14, 2020 On 12/23/2019 at 6:27 AM, TygurDuck said: Do I have to use Altnerate Resource Panel for it to work at all? To answer a fairly old question: yes, without ARP the resource channels will not be sent at all. I'll make sure the documentation is clearer on this. Getting stage and vessel resources isn't exactly a trivial thing - there's some calculation involved. Rather than reinvent the wheel I chose to use the very tidy API that Alternate Resources Panel provides for its data. (for bonus points, even though simpit only supports stock resources, using ARP makes it really really easy to write a companion plugin for modded resources) Link to comment Share on other sites More sharing options...
PSU_Jedi Posted July 20, 2020 Share Posted July 20, 2020 My control box becomes unresponsive ~20-30 minutes into gameplay, or sometimes it seems shorter if I'm using the analog joysticks a lot. Given that, it seems that maybe the information exchange between the Mega board and the game is getting overloaded? Also, the rotary encoder for my SAS mode selector isn't working anymore. Could be that the wiring came loose (hard to check without pulling the whole panel off the control box), but if you see anything in that part of the code that would give you pause, let me know please. BTW, I also have a Leonardo emulating keyboard commands into KSP running on the same control box. It continues to function indefinitely, even after the Mega quits functioning. Code is below...any help would be appreciated! // Sets up the Arduino Mega to handle the analog joysticks, Action Groups, switches and buttons #include <KerbalSimpit.h> #include <KerbalSimpitMessageTypes.h> #include <PayloadStructs.h> #include <ezButton.h> // loads ezButton library for button debounce #include <Rotary.h> rotationMessage myRotation; translationMessage myTranslation; const int ROT_X = A0; // assigns rotation joystick X-axis to pin Analog 0 const int ROT_Y = A1; // assigns rotation joystick Y-axis to pin Analog 1 const int ROT_Z = A2; // assigns rotation joystick Z-axis to pin Analog 2 const int TRANS_X = A3; // assigns translation joystick X-axis to pin Analog 3 const int TRANS_Y = A4; // assigns translation joystick Y-axis to pin Analog 4 const int TRANS_Z = A5; // assigns translation joystick Z-axis to pin Analog 5 const int STAGE_BTN = 2; // assigns the Staging button to pin 2 const int RCS_LED = 3; // assigns the RCS indicator LED to pin 3 const int BRAKES_LED = 4; // assigns the Brakes indicator LED to pin 4 const int GEAR_LED = 5; // assigns the Landing Gear indicator LED to pin 5 const int LIGHTS_LED = 6; // assigns the Lights indicator LED to pin 6 const int SAS_LED = 7; // assigns the SAS indicator LED to pin 7 const int THROT_CLK = 22; // assigns the Throttle rotary encoder CLK output ("A") to pin 22 const int THROT_DT = 23; // assigns the Throttle rotary encoder DT output ("B") to pin 23 const int THROT_BTN = 24; // assigns the Throttle rotary encoder Switch output to pin 24 const int THROT_CUT = 25; // assigns the Throttle Cut button output to pin 25 const int SAS_CLK = 32; // assigns the SAS rotary encoder CLK output ("A") to pin 32 const int SAS_DT = 33; // assigns the SAS rotary encoder DT output ("B") to pin 33 const int SAS_SWITCH = 34; // assigns the SAS switch output to pin 34 const int RCS_SWITCH = 35; // assigns the RCS switch output to pin 35 const int BRAKES_SWITCH = 36; // assigns the Brakes switch output to pin 36 const int GEAR_SWITCH = 37; // assigns the Gear switch output to pin 37 const int LIGHTS_SWITCH = 38; // assigns the Lights switch output to pin 38 const int ABORT_BTN = 39; // assigns the Abort switch output to pin 38 const int AG_01 = 41; // assigns the Action Group 1 switch output to pin 41 const int AG_02 = 42; // assigns the Action Group 2 switch output to pin 42 const int AG_03 = 43; // assigns the Action Group 3 switch output to pin 43 const int AG_04 = 44; // assigns the Action Group 4 switch output to pin 44 const int AG_05 = 45; // assigns the Action Group 5 switch output to pin 45 const int AG_06 = 46; // assigns the Action Group 6 switch output to pin 46 const int AG_07 = 47; // assigns the Action Group 7 switch output to pin 47 const int AG_08 = 48; // assigns the Action Group 8 switch output to pin 48 const int AG_09 = 49; // assigns the Action Group 9 switch output to pin 49 const int AG_10 = 50; // assigns the Action Group 10 switch output to pin 50 int sas_Counter = 1; // initializes SAS Mode counter value variable at 1 int currentSASStateCLK; int lastSASStateCLK; int throt_Counter = 0; // initializes Throttle counter value variable at 0 int currentThrotStateCLK; int lastThrotStateCLK; int rot_X_Read; int rot_Y_Read; int rot_Z_Read; int rot_X_Mapped; int rot_Y_Mapped; int rot_Z_Mapped; int trans_X_Read; int trans_Y_Read; int trans_Z_Read; int trans_X_Mapped; int trans_Y_Mapped; int trans_Z_Mapped; int debounce_Time = 25; KerbalSimpit mySimpit(Serial); ezButton buttonSTAGE(STAGE_BTN); ezButton buttonTHROT(THROT_BTN); ezButton buttonTHROT_CUT(THROT_CUT); ezButton buttonSAS(SAS_SWITCH); ezButton buttonRCS(RCS_SWITCH); ezButton buttonBRAKES(BRAKES_SWITCH); ezButton buttonGEAR(GEAR_SWITCH); ezButton buttonLIGHTS(LIGHTS_SWITCH); ezButton buttonABORT(ABORT_BTN); ezButton buttonAG_01(AG_01); ezButton buttonAG_02(AG_02); ezButton buttonAG_03(AG_03); ezButton buttonAG_04(AG_04); ezButton buttonAG_05(AG_05); ezButton buttonAG_06(AG_06); ezButton buttonAG_07(AG_07); ezButton buttonAG_08(AG_08); ezButton buttonAG_09(AG_09); ezButton buttonAG_10(AG_10); Rotary throtRotary = Rotary(THROT_DT, THROT_CLK); Rotary sasRotary = Rotary(SAS_DT, SAS_CLK); void setup() { Serial.begin(115200); // begins the serial connection to the computer through USB pinMode(ROT_X, INPUT); // defines inputs and outputs on Arduino pins pinMode(ROT_Y, INPUT); pinMode(ROT_Z, INPUT); pinMode(TRANS_X, INPUT); pinMode(TRANS_Y, INPUT); pinMode(TRANS_Z, INPUT); pinMode(STAGE_BTN, INPUT_PULLUP); pinMode(SAS_LED, OUTPUT); pinMode(RCS_LED, OUTPUT); pinMode(BRAKES_LED, OUTPUT); pinMode(GEAR_LED, OUTPUT); pinMode(LIGHTS_LED, OUTPUT); pinMode(SAS_CLK, INPUT); pinMode(SAS_DT, INPUT); pinMode(SAS_SWITCH, INPUT); pinMode(THROT_CLK, INPUT); pinMode(THROT_DT, INPUT); pinMode(THROT_BTN, INPUT); pinMode(SAS_SWITCH, INPUT_PULLUP); pinMode(RCS_SWITCH, INPUT_PULLUP); pinMode(BRAKES_SWITCH, INPUT_PULLUP); pinMode(GEAR_SWITCH, INPUT_PULLUP); pinMode(LIGHTS_SWITCH, INPUT_PULLUP); pinMode(ABORT_BTN, INPUT_PULLUP); pinMode(AG_01, INPUT_PULLUP); pinMode(AG_02, INPUT_PULLUP); pinMode(AG_03, INPUT_PULLUP); pinMode(AG_04, INPUT_PULLUP); pinMode(AG_05, INPUT_PULLUP); pinMode(AG_06, INPUT_PULLUP); pinMode(AG_07, INPUT_PULLUP); pinMode(AG_08, INPUT_PULLUP); pinMode(AG_09, INPUT_PULLUP); pinMode(AG_10, INPUT_PULLUP); buttonSTAGE.setDebounceTime(debounce_Time); // sets debounce times for buttons buttonTHROT.setDebounceTime(debounce_Time); buttonTHROT_CUT.setDebounceTime(debounce_Time); buttonSAS.setDebounceTime(debounce_Time); buttonRCS.setDebounceTime(debounce_Time); buttonBRAKES.setDebounceTime(debounce_Time); buttonGEAR.setDebounceTime(debounce_Time); buttonLIGHTS.setDebounceTime(debounce_Time); buttonABORT.setDebounceTime(debounce_Time); buttonAG_01.setDebounceTime(debounce_Time); buttonAG_02.setDebounceTime(debounce_Time); buttonAG_03.setDebounceTime(debounce_Time); buttonAG_04.setDebounceTime(debounce_Time); buttonAG_05.setDebounceTime(debounce_Time); buttonAG_06.setDebounceTime(debounce_Time); buttonAG_07.setDebounceTime(debounce_Time); buttonAG_08.setDebounceTime(debounce_Time); buttonAG_09.setDebounceTime(debounce_Time); buttonAG_10.setDebounceTime(debounce_Time); digitalWrite(SAS_LED, HIGH); // turns on all the LEDs while the handshake process is happening digitalWrite(RCS_LED, HIGH); digitalWrite(BRAKES_LED, HIGH); digitalWrite(GEAR_LED, HIGH); digitalWrite(LIGHTS_LED, HIGH); while (!mySimpit.init()) { // initializes (handshakes) with Simpit mod delay(100); } digitalWrite(SAS_LED, LOW); // turns off all the LEDs once the handshake process is complete digitalWrite(RCS_LED, LOW); digitalWrite(BRAKES_LED, LOW); digitalWrite(GEAR_LED, LOW); digitalWrite(LIGHTS_LED, LOW); mySimpit.inboundHandler(messageHandler); // declares the message handler to read incoming messages from Simpit mod mySimpit.registerChannel(ACTIONSTATUS_MESSAGE); // subscribes to the Action Status message channel mySimpit.registerChannel(ROTATION_MESSAGE); // subscribes to the Rotation message channel mySimpit.registerChannel(TRANSLATION_MESSAGE); // subscribes to the Translation message channel mySimpit.registerChannel(SCENE_CHANGE_MESSAGE); // subscribes to the Scene Change message channel } void loop() { mySimpit.update(); // necessary updates and loops for called functions buttonSTAGE.loop(); buttonTHROT.loop(); buttonTHROT_CUT.loop(); buttonSAS.loop(); buttonRCS.loop(); buttonBRAKES.loop(); buttonGEAR.loop(); buttonLIGHTS.loop(); buttonABORT.loop(); buttonAG_01.loop(); buttonAG_02.loop(); buttonAG_03.loop(); buttonAG_04.loop(); buttonAG_05.loop(); buttonAG_06.loop(); buttonAG_07.loop(); buttonAG_08.loop(); buttonAG_09.loop(); buttonAG_10.loop(); throt_Counter = constrain(throt_Counter, 0, 32767); // sets upper and lower limits for counter variables for rotary encoders sas_Counter = constrain(sas_Counter, 1, 10); int rot_X_Read = analogRead(ROT_X); // takes a reading for the X-axis; from testing determined X-min = 330, X-mid = 505, X-max = 693 if (rot_X_Read < 510 && rot_X_Read > 500) { // determines if the X-axis pot is in the middle deadzone to eliminate jitter rot_X_Mapped = 0; } if (rot_X_Read <= 500) { // determines if X-axis pot is in the negative portion of its motion rot_X_Mapped = map(rot_X_Read, 330, 500, -32768, 0); // sets the mapping for the negative portion of the axis } if (rot_X_Read >= 510) { // determined if X-axis pot is in the positive portion of its motion rot_X_Mapped = map(rot_X_Read, 510, 693, 0, 32767); // sets the mapping for the positive portion of the axis } int rot_Y_Read = analogRead(ROT_Y); if (rot_Y_Read < 518 && rot_Y_Read > 508) { rot_Y_Mapped = 0; } if (rot_Y_Read <= 508) { rot_Y_Mapped = map(rot_Y_Read, 344, 508, -32768, 0); } if (rot_Y_Read >= 518) { rot_Y_Mapped = map(rot_Y_Read, 518, 680, 0, 32767); } int rot_Z_Read = analogRead(ROT_Z); if (rot_Z_Read < 520 && rot_Z_Read > 510) { rot_Z_Mapped = 0; } if (rot_Z_Read <= 510) { rot_Z_Mapped = map(rot_Z_Read, 296, 510, -32768, 0); } if (rot_Z_Read >= 520) { rot_Z_Mapped = map(rot_Z_Read, 520, 733, 0, 32767); } myRotation.mask = 1|2|4; myRotation.pitch = rot_Y_Mapped; myRotation.roll = rot_X_Mapped; // applies the X-axis value as the rotation roll value myRotation.yaw = rot_Z_Mapped; mySimpit.send(ROTATION_MESSAGE, myRotation); // sends the rotation value to Simpit int trans_X_Read = analogRead(TRANS_X); // takes a reading for the X-axis; from testing determined X-min = 330, X-mid = 505, X-max = 693 if (trans_X_Read < 510 && trans_X_Read > 500) { // determines if the X-axis pot is in the middle deadzone to eliminate jitter trans_X_Mapped = 0; } if (trans_X_Read <= 500) { // determines if X-axis pot is in the negative portion of its motion trans_X_Mapped = map(trans_X_Read, 330, 500, -32768, 0); // sets the mapping for the negative portion of the axis } if (trans_X_Read >= 510) { // determined if X-axis pot is in the positive portion of its motion trans_X_Mapped = map(trans_X_Read, 510, 693, 0, 32767); // sets the mapping for the positive portion of the axis } int trans_Y_Read = analogRead(TRANS_Y); if (trans_Y_Read < 518 && trans_Y_Read > 508) { trans_Y_Mapped = 0; } if (trans_Y_Read <= 508) { trans_Y_Mapped = map(trans_Y_Read, 344, 508, -32768, 0); } if (trans_Y_Read >= 518) { trans_Y_Mapped = map(trans_Y_Read, 518, 680, 0, 32767); } int trans_Z_Read = analogRead(TRANS_Z); if (trans_Z_Read < 520 && trans_Z_Read > 510) { trans_Z_Mapped = 0; } if (trans_Z_Read <= 510) { trans_Z_Mapped = map(trans_Z_Read, 296, 510, -32768, 0); } if (trans_Z_Read >= 520) { trans_Z_Mapped = map(trans_Z_Read, 520, 733, 0, 32767); } myTranslation.mask = 1|2|4; myTranslation.X = trans_X_Mapped; // applies the X-axis value as the X translation value myTranslation.Y = trans_Y_Mapped; myTranslation.Z = trans_Z_Mapped; mySimpit.send(TRANSLATION_MESSAGE, myTranslation); // sends the translation value to Simpit if (buttonSTAGE.isPressed()) { mySimpit.toggleAction(STAGE_ACTION); } if (buttonTHROT.isPressed()) { throt_Counter = 32767; mySimpit.send(THROTTLE_MESSAGE, throt_Counter); } if (buttonTHROT_CUT.isPressed()) { throt_Counter = 0; mySimpit.send(THROTTLE_MESSAGE, throt_Counter); } if (buttonSAS.isPressed()) { mySimpit.toggleAction(SAS_ACTION); } if (buttonRCS.isPressed()) { // declares action if the RCS button is pressed (toggles RCS on/off) mySimpit.toggleAction(RCS_ACTION); } if (buttonBRAKES.isPressed()) { // declares action if the Brakes button is pressed (toggles Brakes on/off) mySimpit.toggleAction(BRAKES_ACTION); } if (buttonGEAR.isPressed()) { // declares action if the Gear button is pressed (toggles Gear up/down) mySimpit.toggleAction(GEAR_ACTION); } if (buttonLIGHTS.isPressed()) { // declares action if the Lights button is pressed (toggles Lights on/off) mySimpit.toggleAction(LIGHT_ACTION); } if (buttonABORT.isPressed()) { // declares action if the Abort button is pressed (activates the Abort action group) mySimpit.toggleAction(ABORT_ACTION); } if (buttonAG_01.isPressed()) { // declares action if the Action Group 1 is pressed (toggles Action Group 1) mySimpit.toggleCAG(1); } if (buttonAG_02.isPressed()) { // declares action if the Action Group 2 is pressed (toggles Action Group 2) mySimpit.toggleCAG(2); } if (buttonAG_03.isPressed()) { // declares action if the Action Group 3 is pressed (toggles Action Group 3) mySimpit.toggleCAG(3); } if (buttonAG_04.isPressed()) { // declares action if the Action Group 4 is pressed (toggles Action Group 4) mySimpit.toggleCAG(4); } if (buttonAG_05.isPressed()) { // declares action if the Action Group 5 is pressed (toggles Action Group 5) mySimpit.toggleCAG(5); } if (buttonAG_05.isPressed()) { // declares action if the Action Group 6 is pressed (toggles Action Group 6) mySimpit.toggleCAG(6); } if (buttonAG_07.isPressed()) { // declares action if the Action Group 7 is pressed (toggles Action Group 7) mySimpit.toggleCAG(7); } if (buttonAG_08.isPressed()) { // declares action if the Action Group 8 is pressed (toggles Action Group 8) mySimpit.toggleCAG(8); } if (buttonAG_09.isPressed()) { // declares action if the Action Group 9 is pressed (toggles Action Group 9) mySimpit.toggleCAG(9); } if (buttonAG_10.isPressed()) { // declares action if the Action Group 10 is pressed (toggles Action Group 10) mySimpit.toggleCAG(10); } unsigned char throtResult = throtRotary.process(); if (throtResult == DIR_CW && (throt_Counter <= 29487)) { throt_Counter = throt_Counter + 3276; // increments the Throttle counter by ~10% mySimpit.send(THROTTLE_MESSAGE, throt_Counter); // sends the new throttle setting to Simpit } if (throtResult == DIR_CCW && (throt_Counter >= 3276)) { throt_Counter = throt_Counter - 3276; // decrements the Throttle counter by ~10% mySimpit.send(THROTTLE_MESSAGE, throt_Counter); // sends the new throttle setting to Simpit } unsigned char sasResult = sasRotary.process(); if (sasResult == DIR_CW) { sas_Counter++; // increments the SAS counter by 1 mySimpit.send(28, (unsigned char*) &sas_Counter, 1); // sends the new SAS mode setting to Simpit } if (sasResult == DIR_CCW) { sas_Counter--; // decrements the SAS Counter by 1 mySimpit.send(28, (unsigned char*) &sas_Counter, 1); // sends the new SAS mode setting to Simpit } } void messageHandler(byte messageType, byte msg[], byte msgSize) { // sets up the message handler to receive messages from Simpit switch(messageType) { case ACTIONSTATUS_MESSAGE: // defines the set of actions for messages coming from ACTIONSTATUS_MESSAGE byte actions = msg[0]; // assigns the ACTIONSTATUS_MESSAGE to the variable actions if (actions & SAS_ACTION) { // checks to see if SAS is turned on digitalWrite(SAS_LED, HIGH); // turns on the SAS LED indicator if SAS is on } else { digitalWrite(SAS_LED, LOW); // set SAS LED indicator off if SAS is off } if (actions & GEAR_ACTION) { // checks to see if Gear is down digitalWrite(GEAR_LED, HIGH); // turns on Gear LED indicator if gear is down } else { digitalWrite(GEAR_LED, LOW); // set the Gear indicator off if gear is up } if (actions & LIGHT_ACTION) { // checks to see if Lights are on digitalWrite(LIGHTS_LED, HIGH); // turns on Lights LED indicator if lights are on } else { digitalWrite(LIGHTS_LED, LOW); // set Lights indicator off if lights are off } if (actions & RCS_ACTION) { // checks to see if RCS is active digitalWrite(RCS_LED, HIGH); // turns on the RCS LED indicator if RCS is active } else { digitalWrite(RCS_LED, LOW); // set RCS indicator off if RCS is inactive } if (actions & BRAKES_ACTION) { // checks to see if Brakes are on digitalWrite(BRAKES_LED, HIGH); // turns on Brakes LED indicator if brakes are on } else { digitalWrite(BRAKES_LED, LOW); // set Brakes indicator off if brakes are off } break; case SCENE_CHANGE_MESSAGE: // defines the set of actions for messages coming from SCENE-CHANGE-MESSAGE byte scene_state = msg[0]; // assigns the SCENE_CHANGE_MESSAGE to the variable scene_state if (scene_state & 0x01) { // checks to see if we are leaving the Flight scene digitalWrite(SAS_LED, LOW); // turns off all LED indicators is leaving the Flight scene digitalWrite(GEAR_LED, LOW); digitalWrite(LIGHTS_LED, LOW); digitalWrite(RCS_LED, LOW); digitalWrite(BRAKES_LED, LOW); } break; } } Link to comment Share on other sites More sharing options...
stibbons Posted July 21, 2020 Author Share Posted July 21, 2020 Hey mate. Sorry you've been having troubles. Let me start with the easiest stuff first: 19 hours ago, PSU_Jedi said: Also, the rotary encoder for my SAS mode selector isn't working anymore. Could be that the wiring came loose (hard to check without pulling the whole panel off the control box), but if you see anything in that part of the code that would give you pause, let me know please. I'm not familiar with rotary encoders at all tbh, but I assume you're using the library at https://github.com/brianlow/Rotary to work with it (that's the one I installed in my IDE to get your sketch to compile). You're right, the first thing to check is that it actually works at all. If it were me I'd test it with one of the Rotary library examples - it looks like your code basically replicates what the Polling example does. After that, I'd be thinking about whether or not turning rotary encoder events are just getting lost because your code is so busy doing other things that it can't poll fast enough. Did it just recently stop working after you had the rest of your setup finalised? Or did it stop somewhere along the way of adding more functionality to your sketch? It might be that you have to delve in to figuring out how to use interrupts to do some processing of events from your encoders. That said, I can't see anything wrong with your code, but I do have some suggestions! Your SAS calls, like mySimpit.send(28, (unsigned char*) &sas_Counter, 1); // sends the new SAS mode setting to Simpit feel clumsy. Do you really need to use the pointers there? I thought just `mySimpit.send(28, sas_Counter, 1);` would work. And, indeed, I had to change the code to that to make it compile on my local machine using Arduino 1.8.3 and Simpit 1.4.0. Haven't actually run it though. Your joystick read routines will be slightly faster with a series of if/else statements rather than just ifs. Like this int rot_Y_Read = analogRead(ROT_Y); if (rot_Y_Read < 518 && rot_Y_Read > 508) { rot_Y_Mapped = 0; } else if (rot_Y_Read <= 508) { rot_Y_Mapped = map(rot_Y_Read, 344, 508, -32768, 0); } else if (rot_Y_Read >= 518) { rot_Y_Mapped = map(rot_Y_Read, 518, 680, 0, 32767); } The only other thing I'll say is that digitalWrite is surprisingly slow. Your messageHandler currently writes every single action LED whenever you get an ACTIONSTATUS message. If you keep variables tracking what the LED currently is, you can write messageHandler so it only updates the LED if it changes. Something like // First we need a global variable to remember SAS state: int sasActive = 0; // You could use a shorter type here if you're tight on space. // Then we do this in messageHandler: // Check if SAS_ACTION in our actions packet matches what we remember. // If not, remember the current value and write it to the LED. if (actions & SAS_ACTION != sasActive) { sasActive = actions & SAS_ACTION; digitalWrite(SAS_LED, sasActive); } // no else required any more! OK. That's the easy stuff. Link to comment Share on other sites More sharing options...
stibbons Posted July 21, 2020 Author Share Posted July 21, 2020 (edited) Now the harder stuff. 20 hours ago, PSU_Jedi said: My control box becomes unresponsive ~20-30 minutes into gameplay, or sometimes it seems shorter if I'm using the analog joysticks a lot. Given that, it seems that maybe the information exchange between the Mega board and the game is getting overloaded? I do not know why. Yet. But let me ask the stupid questions: what exactly do you mean by unresponsive? Does it just stop updating LEDs? Does it just stop sending data from your joysticks? Is it both? Does it catch fire (OK maybe not, but I definitely had a small fire on my controller thanks to a shorted LED at one point)? My first thought was maybe you were leaking memory somehow and the arduino was resetting. But that doesn't seem likely - you've got a lot of free RAM, and I don't see any obvious leaks in this code (although there might be some in the library?). And you're also turning all of your LEDs on in your init. If the arduino was resetting then your board would light up. So that's not it. Your thinking around the volume of info getting from the game to your mega is overloading things could be right. I think that would mean that the serial buffer on your Arduino is filling up faster than your sketch is able to read it. You can check that! The serial buffer should be 64 bytes, I think, and `Serial.available()` will tell you how many bytes are in the buffer. So you could temporarily repurpose one of your LEDs and use it to tell you if the buffer ever gets full. Remove the code from messageHandler that updates your Brake LED (because nobody should ever be using the brakes, gosh!), and then put something like this at the top of your loop(). Note that the best place for it is right before you call the simpit update, because that's the fullest the buffer will get. // The serial receive buffer should be 64 bytes. // Check how much is there, and flip a warning light on if we've filled it: if (Serial.available() > 63) { digitalWrite(BRAKES_LED, HIGH); } And then play until your board stops. If the brake light comes on at any point there, then you know to blame the buffer. Finally, you can also get more logging out of the game. It's worth turning on the debug flag in the Kerbal Simpit config file. Play until you get the problem, and then upload the KSP.log file somewhere I can get to it. With the debug flag on, Simpit logs a lot. You should be able to find messages from it by just searching the log file for "KerbalSimpit". Edited July 21, 2020 by stibbons Link to comment Share on other sites More sharing options...
stibbons Posted July 22, 2020 Author Share Posted July 22, 2020 On 7/21/2020 at 12:21 AM, PSU_Jedi said: Given that, it seems that maybe the information exchange between the Mega board and the game is getting overloaded? Gah, I forgot the one other thing fairly simple thing you can try to test this theory, without having to recompile your controller fimrware. It might be worth experimenting with the RefreshRate in the config file. The default is 125 milliseconds, maybe try doubling that to 250 and see how you go. Link to comment Share on other sites More sharing options...
PSU_Jedi Posted July 24, 2020 Share Posted July 24, 2020 I'm running KSP version 1.10.0.2917 on Windows 10. Acording to CKAN I have Kerbal Simpit version 1.4.1.66. I'm on Arduino IDE 1.8.13 (Windows Store 1.8.42.0). On 7/21/2020 at 6:49 AM, stibbons said: mySimpit.send(28, (unsigned char*) &sas_Counter, 1); // sends the new SAS mode setting to Simpit feel clumsy. Do you really need to use the pointers there? I thought just `mySimpit.send(28, sas_Counter, 1);` would work. And, indeed, I had to change the code to that to make it compile on my local machine using Arduino 1.8.3 and Simpit 1.4.0. Haven't actually run it though. I tried your code here and strangely I got this error: no matching function for call to 'KerbalSimpit::send(int, int*, int)' Quote Your joystick read routines will be slightly faster with a series of if/else statements rather than just ifs. Like this int rot_Y_Read = analogRead(ROT_Y); if (rot_Y_Read < 518 && rot_Y_Read > 508) { rot_Y_Mapped = 0; } else if (rot_Y_Read <= 508) { rot_Y_Mapped = map(rot_Y_Read, 344, 508, -32768, 0); } else if (rot_Y_Read >= 518) { rot_Y_Mapped = map(rot_Y_Read, 518, 680, 0, 32767); } On 7/21/2020 at 7:09 AM, stibbons said: // The serial receive buffer should be 64 bytes. // Check how much is there, and flip a warning light on if we've filled it: if (Serial.available() > 63) { digitalWrite(BRAKES_LED, HIGH); } These two pieces of advice seemed to work really well. I played for well over a half hour and had no issues with the controller locking up at all. I didn't change the RefreshRate at all. So based on a couple of test runs, I want to say it was the code for the analog stick that was overloading everything. On 7/21/2020 at 6:49 AM, stibbons said: // First we need a global variable to remember SAS state: int sasActive = 0; // You could use a shorter type here if you're tight on space. // Then we do this in messageHandler: // Check if SAS_ACTION in our actions packet matches what we remember. // If not, remember the current value and write it to the LED. if (actions & SAS_ACTION != sasActive) { sasActive = actions & SAS_ACTION; digitalWrite(SAS_LED, sasActive); } // no else required any more! OK. That's the easy stuff. Also, something I did in this part of code didn't work right. The LEDs no longer responded properly and only seemed to randomly come on and never turned off once on. THANKS for your advice above! It has really helped me enjoy my custom controller again!!! Link to comment Share on other sites More sharing options...
midnitemax Posted September 6, 2020 Share Posted September 6, 2020 (edited) On 7/21/2020 at 1:09 PM, stibbons said: Your thinking around the volume of info getting from the game to your mega is overloading things could be right. I think that would mean that the serial buffer on your Arduino is filling up faster than your sketch is able to read it. You can check that! The serial buffer should be 64 bytes, I think, and `Serial.available()` will tell you how many bytes are in the buffer. So you could temporarily repurpose one of your LEDs and use it to tell you if the buffer ever gets full. Remove the code from messageHandler that updates your Brake LED (because nobody should ever be using the brakes, gosh!), and then put something like this at the top of your loop(). Note that the best place for it is right before you call the simpit update, because that's the fullest the buffer will get. // The serial receive buffer should be 64 bytes. // Check how much is there, and flip a warning light on if we've filled it: if (Serial.available() > 63) { digitalWrite(BRAKES_LED, HIGH); } And then play until your board stops. If the brake light comes on at any point there, then you know to blame the buffer. Just wanted to chime in on this discussion, because I have similar problems. It doesn't seem like the serial buffer filling up is the issue. I followed your other advice though and that solved the problem (at least this one ). Edited September 7, 2020 by midnitemax Link to comment Share on other sites More sharing options...
midnitemax Posted September 21, 2020 Share Posted September 21, 2020 So, I've run into this problem again (controller becoming unresponsive) and now it happens right away when I want to send a translation message. Here's my code: #include <KerbalSimpit.h> #include <PayloadStructs.h> #include <DebounceInput.h> #define forwardPin 51 #define backwardPin 50 #define rightPin 52 #define leftPin 53 #define upPin 48 #define downPin 49 #define stagePin 26 int lastUpdte = 0; int updateDelay = 125; DebouncedInput displaySelect(4); DebouncedInput forward(forwardPin); DebouncedInput backward(backwardPin); DebouncedInput right(rightPin); DebouncedInput left(leftPin); DebouncedInput up(upPin); DebouncedInput down(downPin); DebouncedInput stage(stagePin); KerbalSimpit mySimpit(Serial); void setup() { Serial.begin(115200); while (!mySimpit.init()); } void loop() { mySimpit.update(); stage.read(); if (stage.falling()) { mySimpit.activateAction(STAGE_ACTION); } translation(); } void translation() { translationMessage translationMsg; translationMsg.mask=1|2|4; forward.read(); backward.read(); right.read(); left.read(); up.read(); down.read(); if (forward.falling() || forward.low()) { translationMsg.X = 32767; } if (backward.falling() || backward.low()) { translationMsg.X = -32767; } if (right.falling() || right.low()) { translationMsg.Y = 32767; } if (left.falling() || left.low()) { translationMsg.Y = -32767; } if (up.falling() || up.low()) { translationMsg.Z = 32767; } if (down.falling() || down.low()) { translationMsg.Z = -32767; } mySimpit.send(TRANSLATION_MESSAGE,translationMsg); } If I comment out the translation(); it works fine (well, all it really does then is staging). But if I leave it in, the staging doesn't work either, indicating to me, that something somewhere has crashed. Link to comment Share on other sites More sharing options...
PSU_Jedi Posted October 23, 2020 Share Posted October 23, 2020 On 9/21/2020 at 5:36 AM, midnitemax said: So, I've run into this problem again (controller becoming unresponsive) and now it happens right away when I want to send a translation message. Here's my code: #include <KerbalSimpit.h> #include <PayloadStructs.h> #include <DebounceInput.h> #define forwardPin 51 #define backwardPin 50 #define rightPin 52 #define leftPin 53 #define upPin 48 #define downPin 49 #define stagePin 26 int lastUpdte = 0; int updateDelay = 125; DebouncedInput displaySelect(4); DebouncedInput forward(forwardPin); DebouncedInput backward(backwardPin); DebouncedInput right(rightPin); DebouncedInput left(leftPin); DebouncedInput up(upPin); DebouncedInput down(downPin); DebouncedInput stage(stagePin); KerbalSimpit mySimpit(Serial); void setup() { Serial.begin(115200); while (!mySimpit.init()); } void loop() { mySimpit.update(); stage.read(); if (stage.falling()) { mySimpit.activateAction(STAGE_ACTION); } translation(); } void translation() { translationMessage translationMsg; translationMsg.mask=1|2|4; forward.read(); backward.read(); right.read(); left.read(); up.read(); down.read(); if (forward.falling() || forward.low()) { translationMsg.X = 32767; } if (backward.falling() || backward.low()) { translationMsg.X = -32767; } if (right.falling() || right.low()) { translationMsg.Y = 32767; } if (left.falling() || left.low()) { translationMsg.Y = -32767; } if (up.falling() || up.low()) { translationMsg.Z = 32767; } if (down.falling() || down.low()) { translationMsg.Z = -32767; } mySimpit.send(TRANSLATION_MESSAGE,translationMsg); } If I comment out the translation(); it works fine (well, all it really does then is staging). But if I leave it in, the staging doesn't work either, indicating to me, that something somewhere has crashed. What happens if you put the translation code directly into loop() instead of in a separate call? Link to comment Share on other sites More sharing options...
TheDicko Posted October 24, 2020 Share Posted October 24, 2020 Hi, just started out with what looks to be an amazing mod. Quick question, how do you guys debug code? I was thinking of printing to the serial monitor, but it says port busy, when using ksp. Link to comment Share on other sites More sharing options...
Codapop Posted October 24, 2020 Share Posted October 24, 2020 18 minutes ago, TheDicko said: Hi, just started out with what looks to be an amazing mod. Quick question, how do you guys debug code? I was thinking of printing to the serial monitor, but it says port busy, when using ksp. You can use the built-in LED in most arduinos (LED_BUILTIN) and have it turn on/off depending on where it is in the code. Alternatively, if you have any other LED indicators or displays (like a 7 segment display) you could have the arduino send debug messages there. Link to comment Share on other sites More sharing options...
Recommended Posts