Jump to content

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


zitronen

Recommended Posts

Do a truckload of example sketches and try to change little things in them first. Try to guess the meaning of the words you are writing and how you can do something a little bit different. Learn how to use a switch. Then learn how to use a switch to assign a value. Learn how to use a potmeter, and how to do simple math in Arduino C so you can assign that value. Then try to change something simple in zitronens code. It is quite a road if you start from scratch, but a highly rewarding summer could await you.

I don't know the contents of the starter kit, but a breadboard, switches, a couple of LEDs and 1k resistors, and a slide or rotary potmeter goes an extremely long way.

Programming is all about breaking complex bits into simple bits, and then solve them one by one. If you read zitronens code, it is rather user friendly in form documentation on how to change simple things. And if you can ask a specific question, some of the gurus around here are very friendly and helpful.

Coding comes natural to some people, and to some other people, it comes extremely opposite of natural. I have an extremely hard time comprehending any kind of code. Especially trying to set it up and build anything.

But even worse, i really wanna learn it, but just can't seem to grasp it.

Link to comment
Share on other sites

Good news is that anyone can learn it. Bad news is that the main ingredient is a ton of work. I tried to learn to play music but never got the hang of it, because I could not be sufficiently interested to train every day. My physical fitness is poor because I do not work out (thank God I have to stand and walk while working, or I would be heavily overweight). You need to make up your mind whether you feel comfortable spending 5-10 hours a week for the next several months learning the mindset, or cut your losses right now.

Link to comment
Share on other sites

Hello everybody! After lurking quite a lot in this thread i felt the need for creating an account and joining this thread.

I am in the works of building a control panel, I am still waiting for parts and using my time waiting to test basic functions. I have spent a few hours fiddling with a 7 segment display, 8 digits with the MAX7219 driver. I finaly got it to do what i want. However, I am a true beginner at code, and I wanted to have your opinion of my coding.

After using code to get the display started, via Ledcontrol.h, I basically put this in the void loop:

void loop(){  
input();
output();
if (VData.RAlt < 9999) //If radar altitude is below 9999 meters
{printNumLED(0, (long)(VData.RAlt), ' ',0); //print radar altitude to display 0
}
else //If above, print H16H (high)
{lc.setChar(0,3,'H',false);
lc.setChar(0,2,'1',false);
lc.setChar(0,1,'6',false);
lc.setChar(0,0,'H',false);
}

It works perfectly, but somewhere in this thread i remember someone saying that putting it in the void loop is not ideal.

Edit:

A problem I do have is when I set my display to:

printNumLED(0, (long)(VData.AP/1000),'A',0);

I of course get the AP in KM, and with a "A" on the first number of the display. I do not want this A, but all I have tried have resulted in either characters in this location, or just a blank. If my ap is 15001200 km, the display shows 5001200, because of this blank space.

Edited by I_KILL_HORSES
Link to comment
Share on other sites

Hello everybody! After lurking quite a lot in this thread i felt the need for creating an account and joining this thread.

I am in the works of building a control panel, I am still waiting for parts and using my time waiting to test basic functions. I have spent a few hours fiddling with a 7 segment display, 8 digits with the MAX7219 driver. I finaly got it to do what i want. However, I am a true beginner at code, and I wanted to have your opinion of my coding.

After using code to get the display started, via Ledcontrol.h, I basically put this in the void loop:

void loop(){  
input();
output();
if (VData.RAlt < 9999) //If radar altitude is below 9999 meters
{printNumLED(0, (long)(VData.RAlt), ' ',0); //print radar altitude to display 0
}
else //If above, print H16H (high)
{lc.setChar(0,3,'H',false);
lc.setChar(0,2,'1',false);
lc.setChar(0,1,'6',false);
lc.setChar(0,0,'H',false);
}

It works perfectly, but somewhere in this thread i remember someone saying that putting it in the void loop is not ideal.

Edit:

A problem I do have is when I set my display to:

printNumLED(0, (long)(VData.AP/1000),'A',0);

I of course get the AP in KM, and with a "A" on the first number of the display. I do not want this A, but all I have tried have resulted in either characters in this location, or just a blank. If my ap is 15001200 km, the display shows 5001200, because of this blank space.

Hi there I_Kill_Horses,

Welcome to the forum.

You are quite right about the void loop.

You can find my working solution in the body of this thread somewhere or in the opening post of the thread linked in my signature below.

My project is in bits at the moment, so I can't test this, but maybe try this to fix your blank problem: printNumLED(0, (long)(VData.AP/1000),0) if I'm wrong one of the skilled folks should be along to correct it

Also, I think I might steal er.... borrow your idea re: the radar height cutoff;)

Edited by T.A.P.O.R.
for clarity
Link to comment
Share on other sites

Hi there I_Kill_Horses,

Welcome to the forum.

You are quite right about the void loop.

You can find my working solution in the body of this thread somewhere or in the opening post of the thread linked in my signature below.

My project is in bits at the moment, so I can't test this, but maybe try this to fix your blank problem: printNumLED(0, (long)(VData.AP/1000),0) if I'm wrong one of the skilled folks should be along to correct it

Also, I think I might steal er.... borrow your idea re: the radar height cutoff;)

Thanks a lot!Funny thing, I already found your thread and put all my display code in the utilities. :)

I also tried ommiting the 'A', but then the display think that the printNumLED(0, (long)(VData.AP/1000),0) refers to '0', and prints a "0" at the first sign. Like this

