Project Energia 5V Heavy Launch Vehicle

GLS

Well-known member
Orbiter Contributor
Addon Developer
Joined
Mar 22, 2008
Messages
5,927
Reaction score
2,937
Points
188
Website
github.com
If someone managed to do it, I'd like to know, if its an Orbiter bug I don't want to chase a wild goose...
I remember using this "vector animation" in SSU to move particle streams, attachment points and lights, so I'd say it works. ?‍♂️


Cleaned the code : instead of dummy thrusters to get manual pitch/yaw/roll input, I now use the dedicated SDK function (GetManualControlLevel). ?

I plan to use the dummy thrusters for core to boosters communications. :giggle:
There is a function to send a message to another vessel (a VESSEL::clbkSomething), so you could send a message to each booster with the target gimbal angle for it (should be the same for all nozzles in a booster). Or you could have a custom public function in the boosters to receive the target angle, called by the core.


BTW: in the image you posted, the normals of some nozzles are not correct.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,627
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
VESSEL::clbkSomething

Its VESSEL3::clbkGeneric().

It would be also possible to use a new callback function there, but the clbkGeneric approach is faster, since you can avoid having to check type information of the VESSEL class. You can just write your data there and be sure: If you did send it to the wrong vessel, it will at least not explode in 99% of all cases.
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
I have it working with dummy thrusters. The animations of the boosters nozzles follow the core inputs, and thrust vectors work the same way. ? Also, I managed to have 1 .dll for the 4 boosters : boosters have a specific name (A,B,V,G) and there is a different "case" for each name, which allows me to have each booster reacting in regard of its position.

Still, I know a dedicated callback function would be much better, so I'll keep that in mind for the upper stages (and for later code improvements). I'm in full learning process.

So right now I'm trying to find a setup that works, allowing to control pitch and yaw channels at the same time and roll channel as "lower priority", to match what the core does. The solution probably won't be the most efficient as I'll use half the nozzles for pitch and half the nozzles for yaw, but it should be enough to allow control. After all, this is a 100-meters tall super-heavy launch system, not a Sukhoi jet fighter performing aerobatics ! :LOL:
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
Ouch, getting an access violation... Am I doing something wrong with my "name comparison" ? Again, I'm rather new to this.

The crash seems triggered by "SetThrusterDir(th_booster[1], _V(vector_pitch.x, vector_pitch.y, vector_pitch.z));" (in the "B" block)

C++:
THRUSTER_HANDLE th_booster[4];
...

void Energia5V_booster::clbkPostStep(double simt, double simdt, double mjd)
{

    ...

    char *myName = GetName();
    char buffer[256];
    strcpy(buffer, myName);

    if (strcmp(buffer, "E5VBoosterA") == 0) // Which booster am I ? A
    {
        SetAnimation(RD171_1_rot, -Pitch_sum);
        SetAnimation(RD171_2_rot, -Yaw_sum);
        SetAnimation(RD171_3_rot, Yaw_sum);
        SetAnimation(RD171_4_rot, Pitch_sum);

        SetThrusterDir(th_booster[0], _V(-vector_pitch.x, -vector_pitch.y, vector_pitch.z));
        SetThrusterDir(th_booster[3], _V(-vector_pitch.x, -vector_pitch.y, vector_pitch.z));


    }
    if (strcmp(buffer, "E5VBoosterB") == 0) // Which booster am I ? B
    {
        SetAnimation(RD171_1_rot, Yaw_sum);
        SetAnimation(RD171_2_rot, Pitch_sum);
        SetAnimation(RD171_3_rot, -Pitch_sum);
        SetAnimation(RD171_4_rot, -Yaw_sum);

        SetThrusterDir(th_booster[1], _V(vector_pitch.x, vector_pitch.y, vector_pitch.z)); // this is where hell breaks loose !
        SetThrusterDir(th_booster[2], _V(vector_pitch.x, vector_pitch.y, vector_pitch.z));

    }
   
    ...
   
}
 

GLS

Well-known member
Orbiter Contributor
Addon Developer
Joined
Mar 22, 2008
Messages
5,927
Reaction score
2,937
Points
188
Website
github.com
Ouch, getting an access violation... Am I doing something wrong with my "name comparison" ? Again, I'm rather new to this.

