Jump to content

[Hardware, Plugin] Arduino based physical display + serial port io+ tutorial (24-11-19)


zitronen

Recommended Posts

Hi they are listed in the example arduino code (first tab)

//Input enums
#define SAS 7
#define RCS 6
#define LIGHTS 5
#define GEAR 4
#define BRAKES 3
#define PRECISION 2
#define ABORT 1
#define STAGE 0

 

 

 

Link to comment
Share on other sites

I'm having some difficulty getting my LCD display to work again for some reason. I have tested the LCD screen so I know it's working. Here is what I have in the KSPISO (tab)

//lcd
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

Simple enough.. and this is what I have in the Utilities Tab...trying to get the AP and PE data to view.

void Indicators() {

 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.setCursor(0,0);
  lcd.print((long)VData.AP);
  lcd.setCursor(0,1);
  lcd.print((long)VData.PE);
}

void InitTxPackets() {
  HPacket.id = 0;  
  CPacket.id = 101;
}

Nothing is showing up on the LCD screen. Am I missing something?

I'm using current plugin with ksp1.3 . I have tested the kspido demo16 and that worked, so I don't think it's a version mess up.

Edited by Freakout242
More info
Link to comment
Share on other sites

4 minutes ago, Freshmeat said:

Have you tried omitting the typecast? I have printed several floats on my LCDs previously. And tried to just print a static value in your LCD to see if it is set up badly somehow in your control code?

Well I could, but this works fine on KSP1_2_2 using KSP_Serial_IO-0.18.3

Why would it have changed?

Link to comment
Share on other sites

Hello, good day


For me this WarningBoardCode works on my i2c-lcd-display 20x4
with KSPSerialIO_019_0.

greeting

	#include <Wire.h>    
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
	#define I2C_ADDR  0x27 
#define BACKLIGHT_PIN 3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
	//macro
#define details(name) (uint8_t*)&name,sizeof(name)
	//if no message received from KSP for more than 2s, go idle
#define IDLETIMER 2000
#define CONTROLREFRESH 25
	unsigned long deadtime, deadtimeOld, controlTime, controlTimeOld;
unsigned long now;
	boolean Connected = false;
	byte caution = 0, warning = 0, id;
	struct VesselData
{
    byte id;                //1
    float AP;               //2
    float PE;               //3
    float SemiMajorAxis;    //4
    float SemiMinorAxis;    //5
    float VVI;              //6
    float e;                //7
    float inc;              //8
    float G;                //9
    long TAp;               //10
    long TPe;               //11
    float TrueAnomaly;      //12
    float Density;          //13
    long period;            //14
    float RAlt;             //15
    float Alt;              //16
    float Vsurf;            //17
    float Lat;              //18
    float Lon;              //19
    float LiquidFuelTot;    //20
    float LiquidFuel;       //21
    float OxidizerTot;      //22
    float Oxidizer;         //23
    float EChargeTot;       //24
    float ECharge;          //25
    float MonoPropTot;      //26
    float MonoProp;         //27
    float IntakeAirTot;     //28
    float IntakeAir;        //29
    float SolidFuelTot;     //30
    float SolidFuel;        //31
    float XenonGasTot;      //32
    float XenonGas;         //33
    float LiquidFuelTotS;   //34
    float LiquidFuelS;      //35
    float OxidizerTotS;     //36
    float OxidizerS;        //37
    uint32_t MissionTime;   //38
    float deltaTime;        //39
    float VOrbit;           //40
    uint32_t MNTime;        //41
    float MNDeltaV;         //42
    float Pitch;            //43
    float Roll;             //44
    float Heading;          //45
    uint16_t ActionGroups;  //46  status bit order:SAS, RCS, Light, Gear, Brakes, Abort, Custom01 - 10
    byte SOINumber;         //47  SOI Number (decimal format: sun-planet-moon e.g. 130 = kerbin, 131 = mun)
    byte MaxOverHeat;       //48  Max part overheat (% percent)
    float MachNumber;       //49
    float IAS;              //50  Indicated Air Speed
    byte CurrentStage;      //51  Current stage number
    byte TotalStage;        //52  TotalNumber of stages
    float TargetDist;       //53  Distance to targeted vessel (m)
    float TargetV;          //54  Target vessel relative velocity
    byte NavballSASMode;    //55  Combined byte for navball target mode and SAS mode
                            // First four bits indicate AutoPilot mode:
                            // 0 SAS is off  //1 = Regular Stability Assist //2 = Prograde
                            // 3 = RetroGrade //4 = Normal //5 = Antinormal //6 = Radial In
                            // 7 = Radial Out //8 = Target //9 = Anti-Target //10 = Maneuver node
                            // Last 4 bits set navball mode. (0=ignore,1=ORBIT,2=SURFACE,3=TARGET)
};
	struct HandShakePacket
{
  byte id;
  byte M1;
  byte M2;
  byte M3;
};
	/*struct ControlPacket {
  byte id;
  byte MainControls;                  //SAS RCS Lights Gear Brakes Precision Abort Stage
  byte Mode;                          //0 = stage, 1 = docking, 2 = map
  unsigned int ControlGroup;          //control groups 1-10 in 2 bytes
  byte NavballSASMode;                //AutoPilot mode
  byte AdditionalControlByte1;
  int Pitch;                          //-1000 -> 1000
  int Roll;                           //-1000 -> 1000
  int Yaw;                            //-1000 -> 1000
  int TX;                             //-1000 -> 1000
  int TY;                             //-1000 -> 1000
  int TZ;                             //-1000 -> 1000
  int WheelSteer;                     //-1000 -> 1000
  int Throttle;                       //    0 -> 1000
  int WheelThrottle;                  //    0 -> 1000
};
*/
	LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
	int time = 0;
	HandShakePacket HPacket;