AP=10km, - represents a blank screen

0-----10.

This problem frustrates me, as I see no reason to waste a digit for A, P or whatever, I can just paint that on my case.

You, and everybody else, are of course welcome to copy my code!

Link to comment
Share on other sites

Thanks a lot!Funny thing, I already found your thread and put all my display code in the utilities. :)

I also tried ommiting the 'A', but then the display think that the printNumLED(0, (long)(VData.AP/1000),0) refers to '0', and prints a "0" at the first sign. Like this

AP=10km, - represents a blank screen

0-----10.

This problem frustrates me, as I see no reason to waste a digit for A, P or whatever, I can just paint that on my case.

You, and everybody else, are of course welcome to copy my code!

Hmmm...

How about this?

printNumLED(0, (long)(VData.AP/1000),0,0)

or this

printNumLED(0, (long)(VData.AP/1000))

Wish I could test it for you, but that's a couple of weeks away (lousy exams).

Link to comment
Share on other sites

Obviously Amelia wrote the function to suit her needs, she probably wanted to always display something in the first digit. You can try commenting out the line 85:

lc.setChar(_dispnum,7,c,false);

to

//lc.setChar(_dispnum,7,c,false);

Link to comment
Share on other sites

Neither of these methods work. Ommiting line 85 will result in first digit being blank, as will printNumLED(0, (long)(VData.AP/1000)). AndprintNumLED(0, (long)(VData.AP/1000),0,0) results in a static 0 printed in the first digit.

However, there is a lot of lines of code refering to "char c" and like in the original code. In line 29 for example:

void printNumLED(int _dispnum, double _value, char c)

I will try tomorrow to edit this code, but I doubt I will be able to. This author, Amelia, does she have an account for this forum?

Thank you for your help!

Link to comment
Share on other sites

Neither of these methods work. Ommiting line 85 will result in first digit being blank, as will printNumLED(0, (long)(VData.AP/1000)). AndprintNumLED(0, (long)(VData.AP/1000),0,0) results in a static 0 printed in the first digit.

However, there is a lot of lines of code refering to "char c" and like in the original code. In line 29 for example:

void printNumLED(int _dispnum, double _value, char c)

I will try tomorrow to edit this code, but I doubt I will be able to. This author, Amelia, does she have an account for this forum?

Thank you for your help!

yep, had responded to this thread and is super helpful via pm :)

Link to comment
Share on other sites

I have recieved an answer from Amelia, containing this code:

"Here is the new function:"

