Jump to content

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


zitronen

Recommended Posts

1 hour ago, ajden said:

I've been trying to figure this out for several days with no success. Maybe it's a limitation of the plugin?

Just downloaded and installed the latest plugin, and have it working with both the game and the debug tool (which is WAY easier!). I can throw physical switches to affect the game, and this turns on/off LEDs. Great success.

 

Hi Adjen, my zero order guess would be that the display is quite resource intensive, so the Mega does not have the computing power to manage the information stream from KSP at the same time. I ran into the issue when I tried to do trigonometric formulae and square roots in each loop. Once the buffer overruns, the Mega no longer appears connected to KSP, and it disconnects. The smaller displays run very well with the LiquidCrystal_I2C library if they have an I2C backpack. I have two of these connected, however I only update every 200 ms to keep my buffer drained. I do not think that is needed for ordinary display stuff, but I process the numbers somewhat.

Edited by Freshmeat
Elaboration
Link to comment
Share on other sites

@ajden It seems like all you need to do is send serial packets to the screen so not sure why it's not working. Do you have the source code so you can see what is actually happening in "genie.WriteObject()"? If it really is taking too long you can try reducing the refresh rate in the plugin cfg file. You can also use another arduino to handle the display and just send simple serial data from your main arduino to it.

Link to comment
Share on other sites

Thanks guys! I tried increasing the handshake delay and refresh rate in the kspiodemo, but didnt change anything in the cfg file. (Didnt help). When i get home tomorrow i'll look into the genie library and see whats going on in there. Maybe that will shed some light. 

Link to comment
Share on other sites

11 hours ago, ajden said:

Thanks guys! I tried increasing the handshake delay and refresh rate in the kspiodemo, but didnt change anything in the cfg file. (Didnt help). When i get home tomorrow i'll look into the genie library and see whats going on in there. Maybe that will shed some light. 

 

You need to change the cfg file, that controls how fast data is sent to the arduino, and therefore how fast your display runs.

Link to comment
Share on other sites

Guys,

Increasing my control refresh to 1000 and "refresh" in the cfg to 1, so both were sending at 1Hz (screen counting up from 0). It seemed to work one time, but that may just have been because the screen was running off of memory and not actually getting commands from the arduino. 

 

Here is the code in my KSPDemo16 file--only setup() and loop() shown.


void setup() {
  Serial.begin(38400); // begin communication on the first
  Serial2.begin(9600);
  genie.Begin(Serial2);
  
  delay (3500);
  genie.WriteContrast(15); // Display ON (brightness 1-15)
  initLEDS();
  InitTxPackets();
  controlsInit();
  LEDSAllOff();
}

int i=0;

void loop()
{
  input();
  output();
}

and my output

void output() {
  now = millis();
  controlTime = now - controlTimeOld;
  if (controlTime > CONTROLREFRESH) {
    controlTimeOld = now;
    
    controls();
    genie.WriteObject(GENIE_OBJ_LED_DIGITS, 3, i);
    i++;
  }
}

 Finally, the genie.WriteObject code from that library

///////////////////////// WriteObject //////////////////////
//
// Write data to an object on the display
//
uint16_t Genie::WriteObject (uint16_t object, uint16_t index, uint16_t data) {
    uint16_t msb, lsb ;
    uint8_t checksum ;
    WaitForIdle();
    lsb = lowByte(data);
    msb = highByte(data);
    Error = ERROR_NONE;
    deviceSerial->write(GENIE_WRITE_OBJ) ;
    checksum  = GENIE_WRITE_OBJ ;
    deviceSerial->write(object) ;
    checksum ^= object ;
    deviceSerial->write(index) ;
    checksum ^= index ;
    deviceSerial->write(msb) ;
    checksum ^= msb;
    deviceSerial->write(lsb) ;
    checksum ^= lsb;
    deviceSerial->write(checksum) ;
    /*
    if (debugSerial) {
        *debugSerial << "WriteObject: " <<  ", ";
        *debugSerial << _HEX(object) << ", ";
        *debugSerial << _HEX(index) << ", ";
        *debugSerial << _HEX(msb) << ", ";
        *debugSerial << _HEX(lsb) << ", ";
        *debugSerial << _HEX(checksum) << endl;
        *debugSerial << "Freemem = " << freeRam()<< endl;
    }
    */
    PushLinkState(GENIE_LINK_WFAN);
}

 

If having the WHOLE files will help, let me know and I'll figure out a way to attach or send a PM.

Thanks!

 

Link to comment
Share on other sites

OOh, you need to put your code in the "input()" section, "output" is for switches and axis controls which are normally sent to KSP at 40Hz.

Also I wonder if

WaitForIdle();

in the writeobject function is what's causing the problems

Link to comment
Share on other sites

Holy crap. That fixed it. Even with refresh set to default values, placing the code between "indicators();" and "break;" (like I had read elsewhere in this thread) made it work. Not sure why it didn't work at first? I didn't have to mess with WaitForIdle(); I must have had made some bonehead mistake initially. Hopefully someone else can learn from my mistakes. Can't wait to post a pic of the finished product! Time to solder up 100 toggle switches. 