The crash seems triggered by "SetThrusterDir(th_booster[1], _V(vector_pitch.x, vector_pitch.y, vector_pitch.z));" (in the "B" block)

THRUSTER_HANDLE th_booster[4];
...

void Energia5V_booster::clbkPostStep(double simt, double simdt, double mjd)
{

...

char *myName = GetName();
char buffer[256];
strcpy(buffer, myName);


if (strcmp(buffer, "E5VBoosterA") == 0) // Which booster am I ? A
{
SetAnimation(RD171_1_rot, -Pitch_sum);
SetAnimation(RD171_2_rot, -Yaw_sum);

SetAnimation(RD171_3_rot, Yaw_sum);
SetAnimation(RD171_4_rot, Pitch_sum);

SetThrusterDir(th_booster[0], _V(-vector_pitch.x, -vector_pitch.y, vector_pitch.z));
SetThrusterDir(th_booster[3], _V(-vector_pitch.x, -vector_pitch.y, vector_pitch.z));


}
if (strcmp(buffer, "E5VBoosterB") == 0) // Which booster am I ? B
{
SetAnimation(RD171_1_rot, Yaw_sum);
SetAnimation(RD171_2_rot, Pitch_sum);
SetAnimation(RD171_3_rot, -Pitch_sum);
SetAnimation(RD171_4_rot, -Yaw_sum);


SetThrusterDir(th_booster[1], _V(vector_pitch.x, vector_pitch.y, vector_pitch.z)); // this is where hell breaks loose !
SetThrusterDir(th_booster[2], _V(vector_pitch.x, vector_pitch.y, vector_pitch.z));

}

...

}
This has to be between 0 and 1.

The function might need an actual VECTOR3 variable, so you can't use the _V(...) in there directly. You have to create a variable, set it's value and then give it to SetThrusterDir().
Also, are you sure th_booster is valid?


You should be able to do away with the buffer string, and use myName directly.
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
OK I'll fix the animation value, I'm using negative values from the beginning, worked so far but you're right, the SDK mentions that it should be between 0 and 1, so I'll set the "neutral" state to 0.5 and make the necessary changes.

Yes, those vectors definitions are a bit messy, I'll sort that.

I got rid of the buffer string and used myName directly, it works. Doesn't solve the access violation but always good to avoid unnecessary variables, thanks.
 

GLS

Well-known member
Orbiter Contributor
Addon Developer
Joined
Mar 22, 2008
Messages
5,927
Reaction score
2,937
Points
188
Website
github.com
Yes, those vectors definitions are a bit messy, I'll sort that.
I just checked the API...
Code:
void SetThrusterDir (THRUSTER_HANDLE th, const VECTOR3 &dir) const;
... and it being a ref, I think you really have to feed it a variable instead of _V():

Code:
VECTOR3 dir = _V(vector_pitch.x, vector_pitch.y, vector_pitch.z);
SetThrusterDir(th_booster[1], dir );

(You can reuse the same variable for other engines.)
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
OK I made the changes you suggested, still no luck. But I found what was going on and was able to fix it.

The problem was that I declared 1 main thruster group (th_booster) for the 4 instances of the module. It doesn't work. So I added the name check in ClbkPostCreation and declared 4 main thruster groups (th_boosterA, th_boosterB, th_boosterG, th_boosterV) so that each instance of the module has its "own" thruster group (and the associated exhausts), and now it works. (y)

No, still have the bug. Probably a undeclared variable somewhere, might come from the core as well...

No, I'm good. I simply made a typo in the thrusters call, it was unrelated to the previous issue.
 
Last edited:
  • Like
Reactions: GLS

GLS

Well-known member
Orbiter Contributor
Addon Developer
Joined
Mar 22, 2008
Messages
5,927
Reaction score
2,937
Points
188
Website
github.com
OK I made the changes you suggested, still no luck. But I found what was going on and was able to fix it.

The problem was that I declared 1 main thruster group (th_booster) for the 4 instances of the module. It doesn't work. So I added the name check in ClbkPostCreation and declared 4 main thruster groups (th_boosterA, th_boosterB, th_boosterG, th_boosterV) so that each instance of the module has its "own" thruster group (and the associated exhausts), and now it works. (y)