VesselData VData;
//ControlPacket CPacket;
	void setup() {
  Serial.begin(38400);
  Wire.begin(); 
  
  InitTxPackets();
	  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  
  lcd.home ();                
  lcd.begin(20, 4);
  
  lcd.clear();
  delay(200);
  lcd.setCursor(0,3);
  lcd.print("V:");
}
void loop()
{
  input();
  if (time==50)
  {
    lcd.setCursor(8,3);
    lcd.print(VData.Alt);
    lcd.print(" m/s   ");
    time=0;
  }
  time++;
}
Edited by funkheld
Link to comment
Share on other sites

Ok, this has been a long day of troubleshooting with just a few wins. Long story short, I am trying to connect my Arduino Bluetooth adapter to my phone and have it display some data from KSP. I know that I can't connect directly to pin 0 and 1 for this, so I included the <SoftwareSerial.h> Library. I defined pins 12 as Rx and 11 as Tx, then called it mySerial . I set mySerial.begin to 38400. I was able to connect to the adapter with a bluetooth terminal app, but I am receiving no data from mySerial.print(VData.AP);    Thoughts?

//pins for LEDs
#include <LiquidCrystal.h>
#include<SoftwareSerial.h>

SoftwareSerial portOne(10, 11);
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

int contr = 9;
int bright = 100;



//Action group statuses
#define AGSAS      0
#define AGRCS      1
#define AGLight    2
#define AGGear     3
#define AGBrakes   4
#define AGAbort    5
#define AGCustom01 6
#define AGCustom02 7
#define AGCustom03 8
#define AGCustom04 9
#define AGCustom05 10
#define AGCustom06 11
#define AGCustom07 12
#define AGCustom08 13
#define AGCustom09 14
#define AGCustom10 15

//macro
#define details(name) (uint8_t*)&name,sizeof(name)

//if no message received from KSP for more than 2s, go idle
#define IDLETIMER 2000
#define CONTROLREFRESH 25



unsigned long deadtime, deadtimeOld, controlTime, controlTimeOld;
unsigned long now;

boolean Connected = false;

byte caution = 0, warning = 0, id;

struct VesselData
{
    byte id;                //1
    float AP;               //2
    float PE;               //3
    float SemiMajorAxis;    //4
    float SemiMinorAxis;    //5
    float VVI;              //6
    float e;                //7
    float inc;              //8
    float G;                //9
    long TAp;               //10
    long TPe;               //11
    float TrueAnomaly;      //12
    float Density;          //13
    long period;            //14
    float RAlt;             //15
    float Alt;              //16
    float Vsurf;            //17
    float Lat;              //18
    float Lon;              //19
    float LiquidFuelTot;    //20
    float LiquidFuel;       //21
    float OxidizerTot;      //22
    float Oxidizer;         //23
    float EChargeTot;       //24
    float ECharge;          //25
    float MonoPropTot;      //26
    float MonoProp;         //27
    float IntakeAirTot;     //28
    float IntakeAir;        //29
    float SolidFuelTot;     //30
    float SolidFuel;        //31
    float XenonGasTot;      //32
    float XenonGas;         //33
    float LiquidFuelTotS;   //34
    float LiquidFuelS;      //35
    float OxidizerTotS;     //36
    float OxidizerS;        //37
    uint32_t MissionTime;   //38
    float deltaTime;        //39
    float VOrbit;           //40
    uint32_t MNTime;        //41
    float MNDeltaV;         //42
    float Pitch;            //43
    float Roll;             //44
    float Heading;          //45
    uint16_t ActionGroups;  //46 status bit order:SAS, RCS, Light, Gear, Brakes, Abort, Custom01 - 10
    byte SOINumber;         //47 SOI Number (decimal format: sun-planet-moon e.g. 130 = kerbin, 131 = mun)
    byte MaxOverHeat;       //48  Max part overheat (% percent)
    float MachNumber;       //49
    float IAS;              //50  Indicated Air Speed
    byte CurrentStage;      //51  Current stage number
    byte TotalStage;        //52  TotalNumber of stages
};