Thanks!

Link to comment
Share on other sites

6 hours ago, Freshmeat said:

Cool start, what are the plans.

The plans are three 128x64 glcd’s at the top (flight data, resources, status), some warning lights, RCS, SAS (with mode selection as well), lights/gear/brakes, a buzzer alarm, throttle, controls for both rotation and traslation via joystick potentiometer, action groups and, hopefully, some kind of launch autopilot (mechjeb style). All was to be done with a Mega, until i discovered the Due (exactly two hours ago :D). If that turns out to be still not enough i’ll try to use a RasPi 3, if it is possible. 

Now the box (50x40x15 cm) is done, i still have to do all the wiring and write the program. 

Link to comment
Share on other sites

@ljkjl Launch autopilot will be quite difficult to do in KSPSerialIO. The data packet does not contain the angles for prograde direction, and without that you cannot check that your rocket goes in the right direction. You could go pitch vs arctan(VVI/V_surf), but for trigonometry the Mega is severely lacking in computing speed. Good news is that the Mega is easily replaceable with a Due and some logic level shifters if you already have a Mega and want to delay the decision.

Link to comment
Share on other sites

@zitronen Most of the cases you are probably right about the launch manager.  However, in the lower layers of the atmosphere at least my rockets needs to be pretty close to prograde, or they will tumble due to drag on the payload. For aircraft, I was able to do altitude hold without overtaxing the Mega, and direction hold would be pretty straightforward to do.

Link to comment
Share on other sites

12 hours ago, zitronen said:

A basic aircraft autopilot that flies to way points is possible. For launch you don't really need prograde vector. A simple pitch vs altitude map and throttle based on time to AP could be enough for some rockets.

And for launch auto that’s exactly what I wanted to do. About the aircraft auto: that’s a great idea! I’m definitely going to add it.

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 weeks later...

FYI, I'm working on a websocket implementation (using websocket4net) to a raspberry PI running node.js and ws.  I've gotten it sending from KSP successfully.  Once I get a bit further, i'll clean up the code and share via a pull-request to the original author (the COM implementation is still an option, but I can't test that I didn't break it since I don't use COM).

Let me know if anyone is interested.  Also since there's a few folks active here, is it just me or is the SettingsNStuff class not getting it's config values properly?  I'm on a Mac and have just resorted to using the default-supplying version of the config.getValue<>() fn with hard-coded values that work for my setup.

Link to comment
Share on other sites

Did this just start happening? Never had that problem before. Although it could be something to do with the Mac version, not sure if the people working on the Mac port are still around...

Oh and I've been wanting to do a UDP based IO for a while, if you get something working we can figure out how to include it.

Edited by zitronen
Link to comment
Share on other sites

Unknown. i'm still on 1.2.2 at the moment.  i'll dig around other open source mods that are loading configs and see if there's something I can fix.

I have the websockets working now, pumping the ~224 byte packet from KSPSerialIO and i'm working on the RPi side parser in node.js (cuz i'm lazy). I didn't want to re-write the Arduino stuff to C++ as it seemed overly complex a data-path, but meh... right now my setup looks to be bottlenecked in the I2C OLED display channel actually performing refreshes (ha!) so i'll be back in hardware land again soon.

note: i have no command feedback from the RPi to KSP yet, my solution is 1-way right now, although the callbacks in websocket4net look pretty simple so I suspect it'd just be another few hours to get that working and adapted back to the KSPSerialIO code.  I'll probably spend another few hours on it this weekend and/or next week.  Glad to know you're around and open to pull-requests :)

Link to comment
Share on other sites

5 hours ago, zitronen said:

Although it could be something to do with the Mac version, not sure if the people working on the Mac port are still around...

Still around, but haven't looked at KSP plugins for a few months due to other life busyness and I think I'm a minor release out of date.

That said, I'm not having any trouble with SettingsNStuff on either Mac or Linux.

Link to comment
Share on other sites

public float Density; //13 air density (presumably kg/m^3, 1.225 at sea level)

I was curious how exactly is Atmospheric Density is handled by this plugin. Does the plugin transmit the actual numeric value of the Atmospheric density as a real unit (such as the listed kg/m^3), or as a percentage of a body's maximum value (percentage of kg/m^3 ASL)? I've been trying to read through the thread, and I honestly don't know. What I want to do is display Atmospheric Density as an output on an analog meter. Does the value sent by the plug in function as a percent of 1 atmosphere (and thus be an output compatible with an analog meter), or do I need to keep constants representing each body and perform a calculation on the Arduino end to get the Atmospheric density in a 0-255 scale?

Edited by richfiles
Link to comment
Share on other sites

Hello Again it's been a while but I'm a bit stuck again,