No, still have the bug. Probably a undeclared variable somewhere, might come from the core as well...

No, I'm good. I simply made a typo in the thrusters call, it was unrelated to the previous issue.
Unless you declare the thruster handle variables static, you shouldn't have any issues with data being mixed between the boosters, which should be (independent) instances of the same class.
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
Yes, I'm crashing again, there's something else...

Just to be sure, this is how I declare my thrusters :

C++:
class Energia5V_booster : public VESSEL4 {
public:
    Energia5V_booster(OBJHANDLE hVessel, int flightmodel);
    ~Energia5V_booster();

    void clbkSetClassCaps(FILEHANDLE cfg);
    void clbkPostCreation();
    void clbkPostStep(double simt, double simdt, double mjd);

private:

    ...

    THRUSTER_HANDLE th_boosterA[4], th_boosterB[4], th_boosterV[4], th_boosterG[4];

    ...

};

void Energia5V_booster::clbkPostCreation()
{

    char *myName = GetName();

    if (strcmp(myName, "E5VBoosterA") == 0) // Which booster am I ? A
    {
        th_boosterA[0] = CreateThruster(_V(0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterA[1] = CreateThruster(_V(0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterA[2] = CreateThruster(_V(-0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterA[3] = CreateThruster(_V(-0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        CreateThrusterGroup(th_boosterA, 4, THGROUP_MAIN);

        AddExhaust(th_boosterA[0], 10, 0.4);
        AddExhaust(th_boosterA[1], 10, 0.4);
        AddExhaust(th_boosterA[2], 10, 0.4);
        AddExhaust(th_boosterA[3], 10, 0.4);

    }
    if (strcmp(myName, "E5VBoosterB") == 0) // Which booster am I ? B
    {
        th_boosterB[0] = CreateThruster(_V(0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterB[1] = CreateThruster(_V(0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterB[2] = CreateThruster(_V(-0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterB[3] = CreateThruster(_V(-0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        CreateThrusterGroup(th_boosterB, 4, THGROUP_MAIN);

        AddExhaust(th_boosterB[0], 10, 0.4);
        AddExhaust(th_boosterB[1], 10, 0.4);
        AddExhaust(th_boosterB[2], 10, 0.4);
        AddExhaust(th_boosterB[3], 10, 0.4);

    }
    if (strcmp(myName, "E5VBoosterV") == 0) // Which booster am I ? V
    {
        th_boosterV[0] = CreateThruster(_V(0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterV[1] = CreateThruster(_V(0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterV[2] = CreateThruster(_V(-0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterV[3] = CreateThruster(_V(-0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        CreateThrusterGroup(th_boosterV, 4, THGROUP_MAIN);

        AddExhaust(th_boosterV[0], 10, 0.4);
        AddExhaust(th_boosterV[1], 10, 0.4);
        AddExhaust(th_boosterV[2], 10, 0.4);
        AddExhaust(th_boosterV[3], 10, 0.4);
    
    }
    if (strcmp(myName, "E5VBoosterG") == 0) // Which booster am I ? G
    {
        th_boosterG[0] = CreateThruster(_V(0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterG[1] = CreateThruster(_V(0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterG[2] = CreateThruster(_V(-0.8515, 0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        th_boosterG[3] = CreateThruster(_V(-0.8515, -0.8515, -17.55), _V(0, 0, 1), 1976000, KeroLOX, 3305.97, 3031.29);
        CreateThrusterGroup(th_boosterG, 4, THGROUP_MAIN);

        AddExhaust(th_boosterG[0], 10, 0.4);
        AddExhaust(th_boosterG[1], 10, 0.4);
        AddExhaust(th_boosterG[2], 10, 0.4);
        AddExhaust(th_boosterG[3], 10, 0.4);

    }
    
    ...
    
}
 

GLS

Well-known member
Orbiter Contributor
Addon Developer
Joined
Mar 22, 2008
Messages
5,927
Reaction score
2,937
Points
188
Website
github.com
OK, just to confirm: you have 1 vessel named booster (or something), which you then instanciate 4 times in the scenario + 1 vessel named core, which only shows up once in the scenario, correct?
 

GLS

Well-known member
Orbiter Contributor
Addon Developer
Joined
Mar 22, 2008
Messages
5,927
Reaction score
2,937
Points
188
Website
github.com
Try this: create 1 booster vessel .cfg file and make it load the booster dll module*. In the code, load the mesh, create the docking port, set the empty mass, etc, create the thrusters and set up whatever infrastructure you want to receive and act on the gimbal commands from the core (and probably ignition and shutdown signals as well).
This is all done as if there is only one booster. It is so stupid it doesn't care how many there are or where it is in the stack, the brains are in the core.

*) In the scenario declare the 4 boosters, with different names, but the same vessel class.
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
Well in my scenario I have only the core booster. It "creates" and docks the 4 strap-on boosters and dock them, only way I found to have a docked assembly.

I have 4 different config files, that all load the same booster .dll module. So my core module creates 4 instances of the booster .dll.
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
Found that on a C++ forum :

Access violation reading location 0x00000018

When you get this message, it usually means you are trying to read from a bad pointer. In this case, since the address is near zero, it tells me you are trying to access a member of a class or struct, but the this pointer is null.
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
Oh ok I found it... very very stupid... a & put in a place I was not suspecting (propellant resource handle)... 1 day lost... :rolleyes:

Those "&" are lethal... use with extreme caution... ☢️

Well, the good thing is that I cleaned the code a lot.
 
Last edited:

kuddel

Donator
Donator
Joined
Apr 1, 2008
Messages
2,064
Reaction score
507
Points
113
Yeah, that's the spirit!
You've found a problem, analyzed it, "wasted" some time in code-cleanup.
From my experience, you learn much more from errors than from successes...
The only "downside" of this is: You get more experience, you get less opportunities to make errors (to learn something new from) ;)
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
Back to the good maths 3D vector stuff...

I'm having trouble to find the right formula for my thrust vectors... In the typical (easy) case for 1 axis gimbal you have "sin(x), 0, cos(z)".

Now I want it 45° sideways. So I'm pretty sure I have to input sin(45) somewhere. I tried "sin(45)*x, sin(45)*y, cos(z)" and even "sin(45)*sin(x), sin(45)*sin(y), cos(z)" and still no luck, I don't get a normal vector. I can't really use normalise here because it will lead to some thurst imbalance, so I need the correct maths.

So if there is some math guru around, I'd like to have your input - I stopped maths in high school, nearly 20 years ago...-. Again I want gimbal on 1 axis only, and 45° rotation so that if the gimbal angle was 45° it would be (0.707.., 0.707..., z...).

I found out ! I was mixing DEG with RAD... Orbiter takes RAD by default, so that sin(45) is nonsense. 45 DEG = PI/180 in RAD.

So the correct formula is :

myVector = _V(cos(PI/180)*x, cos(PI/180)*y, cos(z))
 
Last edited:

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,627
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
The cos(z) inside looks rather dangerous. Is z an angle? PI/180 is also not 45° but 1°. 45° = PI/4

And finally: What you are actually doing there, is a matrix multiplication, don't forget it. ;)
 

N_Molson

Addon Developer
Addon Developer
Donator
Joined
Mar 5, 2010
Messages
9,290
Reaction score
3,258
Points
203
Location
Toulouse
No x, y and z are the vector components... They are related to an input level and a max gimbal angle, so, for z, when input = 0 then z = 1, which is fine.

so I guess :

myVector = _V(cos(PI/4)*x, cos(PI/4)*y, cos(z))

in code :

Code:
vector_pitch = _V(cos(PI/4)*Pitch_sum*RD171_GIMBAL_RANGE, cos(PI/4)*Pitch_sum*RD171_GIMBAL_RANGE, cos(Pitch_sum*RD171_GIMBAL_RANGE));

where Pitch_sum is between -1 and 1, and RD171_GIMBAL_RANGE is an angle in RAD.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,627
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Yes, but cos expects an angle as input, not a scalar vector component, remember? cos(z) makes absolutely no sense, especially if you DON'T want to change anything in the Z axis of the vector. Just make it z. Or 1.0 * z, if you feel funny.
 
Top