struct HandShakePacket
{
  byte id;
  byte M1;
  byte M2;
  byte M3;
};

struct ControlPacket {
  byte id;
  byte MainControls;                  //SAS RCS Lights Gear Brakes Precision Abort Stage
  byte Mode;                          //0 = stage, 1 = docking, 2 = map
  unsigned int ControlGroup;          //control groups 1-10 in 2 bytes
  byte AdditionalControlByte1;        //other stuff
  byte AdditionalControlByte2;
  int Pitch;                          //-1000 -> 1000
  int Roll;                           //-1000 -> 1000
  int Yaw;                            //-1000 -> 1000
  int TX;                             //-1000 -> 1000
  int TY;                             //-1000 -> 1000
  int TZ;                             //-1000 -> 1000
  int WheelSteer;                     //-1000 -> 1000
  int Throttle;                       //    0 -> 1000
  int WheelThrottle;                  //    0 -> 1000
};

HandShakePacket HPacket;
VesselData VData;
ControlPacket CPacket;

void setup() {
  Serial.begin(38400);
 portOne.begin(38400);
  InitTxPackets();


}

void loop()
{
  input();
  output();
}
  
  --------Utilities--------
  
  void Indicators() {


 
analogWrite(contr, bright);
lcd.begin(16, 2);

  // Print a message to the LCD.
  lcd.setCursor(0,0);
  lcd.print("APPO:");
  lcd.setCursor(5,0);
  lcd.print((long)VData.AP);
  lcd.setCursor(0,1);
  lcd.print("PERE:");
  lcd.setCursor(5,1);
  lcd.print((long)VData.PE);
  portOne.println((long)VData.AP);
 //portOne.println("hello");
 

}

void InitTxPackets() {
  HPacket.id = 0;  
  CPacket.id = 101;
}

 

Edited by Freakout242
added code
Link to comment
Share on other sites

1 hour ago, funkheld said:

SoftwareSerial portOne(10, 11);

you : 11/12 Pin

I changed it to 10 and 11 while troubleshooting. So that's not it. I wrote a simple sketch and used Serial.print("hello"); and portOne.println("goodbye"); and it works. Data will show over my com port and through the bluetooth. But when I place it on the sketch for ksp, I get nothing. 

Link to comment
Share on other sites

Have you tried without software serial? It is very slow and uses a lot of processor time. It might be slowing down everything so you don't have enough time to process the incoming packets.

I would suggest getting a Mega board which has 4 hardware COM ports.

Edited by zitronen
Link to comment
Share on other sites

You mean on a mega? You can't do it without software serial on a normal arduino.

On a mega you can use Serial.print(), Serial1.print(), and so on. It will be much faster because they are hardware serial ports. There are also other arduino or teensy boards with more than 1 serial ports. But this is assuming your problem is caused by software serial.

Link to comment
Share on other sites

On 6/12/2017 at 11:32 AM, zitronen said:

I would suggest getting a Mega board which has 4 hardware COM ports.

OK Guys....I'm Stuck.

Got myself a Mega board (love it) and I wrote the following sketch.

void setup() {
  // initialize both serial ports:
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  Serial.print("Test1 "); 
  Serial1.println("Test2 ");
  delay(1000);
}

I was able to receive data from both the Serial Monitor and my phone (which is connected to my bluetooth adapter....which is monitoring Serial1). So YAY!

The I placed this code for ksp into the "utilities" tab in order to get the Electric Charge total.

Serial1.begin(38400);
Serial1.println((long)VData.ECharge);

I get no response. Any ideas? I have also tried Serial1.println(VData.ECharge); as well.

EDIT: I added my lcd display with the above code. I can see data on the LCD screen, but still nothing over the Serial1 monitor.

Edited by Freakout242
more testing stuff
Link to comment
Share on other sites

have you tried putting

Serial1.begin(38400);

In void setup()

instead of utilities?

Also what is the baud rate for your bluetooth? Maybe it only works at 9600.

Edited by zitronen
Link to comment
Share on other sites