I have been able to get the game to output VData to a LCD using the LiquidCrystal.h library but when I try and display VData using 2 7 segment displays and 2 shift registers plus the ShiftDisplay.h library nothing get displayed on my 7 segment displays it's just blank. The 7 segment displays work independently of the code so it seems wired up fine and it can display a value 12345 in the demo code fine but once I try and display VData it doesn't do anything I was wondering If you guys had any idea or I was wondering how you guys displayed data to 7 segment displays.

Please and thank you, I attached the part of KSPIODemo16 that I changed below

 

//------------------------------------------------

//#include <LiquidCrystal.h>
//LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
#include <ShiftDisplay.h>
ShiftDisplay display(9,10,8,COMMON_CATHODE,5);
//------------------------------------------------

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

 //pinMode(51,INPUT_PULLUP);     //Stage transition
   // lcd.begin(16, 2);
   // lcd.print("fuel");

  initLEDS();
  InitTxPackets();
  //controlsInit();

  LEDSAllOff();  
}

void loop()
{
  input();
  output();
  //lcd.setCursor(0, 1);
  //lcd.print(VData.LiquidFuelTot);
    
//------------------------------------------------
 //display.show(12345,1000,ALIGN_LEFT);
 display.show(VData.LiquidFuelTot);
//------------------------------------------------
}

 

Link to comment
Share on other sites

LiquidFuelTot is a 32bit float in little-endianness.  my suggestion is to log to file or console on your arduino to ensure that you're getting the right value you want before sending it to the display.  I also note that you're not sending whatever the heck "1000, ALIGN_LEFT" is so ... not sure what's going on but there's some clear differences in your API calls between testing and data.  Probably something simple... like display.show() quietly choking on a float when you wanted to give it an integer?  you should probably have a look at doing rounding to convert the float to an int, or just truncate it (eww).

Also note: LiquidFuelTotS (per-stage) might be what you want instead for your display, but it's your display :)  

Link to comment
Share on other sites

On 10/24/2017 at 12:18 AM, richfiles said:

public float Density; //13 air density (presumably kg/m^3, 1.225 at sea level)

I was curious how exactly is Atmospheric Density is handled by this plugin. Does the plugin transmit the actual numeric value of the Atmospheric density as a real unit (such as the listed kg/m^3), or as a percentage of a body's maximum value (percentage of kg/m^3 ASL)? I've been trying to read through the thread, and I honestly don't know. What I want to do is display Atmospheric Density as an output on an analog meter. Does the value sent by the plug in function as a percent of 1 atmosphere (and thus be an output compatible with an analog meter), or do I need to keep constants representing each body and perform a calculation on the Arduino end to get the Atmospheric density in a 0-255 scale?

I am 90% sure it is the actual absolute density in kg/m^3. If you want a density ratio then you will need to know the sea level density of each planet, but if you just want a ratio to 1 (Kerbin) atmosphere you just need to divide it by 1.225.

On 10/24/2017 at 3:26 AM, EccentricTea said:

Hello Again it's been a while but I'm a bit stuck again,

I have been able to get the game to output VData to a LCD using the LiquidCrystal.h library but when I try and display VData using 2 7 segment displays and 2 shift registers plus the ShiftDisplay.h library nothing get displayed on my 7 segment displays it's just blank. The 7 segment displays work independently of the code so it seems wired up fine and it can display a value 12345 in the demo code fine but once I try and display VData it doesn't do anything I was wondering If you guys had any idea or I was wondering how you guys displayed data to 7 segment displays.

Please and thank you, I attached the part of KSPIODemo16 that I changed below

 


//------------------------------------------------

//#include <LiquidCrystal.h>
//LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
#include <ShiftDisplay.h>
ShiftDisplay display(9,10,8,COMMON_CATHODE,5);
//------------------------------------------------

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

 //pinMode(51,INPUT_PULLUP);     //Stage transition
   // lcd.begin(16, 2);
   // lcd.print("fuel");

  initLEDS();
  InitTxPackets();
  //controlsInit();

  LEDSAllOff();  
}

void loop()
{
  input();
  output();
  //lcd.setCursor(0, 1);
  //lcd.print(VData.LiquidFuelTot);
    
//------------------------------------------------
 //display.show(12345,1000,ALIGN_LEFT);
 display.show(VData.LiquidFuelTot);
//------------------------------------------------
}

 

Please make sure you put your own code in the "input()" function, don't put stuff in "loop()" since it need to run at a much faster rate where as "input()" is only ran when the arduino received a packet. Example:

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

	  //PUT YOUR CODE HERE
      display.show(....)

      break;
    }

 

Link to comment
Share on other sites

3 hours ago, zitronen said:

Please make sure you put your own code in the "input()" function, don't put stuff in "loop()" since it need to run at a much faster rate where as "input()" is only ran when the arduino received a packet. Example:


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

	  //PUT YOUR CODE HERE
      display.show(....)

      break;
    }

 

That mostly fixed it I'm reading the appropriate number now except the whole number blinks, could this be because of the refresh rate of the game or would it be something else?

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...