[COLOR=#333333][I]//-------------------------------------------------------------------------------------//[/I][/COLOR]
[COLOR=#333333][I]void printNumLEDnew(int _dispnum, long _value, char c, int _decplace, int _base)[/I][/COLOR]
[COLOR=#333333][I]{[/I][/COLOR]
[COLOR=#333333][I]//char c is now made redundant, only kept in the header for a consistent input field.[/I][/COLOR]

[COLOR=#333333][I]//prints number to LEDmatrix chip.[/I][/COLOR]
[COLOR=#333333][I]//for (int ch=0;ch<8;ch++) {[/I][/COLOR]
[COLOR=#333333][I]// numdisp.setChar(loopval,ch,'-',false);//false flag is for decpnt control.[/I][/COLOR]
[COLOR=#333333][I]//}//end for[/I][/COLOR]
[COLOR=#333333][I]if (numdisp.getDeviceCount()<=_dispnum) return;//cannot enter info on displays that do not exist.[/I][/COLOR]

[COLOR=#333333][I]boolean IsNeg=false;[/I][/COLOR]
[COLOR=#333333][I]if (_value<0) {[/I][/COLOR]
[COLOR=#333333][I]IsNeg=true;[/I][/COLOR]
[COLOR=#333333][I]_value=-_value;//make positive num[/I][/COLOR]
[COLOR=#333333][I]}[/I][/COLOR]
[COLOR=#333333][I]boolean decpoint;[/I][/COLOR]
[COLOR=#333333][I]int placeval=0;int tempval;[/I][/COLOR]
[COLOR=#333333][I]//digitalWrite(LED_CSstart+_dispnum,LOW);//activate !CS[/I][/COLOR]
[COLOR=#333333][I]//numdisp.SPI_CS=LED_CSstart+_dispnum;//change CS for current display[/I][/COLOR]
[COLOR=#333333][I]do {[/I][/COLOR]
[COLOR=#333333][I]tempval=_value%_base; _value=_value/_base;[/I][/COLOR]
[COLOR=#333333][I]decpoint=false; if ((_decplace)==placeval) decpoint=true;[/I][/COLOR]
[COLOR=#333333][I]numdisp.setDigit(_dispnum,placeval,tempval,decpoint);[/I][/COLOR]
[COLOR=#333333][I]//placeval++;[/I][/COLOR]
[COLOR=#333333][I]} while ((placeval++<7 && _value>0) || (placeval<=_decplace));[/I][/COLOR]
[COLOR=#333333][I]if (IsNeg) {[/I][/COLOR]
[COLOR=#333333][I]numdisp.setChar(_dispnum,placeval++,'-',false);[/I][/COLOR]
[COLOR=#333333][I]}[/I][/COLOR]
[COLOR=#333333][I]for (placeval=placeval;placeval<8;placeval++) {[/I][/COLOR]
[COLOR=#333333][I]numdisp.setChar(_dispnum,placeval,' ',false);[/I][/COLOR]
[COLOR=#333333][I]}[/I][/COLOR]
[COLOR=#333333][I]//numdisp.setChar(_dispnum,7,c,false);[/I][/COLOR]
[COLOR=#333333][I]//digitalWrite(36+_dispnum,HIGH);[/I][/COLOR]
[COLOR=#333333][I]}[/I][/COLOR]

[COLOR=#333333][I]//-------------------------------------------------------------------------------------//[/I][/COLOR]

"I've given it a different name so that you can use the old and the new in the same program; just throw that function in the 'LedControlFunctions' tab :)"

I have tried this, and it throws up a few errors: I do not know how to fix this, but I think that someone in this thread might be able to help me:

LedControlFunctions.ino: In function 'void printNumLEDnew(int, long int, char, int, int)':

LedControlFunctions.ino:175:5: error: 'numdisp' was not declared in this scope

LedControlFunctions.ino:189:1: error: 'numdisp' was not declared in this scope

LedControlFunctions.ino:193:1: error: 'numdisp' was not declared in this scope

LedControlFunctions.ino:196:1: error: 'numdisp' was not declared in this scope

Error compiling.

I have of course asked Amelia for help, but due to time difference our correspondence is pretty slow. Anyone here who can help me with how and where to declare 'numdisp'?

Link to comment
Share on other sites

Update 0.17.2

Changed:

Added SOI output. So I changed my mind again :sticktongue:, I'm now sending SOI name as a single byte.

The way it works right now is decimal format: sun-planet-moon

"sun" = 100

"moho"= 110

"eve" = 120

"gilly" = 121

"kerbin" = 130

"mun" = 131

"minmus" = 132

"duna" = 140

"ike" = 141

"dres" = 150

"jool" = 160

"laythe" = 161

"vall" = 162

"tylo" = 163

"bop" = 164

"pol" = 165

"eeloo" = 170

"unknown" = 0

I will leave how to write the arduino code as an exercise to the reader :). A simple switch-case statement should do.

Please let me know if you find any problems.

Plugin:

https://sites.google.com/site/zitronfiles/KSPSerialIO_017_2.zip

Arduino Code:

https://sites.google.com/site/zitronfiles/KSPIODemo11.zip

Link to comment
Share on other sites

You need to post more of your code for people to help you, like how are you using the function?

I will just copy all of my code, I do not know how much I need to post for someone to troubleshoot it for me.

[CODE\

#include <LedControl.h> //to be made redundant - BIG power drain. 8x7 seg display with the maxim chip.
#define LEDClkPin 6
#define LEDChipSel 5
#define LEDDatain 7
//these pins were set up for an Arduino Uno, adjust as appropriate.

LedControl lc=LedControl(LEDDatain,LEDClkPin,LEDChipSel,12);//1==num of 8x8pixel arrays in line. can be up to 8.












//pins for LEDs
#define GLED 5
#define YLED 6
#define RLED 7
#define SASLED 11
#define RCSLED 12
#define CG1LED 13


//pins for input
#define SASPIN 8
#define RCSPIN 9
#define CG1PIN 10
#define THROTTLEPIN 0


#define THROTTLEDB 4 //Throttle axis deadband


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


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


//warnings
#define GWARN 9 //9G Warning
#define GCAUTION 5 //5G Caution
#define FUELCAUTION 10.0 //10% Fuel Caution
#define FUELWARN 5.0 //5% Fuel warning


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
};


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);


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


LEDSAllOff();

for (int loopval=0;loopval < lc.getDeviceCount();loopval++) {
//getDeviceCount will get the number of dev's attached
//so I don't have to re-write all the vars as the code changes :D
//digitalWrite(36+loopval,LOW);//activate !CS
//lc.SPI_CS=LED_CSstart+loopval;//change CS for current display
lc.shutdown(loopval,false);
lc.setIntensity(loopval,3);//val up to 15, zero is invalid (use shutdown method)
lc.clearDisplay(loopval);//likely not needed for init, but is nicer coding.
}
// Initialize the MAX7219 device
/* lc.shutdown(0,false); // Enable display
lc.setIntensity(0,5); // Set brightness level (0 is min, 15 is max)
lc.clearDisplay(0); // Clear display register// */

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



}




void Handshake(){
digitalWrite(GLED,HIGH);


HPacket.id = 0;
HPacket.M1 = 3;
HPacket.M2 = 1;
HPacket.M3 = 4;


KSPBoardSendData(details(HPacket));
//Serial.println(F("KSP;0"));
//delay(1000);
}








// Handshake


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(GLED,HIGH);
Connected = true;
}
else
{ //if no message received for a while, go idle
deadtime = now - deadtimeOld;
if (deadtime > IDLETIMER)
{
deadtimeOld = now;
Connected = false;
LEDSAllOff();
}
}


return returnValue;
}


byte ControlStatus(byte n)
{
return ((VData.ActionGroups >> n) & 1) == 1;
}


int input() {  int returnValue = -1;


/*This is current draw for one 8 digit 7 segment display, printing A88888.88
15= 147
14= 140
13= 132
12= 124
11= 116
10= 105
9= 99
8= 89
7= 81
6= 72
5= 62
4= 52
3= 42
2= 32
1= 22 All in mA */


//-------------------------------------------------------------------------------------//
void blankLEDscreens()
{
for (int loopval=0;loopval < lc.getDeviceCount();loopval++) {
//getDeviceCount will get the number of dev's attached
//so I don't have to re-write all the vars as the code changes :D
//digitalWrite(36+loopval,LOW);//activate !CS
//lc.SPI_CS=LED_CSstart+loopval;//change CS for current display
lc.shutdown(loopval,false);
lc.setIntensity(loopval,1);//val up to 15, zero is invalid (use shutdown method)
lc.clearDisplay(loopval);//likely not needed for init, but is nicer coding.
//digitalWrite(36+loopval,HIGH);//close !CS


}//end for
for (int loopval=0;loopval < lc.getDeviceCount();loopval++) {
//lc.SPI_CS=LED_CSstart+loopval;//change CS for current display
for (int ch=0;ch<8;ch++) {
//digitalWrite(36+loopval,LOW);//activate !CS
lc.setChar(loopval,ch,'-',false);//false flag is for decpnt control.
//digitalWrite(36+loopval,HIGH);
}//end for
}//end for loopval


}
//-------------------------------------------------------------------------------------//
//-------------------------------------------------------------------------------------//
void printNumLED(int _dispnum, double _value, char c)
{
//needs to automatically calc where the decimal place goes.
if (isEqual(_value-((long)_value),0)) printNumLED(_dispnum, (long)_value, c, -1, DEC);
else if (isEqual(_value*10-((long)(_value*10)),0)) printNumLED(_dispnum, (long)(_value*10), c, 1, DEC);
else if (isEqual(_value*100-((long)(_value*100)),0)) printNumLED(_dispnum, (long)(_value*100), c, 2, DEC);
else if (isEqual(_value*1000-((long)(_value*1000)),0)) printNumLED(_dispnum, (long)(_value*1000), c, 3, DEC);
else if (isEqual(_value*10000-((long)(_value*10000)),0)) printNumLED(_dispnum, (long)(_value*10000), c, 4, DEC);


//printNumLED(_dispnum, _value, ' ', 0, 10);
}
//----------------//
void printNumLED(int _dispnum, long _value)
{
printNumLED(_dispnum, _value, ' ', -1, DEC);
}
//----------------//


void printNumLED(int _dispnum, long _value, char c)
{
printNumLED(_dispnum, _value, c, -1, DEC);
}
//----------------//
void printNumLED(int _dispnum, long _value, char c, int _decplace)
{
printNumLED(_dispnum, _value, c, _decplace, DEC);
}
//----------------//
void printNumLED(int _dispnum, long _value, char c, int _decplace, int _base)
{
//prints number to LEDmatrix chip.
//for (int ch=0;ch<8;ch++) {
// lc.setChar(loopval,ch,'-',false);//false flag is for decpnt control.
//}//end for
boolean IsNeg=false;
if (_value<0) {
IsNeg=true;
_value=-_value;//make positive num
}
boolean decpoint;
int placeval=0;int tempval;
//digitalWrite(LED_CSstart+_dispnum,LOW);//activate !CS
//lc.SPI_CS=LED_CSstart+_dispnum;//change CS for current display
do {
tempval=_value%_base; _value=_value/_base;
decpoint=false; if ((_decplace)==placeval) decpoint=true;
lc.setDigit(_dispnum,placeval,tempval,decpoint);
//placeval++;
} while ((placeval++<6 && _value>0) || (placeval<=_decplace));
if (IsNeg) {
lc.setChar(_dispnum,placeval++,'-',false);
}
for (placeval=placeval;placeval<7;placeval++) {
lc.setChar(_dispnum,placeval,' ',false);
}
// lc.setChar(_dispnum,7,c,false);
//digitalWrite(36+_dispnum,HIGH);
}


//-------------------------------------------------------------------------------------//
void printLeadingZeroFloatNumLED(int _dispnum, double _value, float _digits, char c, int _base)
{

int _lowerplaceval=(int(_digits*10)%10);
int _newdigits=int(_digits)+_lowerplaceval;

long _newvalue=(long)(_value*exponent(10,_lowerplaceval));

//printNumLED(_dispnum, _newvalue, c, _lowerplaceval, _base);
printLeadingZeroNumLED(_dispnum, _newvalue, _newdigits, c, _lowerplaceval, _base);
}


//----------------//
void printLeadingZeroNumLED(int _dispnum, long _value, int _digits)
{
printLeadingZeroNumLED(_dispnum,_value,_digits,' ',-1,DEC);
}
//----------------//
void printLeadingZeroNumLED(int _dispnum, long _value, int _digits, char c)
{
printLeadingZeroNumLED(_dispnum,_value,_digits,c,-1,DEC);
}
//----------------//
void printLeadingZeroNumLED(int _dispnum, long _value, int _digits, char c, int _decplace)
{
printLeadingZeroNumLED(_dispnum,_value,_digits,c,_decplace,DEC);
}
//----------------//


void printLeadingZeroNumLED(int _dispnum, long _value, int _digits, char c, int _decplace, int _base)
{
//prints number to LEDmatrix chip.
//for (int ch=0;ch<8;ch++) {
// lc.setChar(loopval,ch,'-',false);//false flag is for decpnt control.
//}//end for
boolean IsNeg=false;
if (_value<0) {
IsNeg=true;
_value=-_value;//make positive num
if (_digits>6) _digits=6;//forces the negative sign to be shown, even if number is cut short.
}
boolean decpoint;
int placeval=0;int tempval;
do {
tempval=_value%_base; _value=_value/_base;
decpoint=false; if ((_decplace)==placeval) decpoint=true;
lc.setDigit(_dispnum,placeval,tempval,decpoint);
//placeval++;
} while ((placeval++<6 && _value>0) || (placeval<_digits));
if (IsNeg) {
lc.setChar(_dispnum,placeval++,'-',false);
}
for (placeval=placeval;placeval<7;placeval++) {
lc.setChar(_dispnum,placeval,' ',false);
}
lc.setChar(_dispnum,7,c,false);

}


//-------------------------------------------------------------------------------------//
[COLOR=#ff0000]void printNumLEDnew(int _dispnum, long _value, char c, int _decplace, int _base)[/COLOR]
[COLOR=#ff0000]{[/COLOR]
[COLOR=#ff0000]//char c is now made redundant, only kept in the header for a consistent input field.[/COLOR]
[COLOR=#ff0000]
[/COLOR]
[COLOR=#ff0000]//prints number to LEDmatrix chip.[/COLOR]
[COLOR=#ff0000]//for (int ch=0;ch<8;ch++) {[/COLOR]
[COLOR=#ff0000]// numdisp.setChar(loopval,ch,'-',false);//false flag is for decpnt control.[/COLOR]
[COLOR=#ff0000]//}//end for[/COLOR]
[B][COLOR=#ff0000]if (numdisp.getDeviceCount()<=_dispnum) return;//cannot enter info on displays that do not exist.[/COLOR][/B]
[COLOR=#ff0000]
[/COLOR]
[COLOR=#ff0000]boolean IsNeg=false;[/COLOR]
[COLOR=#ff0000]if (_value<0) {[/COLOR]
[COLOR=#ff0000]IsNeg=true;[/COLOR]
[COLOR=#ff0000]_value=-_value;//make positive num[/COLOR]
[COLOR=#ff0000]}[/COLOR]
[COLOR=#ff0000]boolean decpoint;[/COLOR]
[COLOR=#ff0000]int placeval=0;int tempval;[/COLOR]
[COLOR=#ff0000]//digitalWrite(LED_CSstart+_dispnum,LOW);//activate !CS[/COLOR]
[COLOR=#ff0000]//numdisp.SPI_CS=LED_CSstart+_dispnum;//change CS for current display[/COLOR]
[COLOR=#ff0000]do {[/COLOR]
[COLOR=#ff0000]tempval=_value%_base; _value=_value/_base;[/COLOR]
[COLOR=#ff0000]decpoint=false; if ((_decplace)==placeval) decpoint=true;[/COLOR]
[B][COLOR=#ff0000]numdisp.setDigit(_dispnum,placeval,tempval,decpoint);[/COLOR][/B]
[COLOR=#ff0000]//placeval++;[/COLOR]
[COLOR=#ff0000]} while ((placeval++<7 && _value>0) || (placeval<=_decplace));[/COLOR]
[COLOR=#ff0000]if (IsNeg) {[/COLOR]
[B][COLOR=#ff0000]numdisp.setChar(_dispnum,placeval++,'-',false);[/COLOR][/B]
[COLOR=#ff0000]}[/COLOR]
[COLOR=#ff0000]for (placeval=placeval;placeval<8;placeval++) {[/COLOR]
[B][COLOR=#ff0000]numdisp.setChar(_dispnum,placeval,' ',false);[/COLOR][/B]
[COLOR=#ff0000]}[/COLOR]
[COLOR=#ff0000]//numdisp.setChar(_dispnum,7,c,false);[/COLOR]
[COLOR=#ff0000]//digitalWrite(36+_dispnum,HIGH);[/COLOR]
[COLOR=#ff0000]}[/COLOR]




//-------------------------------------------------------------------------------------//
boolean isEqual(double _var, double _valtotest)
{
return isEqual( _var, _valtotest, 0.001);//default tolerance is real low.
}


//----------------//
boolean isEqual(double _var, double _valtotest, double _tolerance)
{
//tests if two values (e.g "if (x==_number)", but allowing floating point nums;
//which have a habit of rounding errors.

//(fabs(result - expectedResult) < 0.0001)
if (fabs(_var - _valtotest) < _tolerance) return true;
else return false;
}


//-------------------------------------------------------------------------------------//
unsigned long exponent(unsigned long _base, int _exp)
{
//raises _base to the power of _exp
//i.e. _base ^ _exp
//example call: bignum=exponent(2,8); //bignum=2^8=256

if (_exp==0) return(1);//anything to the power of 0 = 1.
if (_base<1) return(0);//only valid base num's please! (note: 0^x (x>0) is always zero anyway.)
if (_exp<0) return(0);//no negative exponents! we call that 'division'. take that .... elsewhere!

unsigned long result=1;

for (int indx=1;indx<=_exp;indx++)
{
//exponent is multiple multiples... i.e. 10^5 == 10*10*10*10*10
//so loop that ....!
if ((result*_base) < result) {
result=0;
break;//return 0 if overflow.
}
result=result*_base;

}//end for
return(result);
//keep in mind, that if result > ~4x10^9 that result will overflow and give a garbage result.
}


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


As I said before, this throws up these

LedControlFunctions.ino: In function 'void printNumLEDnew(int, long int, char, int, int)':

LedControlFunctions.ino:175:5: error: 'numdisp' was not declared in this scope

LedControlFunctions.ino:189:1: error: 'numdisp' was not declared in this scope

LedControlFunctions.ino:193:1: error: 'numdisp' was not declared in this scope

LedControlFunctions.ino:196:1: error: 'numdisp' was not declared in this scope

Error compiling


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 .... contains stuff borrowed from EasyTransfer lib
boolean KSPBoardReceiveData() {
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;
}


void KSPBoardSendData(uint8_t * address, uint8_t len){
uint8_t CS = len;
Serial.write(0xBE);
Serial.write(0xEF);
Serial.write(len);

for(int i = 0; i<len; i++){
CS^=*(address+i);
Serial.write(*(address+i));
}

Serial.write(CS);
}




uint8_t rx_len;uint8_t * address;


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


void controls() {
if (Connected) {


if (digitalRead(SASPIN)) //--------- This is how you do main controls
{MainControls(SAS, HIGH);}
else
{MainControls(SAS, LOW);}


if (digitalRead(RCSPIN))
MainControls(RCS, HIGH);
else
MainControls(RCS, LOW);


if (digitalRead(CG1PIN)) //--------- This is how you do control groups
ControlGroups(1, HIGH);
else
ControlGroups(1, LOW);



//This is an example of reading analog inputs to an axis, with deadband and limits
//AVAKTIVERAD CPacket.Throttle = constrain(map(analogRead(THROTTLEPIN),THROTTLEDB,1024-THROTTLEDB,0,1000),0, 1000);


KSPBoardSendData(details(CPacket));
}
}


void controlsInit() {
pinMode(SASPIN, INPUT_PULLUP);
pinMode(RCSPIN, INPUT_PULLUP);
pinMode(CG1PIN, INPUT_PULLUP);
}


void MainControls(byte n, boolean s) {
if (s)
CPacket.MainControls |= (1 << n); // forces nth bit of x to be 1. all other bits left alone.
else
CPacket.MainControls &= ~(1 << n); // forces nth bit of x to be 0. all other bits left alone.
}


void ControlGroups(byte n, boolean s) {
if (s)
CPacket.ControlGroup |= (1 << n); // forces nth bit of x to be 1. all other bits left alone.
else
CPacket.ControlGroup &= ~(1 << n); // forces nth bit of x to be 0. all other bits left alone.

}


void output() {  now = millis();


CLK=6 GREEN
DIN=7 ORANGE1 */
//RADAR ALT------------------------------------------------------------------------------------


if (VData.RAlt < 100) {
printNumLED(0, (long)(VData.RAlt*10), ' ',1); //Below 100m, print with 1 decimal.
}
else if (VData.RAlt <10000){
printNumLED(0, (long)(VData.RAlt), ' ',0); //Above 100m, print without decimals.
}
else if (VData.RAlt > 10000) { //Above 10000m, print H16H (high)
lc.setChar(0,3,'H',false);
lc.setChar(0,2,'1',false);
lc.setChar(0,1,'6',false);
lc.setChar(0,0,'H',false);}


//RADAR ALT----------------------------------------------------------------------------------------------
//FUEL PERCENTAGE ---------------------------------------------------------------------------------
/*
if (VData.LiquidFuel/VData.LiquidFuelTot==1) //When stage is full, print "FULL"
{
lc.setChar(0,3,'F',false);
lc.setRow(0,2,62); //62= Capital U
lc.setChar(0,1,'L',false);
lc.setChar(0,0,'L',false);
}
else if(VData.LiquidFuel/VData.LiquidFuelTot<1)
{ //When stage is not full, print stage fuel %
printNumLED(0, (long)(VData.LiquidFuel/VData.LiquidFuelTot*10000),' ', 2);
}
else if(VData.LiquidFuel<=0){ //When stage is 0 or below (SIC) print "null"
lc.setRow(0,3,0x15); // "n"
lc.setRow(0,2,0x1c); // "u"
lc.setChar(0,1,'1',false); // "l"
lc.setChar(0,0,'1',false);} // "l"
//the null print is because when you drop the last tank before it is empty, wierd negative
//numbers can appear appear. With this, the display will show null instead of these numbers.
*/
//FUEL PERCENTAGE--------------------------------------------------------------------------------------------


//printNumLED(0, (long)(VData.Alt/1000*1000),'0',2);//will display apoapsis, with the decimal point separating km and m.


caution = 0;
warning = 0;


caution += VData.G > GCAUTION;
warning += VData.G > GWARN;
caution += VData.LiquidFuelS/VData.LiquidFuelTotS*100 < FUELCAUTION;
warning += VData.LiquidFuelS/VData.LiquidFuelTotS*100 < FUELWARN;


if (caution != 0)
digitalWrite(YLED,HIGH);
else
digitalWrite(YLED,LOW);


if (warning != 0)
digitalWrite(RLED,HIGH);
else
digitalWrite(RLED,LOW);

digitalWrite(SASLED,ControlStatus(AGSAS));
digitalWrite(RCSLED,ControlStatus(AGRCS));
digitalWrite(CG1LED,ControlStatus(AGCustom01));
}


void initLEDS() {
pinMode(GLED,OUTPUT);
digitalWrite(GLED,HIGH);


pinMode(YLED,OUTPUT);
digitalWrite(YLED,HIGH);


pinMode(RLED,OUTPUT);
digitalWrite(RLED,HIGH);

pinMode(SASLED,OUTPUT);
digitalWrite(SASLED,HIGH);

pinMode(RCSLED,OUTPUT);
digitalWrite(RCSLED,HIGH);

pinMode(CG1LED,OUTPUT);
digitalWrite(CG1LED,HIGH);
}


void LEDSAllOff() {
digitalWrite(GLED,LOW);
digitalWrite(YLED,LOW);
digitalWrite(RLED,LOW);
digitalWrite(SASLED,LOW);
digitalWrite(RCSLED,LOW);
digitalWrite(CG1LED,LOW);
}




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


void Indicators() {/* CS=5 YELLOW

I would really appreciate if someone has the time and energy to help me solve this. It's really frustrating not to be able to find out what's wrong by myself.

Edited by I_KILL_HORSES
Link to comment
Share on other sites

Zitronen:

Thanks so much for the hard work you've put (and continue to put) into this effort. Your work (along with many others) has inspired me to learn the Arduino, and begin working on my own simpit/console! :)

I'm currently reading the archives (up to page 16/96) - but I was wondering if you had a feature-request form? Or some way for us to see what features have been requested (apart from going through all the posts) / are being worked on?

I've been thinking that it would be nifty to be able to get overheat warnings when something overheats > 50% [such as rockets at launch]

[The latest version of KSP also seems to have 'health' for various parts of the craft, such as parachutes exposed to the re-entry have a health bar show up - which could be useful to output a warning about]

ksp_health.png

Link to comment
Share on other sites

2zitronen: Hi! your plugin is awesome. I`m doing my own hardware controller too, and looks like you saved a ton of my time. I would like to make a powered landing helper, that would show me when it`s time to start suicide burn. And take-off helper, that wil show me how far I`m from terminal velocity. For those I need a TWR, or even better - current thrust and mass of a vessel. Is it possible to get that kind of data through your plugin?

Link to comment
Share on other sites

Hi Dimitrik,

I don't think KSPIO will be able to give you that

The opening post has the data that is already supported


[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct VesselData
{
public byte id; //1 packet id
public float AP; //2 apoapsis (m to sea level)
public float PE; //3 periapsis (m to sea level)
public float SemiMajorAxis; //4 orbit semi major axis (m)
public float SemiMinorAxis; //5 orbit semi minor axis (m)
public float VVI; //6 vertical velocity (m/s)
public float e; //7 orbital eccentricity (unitless, 0 = circular, > 1 = escape)
public float inc; //8 orbital inclination (degrees)
public float G; //9 acceleration (Gees)
public int TAp; //10 time to AP (seconds)
public int TPe; //11 time to Pe (seconds)
public float TrueAnomaly; //12 orbital true anomaly (degrees)
public float Density; //13 air density (presumably kg/m^3, 1.225 at sea level)
public int period; //14 orbital period (seconds)
public float RAlt; //15 radar altitude (m)
public float Alt; //16 altitude above sea level (m)
public float Vsurf; //17 surface velocity (m/s)
public float Lat; //18 Latitude (degree)
public float Lon; //19 Longitude (degree)
public float LiquidFuelTot; //20 Liquid Fuel Total
public float LiquidFuel; //21 Liquid Fuel remaining
public float OxidizerTot; //22 Oxidizer Total
public float Oxidizer; //23 Oxidizer remaining
public float EChargeTot; //24 Electric Charge Total
public float ECharge; //25 Electric Charge remaining
public float MonoPropTot; //26 Mono Propellant Total
public float MonoProp; //27 Mono Propellant remaining
public float IntakeAirTot; //28 Intake Air Total
public float IntakeAir; //29 Intake Air remaining
public float SolidFuelTot; //30 Solid Fuel Total
public float SolidFuel; //31 Solid Fuel remaining
public float XenonGasTot; //32 Xenon Gas Total
public float XenonGas; //33 Xenon Gas remaining
public float LiquidFuelTotS;//34 Liquid Fuel Total (stage)
public float LiquidFuelS; //35 Liquid Fuel remaining (stage)
public float OxidizerTotS; //36 Oxidizer Total (stage)
public float OxidizerS; //37 Oxidizer remaining (stage)
public UInt32 MissionTime; //38 Time since launch (s)
public float deltaTime; //39 Time since last packet (s)
public float VOrbit; //40 Orbital speed (m/s)
public UInt32 MNTime; //41 Time to next node (s) [0 when no node]
public float MNDeltaV; //42 Delta V for next node (m/s) [0 when no node]
public float Pitch; //43 Vessel Pitch relative to surface (degrees)
public float Roll; //44 Vessel Roll relative to surface (degrees)
public float Heading; //45 Vessel Heading relative to surface (degrees)
public UInt16 ActionGroups; //46 status bit order:SAS, RCS, Light, Gear, Brakes, Abort, Custom01 - 10 [COLOR=#333333] }
[/COLOR]

Link to comment
Share on other sites

I have started thinking recently that TWR would be good to have available. Playing with FAR in 0.90 and the awesome new stock aero in 1.0 and up I find that the one thing I eyeball very carefully on ascent is Kerbal Engineer's TWR display for the current stage.

When some more free time magically appears I was thinking I might try to add vessel mass and current thrust to the VesselData packet, and let my controller compute current TWR. The thrust at least probably has other uses.

Link to comment
Share on other sites

I have started thinking recently that TWR would be good to have available. Playing with FAR in 0.90 and the awesome new stock aero in 1.0 and up I find that the one thing I eyeball very carefully on ascent is Kerbal Engineer's TWR display for the current stage.

When some more free time magically appears I was thinking I might try to add vessel mass and current thrust to the VesselData packet, and let my controller compute current TWR. The thrust at least probably has other uses.

Good thing I haven't done the decals yet!

Link to comment
Share on other sites

Hi Dimitrik,

I don't think KSPIO will be able to give you that

The opening post has the data that is already supported

I was hoping that it`s some kind of undocumented feature, or such obvious thing that is not worth documenting. It`s a pity.

It seems that telemachus is not helpful eather - no mass and no thrust. Maybe there are some other sources for that kind of data? kOs seems like can give much more.

Or it will be easier to make a branch of this fine plugin?

Link to comment
Share on other sites

I was hoping that it`s some kind of undocumented feature, or such obvious thing that is not worth documenting. It`s a pity.

It seems that telemachus is not helpful eather - no mass and no thrust. Maybe there are some other sources for that kind of data?

The information is either directly accessible through the API or easily derived. I use KER a lot, which seems to have no trouble displaying it all.

The code for this plugin is pretty easy to get the hang of, even for stubborn sysadmins like me. I highly recommend forking the github repo, adding it in and submitting a pull request. If you don't, I'll have a crack at it in the next few weeks. :)

Link to comment
Share on other sites

Maybe I can inspire you with my intentions for expanding my project. The second arduino in my console (the module I named COLOSSUS) will read a precomputed ascent trajectory calculated by Ascent Komputron from a SD card. It then gives you ascent guidance by displaying the desired pitch angle for your trajectory at the current altitude. More interesting for you is that Ascent Komputron has thrust data for all stages available

// KHDL description of vessel "Kerbal X" with final sequence stage = 4
// Komputron version: 1.4.2.0, file generated on 12/18/2014 12:13:12 PM
// This is an automatic conversion: please make sure the source design is compliant with the conversion rules and check the results for consistency <<
VESSEL=Kerbal_X DRYMASS=46.820 DRYDRAG=0.1945

// Region #5, 2 parts
// Region is treated as payload, total mass = 4.300t <<
// 1 x Mk1-2 Command Pod

// Region #4, 14 parts
// Region is treated as payload, total mass = 11.700t <<
// 1 x Rockomax X200-16 Fuel Tank, resources = [LiquidFuel / Oxidizer]
// 1 x Rockomax "Poodle" Liquid Engine, propellants = [LiquidFuel / Oxidizer]

// Region #3, 14 parts, dry mass = 12.520t
// Region not decoupled <<
// 1 x Rockomax "Mainsail" Liquid Engine, propellants = [LiquidFuel / Oxidizer]
ENGINE=LFE3_8 THRUST=1500.000 VACISP=360.000 KSLISP=320.000
// 3 x Rockomax X200-32 Fuel Tank, resources = [LiquidFuel / Oxidizer]
TANK=LFT3 FUEL=48.000 FUELDRAG=0.2000 RESERVE=0.000
CONNECTSRC=LFT3 CONNECTDEST=LFE3_8

From this data you can read dry weight and thrust of the vehicle and the individual stages.

I let my arduinos communicate on i2c bus and share that information.

One day I want to see chamber pressure and temperature on my console and have status lights for individual engines. One day...

Link to comment
Share on other sites

I will just copy all of my code, I do not know how much I need to post for someone to troubleshoot it for me.

I would really appreciate if someone has the time and energy to help me solve this. It's really frustrating not to be able to find out what's wrong by myself.

Looks like you can just replace "numdisp" with "lc"?

Zitronen:

Thanks so much for the hard work you've put (and continue to put) into this effort. Your work (along with many others) has inspired me to learn the Arduino, and begin working on my own simpit/console! :)

I'm currently reading the archives (up to page 16/96) - but I was wondering if you had a feature-request form? Or some way for us to see what features have been requested (apart from going through all the posts) / are being worked on?

I've been thinking that it would be nifty to be able to get overheat warnings when something overheats > 50% [such as rockets at launch]

There was a spread sheet like thing awhile back. Most of the things on there are now implemented. The best place for feature request would be github I guess. I'll have a look at how easy/hard it would be to add overheat.

@zitronen: You just saved me a SOI slider. Thanks for the update. Let us just hope that Squad does not plug in three new planets, or the scheme will be broken.

If they add more planets then F- it we are going 16bit! :cool:

2zitronen: Hi! your plugin is awesome. I`m doing my own hardware controller too, and looks like you saved a ton of my time. I would like to make a powered landing helper, that would show me when it`s time to start suicide burn. And take-off helper, that wil show me how far I`m from terminal velocity. For those I need a TWR, or even better - current thrust and mass of a vessel. Is it possible to get that kind of data through your plugin?
I have started thinking recently that TWR would be good to have available. Playing with FAR in 0.90 and the awesome new stock aero in 1.0 and up I find that the one thing I eyeball very carefully on ascent is Kerbal Engineer's TWR display for the current stage.

When some more free time magically appears I was thinking I might try to add vessel mass and current thrust to the VesselData packet, and let my controller compute current TWR. The thrust at least probably has other uses.

Thrust is not trivial to get. You would need to iterate through all the parts, find which parts are engines, whether they are active and have fuel. In 1.0 thrust also changes with atmo. Even then you could have situations where you have engines facing each other (as an extreme example) so their net thrust is zero. I think we would need to steal some code from mechjeb/engineer for that unless stibbons wants to do the dirty work :D. You can make a simple landing computer with some nested PID controller loops on decent velocity, acceleration and predicted impact time. Obviously won't be quite as good as a true suicide burn, but this can be done with the currently available data.

I've been messing around with aerodynamics lately, I am planning on also adding indicated airspeed, Mach number, and maybe angle of attack.

Edited by zitronen
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...