Just now, zitronen said:

have you tried putting


Serial1.begin(38400);

In void setup()

instead of utilities?

I did, but it still didn't work....HOWEVER!!!! I also placed 

Serial1.println((long)VData.ECharge);

Right below the loop statement...and it's WORKING!! WOO HOO!

Link to comment
Share on other sites

I would like to thank everyone here for helping me out with getting this Serial communication down. I now have it working and displaying data from KSP to my phone. I am making a prototype Android App that should show me all the data I need for a mission. Link to the screenshot is below. Again thanks everyone.

KSP_ISO Glass Cockpit Project

Link to comment
Share on other sites

13 hours ago, funkheld said:

Gui (Purebasic) with KOS and Seriell:

https://www.kerbalspaceprogram.de/index.php?attachment/12246-seriell-jpg/

Hello Freakout242.

How do your programs look like?

Can you please reset this here?

Thank you.
greeting

Not sure that you mean by "reset". Sorry. I am making an Android APP that will act as a "Glass Cockpit". At least thats the idea. I'll post more pics once I am done testing.

Link to comment
Share on other sites

On 19/06/2017 at 1:01 AM, Freakout242 said:

I did, but it still didn't work....HOWEVER!!!! I also placed 


Serial1.println((long)VData.ECharge);

Right below the loop statement...and it's WORKING!! WOO HOO!

OK cool, but without seeing your whole code it's hard to say if you put it in the right place.

Ideally you should put it in the outputs() function, which is run every 25ms by default if you want fast updates from axes controls:

controlTime = now - controlTimeOld; 
  if (controlTime > CONTROLREFRESH){
    controlTimeOld = now;
    controls();

    Serial1.println((long)VData.ECharge);
  }    

 

or in inputs() which is ran whenever a packet is received from KSP

if (KSPBoardReceiveData()){
    deadtimeOld = now;
    returnValue = id;
    switch(id) {
    case 0: //Handshake packet
      Handshake();
      break;
    case 1:
      Indicators();

      Serial1.println((long)VData.ECharge);

      break;
    }

 

Link to comment
Share on other sites

Welp, I'm having a little trouble getting this up and running.  I've got the included demo code on my Arduino, modified slightly to work with my TFT LCD and just try and display Fuel, Altitude, and whether we're connected or not.  I'm running the latest plugin version on KSP 1.2.2.

 

As soon as I load up a ship, I can see my Arduino flicker off and on, indicating something is trying to connect to it via COM port.  Then my little "Connected" indicator turns on.  Then just before the ship is finally done loading, the Arduino flickers off and on a second time, and this time it's no longer connected.

 

So the whole time while loading a ship, it resets the Arduino, connects, resets the Arduino a second time, and is no longer connected. 

 

Edit:  According to my logs, the Serial plugin is detecting my Arduino, and getting a handshake received.  So I guess the problem is on the Arduino side.  Maybe my TFT LCD is too slow.

Edited by moeburn
Link to comment
Share on other sites

@moeburn First of all: Windows 10 is only partially supported, but since you get a handshake I guess that is not your problem. If your TFT is to slow overall, you are pretty much out of luck. But if the problem is long loading times on the KSP side, there is a setting, handshakedelay in the init file in the plugin directory. Try setting it to 5000 or something like that.

Link to comment
Share on other sites

9 hours ago, Freshmeat said:

@moeburn First of all: Windows 10 is only partially supported, but since you get a handshake I guess that is not your problem. If your TFT is to slow overall, you are pretty much out of luck. But if the problem is long loading times on the KSP side, there is a setting, handshakedelay in the init file in the plugin directory. Try setting it to 5000 or something like that.

Thanks for your help, I got it working! :D

 

Turns out it was my TFT LCD code, was too slow to run alongside serial communications.  I confirmed this by removing all the TFT code and telling it just to turn on the built-in LED if we're connected, turn it off if disconnected, and that was working.  So next step was figuring out how to structure the TFT code alongside the serial code to get them to both work.  I ended up doing that successfully by sticking it inside the input() command, as such:

 

int input() {
  int returnValue = -1;
  now = millis();

  if (KSPBoardReceiveData()){
    deadtimeOld = now;
    returnValue = id;
    switch(id) {
    case 0: //Handshake packet
      Handshake();
      break;
    case 1:
      //Indicators();
      break;
    }

    //We got some data, turn the green led on
    digitalWrite(LED_BUILTIN, HIGH);
    Connected = true;
    tft.setCursor (0, 0);
    tft.setTextSize (2);
    tft.setTextColor(RED, BLACK);
    
    tft.print("Fuel: ");
    tft.println(VData.LiquidFuelTot);
    tft.print("Altitude: ");
    tft.println(VData.Alt);
    tft.print("CONNECTED");
    
  }
  else
  { //if no message received for a while, go idle
    deadtime = now - deadtimeOld; 
    if (deadtime > IDLETIMER)
    {
      deadtimeOld = now;
      Connected = false;
      digitalWrite(LED_BUILTIN, LOW);
      tft.print("NOPE");
    }    
  }

  return returnValue;
}

It's the tft.print lines that are my TFT code.  I've also made a few other changes in my many attemps to get this working, and I'm not sure which of them helped, so I'll list them here.

I changed "#define IDLETIMER 2000" to 20000, because my computer is a little old and takes 30+ seconds just to load a ship. Not sure if necessary.

In the config, I have "refresh" set to 1.0 (and you can see that in the linked video, it is only updating once per second) and HandshakeDelay is set to 7000.  Again, not sure if either is necessary.

I'm just typing all this out for future googlers if they have the same problem I did.  Now to see just how fast I can set that refresh value to, and just how much TFT drawing code I can do before it resets itself.  Not sure why "code takes too long" = "Entire arduino resets", but whatever.

Oh and I'm running Windows 8.1, not Windows 10, if that helps.

Link to comment
Share on other sites

Hi

Changine IDLETIMER is fine, it needs to be at least more than refresh time. Increasing handshake delay is also fine, the only downside is if you have lots of serial ports, the plugin can wait up to the delay for each port as it checks for a connection, so it can increase KSP load time by a lot.

I don't know which screen you are using, but you also might try some of the fast tft libraries.

Oh and ideally, you should put your code between

case 1:
// your code here
break;

you can also add something like

case 0: //Handshake packet
	Handshake();
	tft.print("connecting");
break;

if you want

Edited by zitronen
Link to comment
Share on other sites

Hello everyone! I've been trying to use this plugin with an Arduino UNO but it wouldn't work. I loaded @zitronen's "Warning LEDs" example with the same setup he used, except for an additional LED to signal whether or not rx_len is equal to 0 (it always is, thus the BoardReceive function won't read anything). I suspect this is because KSP won't transmit any data since the plugin, upon spawning on the launchpad, says  "No display found", and in the plugin sourcecode (game side) i've seen that in order for the Begin(); function to be called, a display has to be found. My question is, what do you mean by display, and what could i do to add one?

Here is the Arduino sourcecode (only the one i modified, the rest is identical to the example):

uint8_t rx_len;
uint8_t * address;
byte buffer[256]; //address for temporary storage and parsing buffer
uint8_t structSize;
uint8_t rx_array_inx;  //index for RX parsing buffer
uint8_t calc_CS;	   //calculated Chacksum

//This excrements contains stuff borrowed from EasyTransfer lib
boolean KSPBoardReceiveData() {

  //THIS IS THE ONLY PART I ADDED
  if(rx_len==0)
    digitalWrite(12, HIGH);
  else
    digitalWrite(12, LOW);
    
  if ((rx_len == 0)&&(Serial.available()>3)){
    while(Serial.read()!= 0xBE) {
      if (Serial.available() == 0)
        return false;  
    }
    if (Serial.read() == 0xEF){
      rx_len = Serial.read();   
      id = Serial.read(); 
      rx_array_inx = 1;

      switch(id) {
      case 0:
        structSize = sizeof(HPacket);   
        address = (byte*)&HPacket;     
        break;
      case 1:
        structSize = sizeof(VData);   
        address = (byte*)&VData;     
        break;
      }
    }

    //make sure the binary structs on both Arduinos are the same size.
    if(rx_len != structSize){
      rx_len = 0;
      return false;
    }   
  }

  if(rx_len != 0){
    while((Serial.available()) && (rx_array_inx <= rx_len)){
      buffer[rx_array_inx++] = Serial.read();
    }
    buffer[0] = id;

    if(rx_len == (rx_array_inx-1)){
      //seem to have got whole message
      //last uint8_t is CS
      calc_CS = rx_len;
      for (int i = 0; i<rx_len; i++){
        calc_CS^=buffer[i];
      } 

      if(calc_CS == buffer[rx_array_inx-1]){//CS good
        memcpy(address,buffer,structSize);
        rx_len = 0;
        rx_array_inx = 1;
        return true;
      }
      else{
        //failed checksum, need to clear this out anyway
        rx_len = 0;
        rx_array_inx = 1;
        return false;
      }
    }
  }

  return false;
}

P.S. This is the first time i use serial communication, so that "BoardReceive won't read" is almost a guess.

Thanks in advance for your answer!

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...