Project The Battle for a Flag

Thunder Chicken

Resident Lua Script Rabble-Rouser
Donator
Joined
Mar 22, 2008
Messages
5,847
Reaction score
5,509
Points
188
Location
Massachusetts
I am working on making a vessel that can provide a visual wind indication when atmospheric wind effects are turned on, in the manner of a wind sock on a small airfield. What could go wrong?

So I made a simple mesh of a flag and animated it.

screenshot-at-2025-03-01-12-07-10-png.42562


The intent was that this would remain stationary and the flag would rotate via animation to align with the wind direction.

First trick was to make a vessel, and get it out of inactive / landed status. So I set contact points and gave it a nominal mass, and I "bump" it with a small add_force force on the first time step. This was necessary to get vi:airspeed() and vi:airspeedvector() to return anything, as landed vessels don't interact with the wind.

Second problem (very possibly an Orbiter bug?) - once I got it out of the landed state, the flag started getting blown away by the wind! There was a drag force acting on the vessel even though there were absolutely no drag elements applied to it!

Screenshot at 2025-03-02 16-57-45.png
Screenshot at 2025-03-02 16-59-10.png

I have no idea why this occurs and will submit it as an issue to Github.

So, in order to patch that problem and keep the flag stationary, I used add_force to oppose and neutralize the drag force, and set the angular velocity to 0 to keep it from rotating:

Code:
--shouldn't need the following, but a spurious drag force is applied to the flag when atmospheric wind effects are enabled.

drag = vi:get_dragvector()
vi:add_force(vec.mul(drag,-1), {x=0,y=0,z=0})
vi:set_angvel({x=0,y=0,z=0})

This kinda-sorta worked, but the flag would still move about randomly, but usually randomly around its original point. You can see that the drag forces are not trivial (flag alignment animation is not set yet in this image):

Screenshot at 2025-03-02 18-08-45.png

But once in a while it would be at a velocity close enough to 0 where it would resume inactive/landed status again!:

Code:
BEGIN_SHIPS
WindSock:WindSock
  STATUS Landed Earth
  POS -80.6825845 28.5969059
  HEADING 330.18
  ALT 0.837
  AROT 66.673 33.912 9.869
  NAVFREQ 0 0
END
END_SHIPS

So, to work around this issue, I tested to see if the vessel was landed, and if so I re-bumped it to get it out of inactive landing status:

Code:
if simt == simdt or vi:is_landed() ~= nil then --bump vessel to get it out of inactive status

    vi:add_force({x=0, y=1e-9, z=0}, {x=0,y=0,z=0})

end

It seems that every time the flag needs a "bump" the forces become unbalanced and it drifts with the wind a bit. Again, no drag elements whatsoever are applied to this vessel - no airfoils, no drag coefficients, no variable drag, nothing.

But it 95% works:

Waving_Flag_Drag.gif

It's been running for about 20 minutes and is still not landed, but you can see how far it moves (it started at the end of the runway at the start of the over-run):

Screenshot at 2025-03-02 18-46-43.png
 
Last edited:
Did you check if you have the default cross sections and Cw coeffs there? Did you try overriding them to reach zero?
 
Did you check if you have the default cross sections and Cw coeffs there? Did you try overriding them to reach zero?
I was not aware that there were default Cw coefficients!

Code:
vi:set_cw({x=0,y=0,z=0,zn=0})

This shuts off the drag:

Screenshot at 2025-03-02 19-22-42.png

That is a really annoying behavior. If I don't program in drag, I expect NO DRAG. Why doesn't it default to 0?
 
That is a really annoying behavior. If I don't program in drag, I expect NO DRAG. Why doesn't it default to 0?

I hate these words as much as you do, but: It has always been done that way.
 
I hate these words as much as you do, but: It has always been done that way.
Tradition is great, but it would be nice if someone told the add on developers. Undocumented feature = bug in my book.
 
Tradition is great, but it would be nice if someone told the add on developers. Undocumented feature = bug in my book.

I am sure it is documented right next to the functions to set them, but of course, we have a lot more functions today, so you might not read this fine print.
 
I am sure it is documented right next to the functions to set them, but of course, we have a lot more functions today, so you might not read this fine print.
Nope. This is what we get, nearly identical in the API Reference:
vessel:set_cw (cw) Set wind resistance coefficients.

Set the vessel's wind resistance coefficients along its axis directions.

The cw coefficients are only used by the legacy flight model (if no airfoils are defined). In the presence of airfoils, drag calculations are performed on the basis of the airfoil parameters.

The parameter passed to this function must be a table with 4 fields: 'x', 'y', 'z','zn'., where 'z' is the coefficient in +z (forward) direction, 'zn' is the coefficient in -z (backward) direction, 'x' is the coefficient in lateral (left/right) direction,and 'y' is the coefficient in vertical (up/down) direction. Drag coefficients in lateral and vertical direction are assumed symmetric.

The 'x', 'y' and 'z' fields are identical to a standard vector variable, and can thus be assigned via vector operations, but the 'zn' field must be added manually.

Parameters:​

  • cw table resistance coefficients in principal directions

See also:​

 
Then its part of this arcane knowlegde that you get by doing Orbiter add-ons for 21 years.... OK, should better be documented, I think the defaults are for a 1 kg sphere with 1 m² crosssection in every direction.
 
Then its part of this arcane knowlegde that you get by doing Orbiter add-ons for 21 years.... OK, should better be documented, I think the defaults are for a 1 kg sphere with 1 m² crosssection in every direction.
The mass of the sphere would not matter. If the cw coefficients default to 1.0 in each direction and are applied to a 1 m2 projection of a sphere, at standard density and with the wind speeds I was experiencing (~6-7 m/s) that would yield a drag force of about 50-60 N which matches what I saw in the previous post.

I searched around GitHub to see if I could find where these defaults are buried but no luck so far.
 
Code:
void Vessel::DefaultGenericCaps ()
{
...
    CWz[0]             = 0.1;
    CWz[1]             = 0.3;
    CWx                = 0.3;
    CWy                = 0.3;
...
}
?
This is in Vessel.cpp.

There must be cross sectional areas defined in addition to these coefficients. The only thing that looks plausible is later in this function:

Code:
cs.Set (20,20,20);

That does seem to be the case:

Code:
    void GetCrossSections (VECTOR3 &cs) const;

    /**
     * \brief Defines the vessel's cross-sectional areas, projected in the
     *   directions of the vessel's principal axes.
     * \param cs vector of cross-sectional areas of the vessel's projection

So my 1 kg add-on free-falling at terminal velocity in the -Y orientation should achieve a terminal velocity of:

math.sqrt((2*m*G0)/(cw_y*rho*A_y))

= math.sqrt((2*(1 kg)*9.81 m/s2)/(0.3*1.115*20m2)) = 1.71 m/s

But it falls at 2.42 m/s?

The ratio of 2.42/1.71 ~ sqrt(2). I smell a rat...

If the dynamic pressure is to be believed (3.26 N/m2), then the product of cw_y*A_y needs to be 3.0 m2, which would be 0.3 * 10 m2, not 20 m2.

Screenshot at 2025-03-03 16-34-26.png

Digging a little deeper, it seems that the cross sectional areas were multiplied by 0.5 in this block of code for reasons unknown?

Code:
void VESSEL::SetCrossSections (const VECTOR3 &cs) const
{
    vessel->cs.Set (cs.x, cs.y, cs.z);
    vessel->vd_forw = cs.z * 0.5*vessel->CWz[0];
    vessel->vd_back = cs.z * 0.5*vessel->CWz[1];
    vessel->vd_vert = cs.y * 0.5*vessel->CWy;
    vessel->vd_side = cs.x * 0.5*vessel->CWx;
}

It looks like these components are projected into the direction of motion to calculate drag here in Vessel.cpp:

Code:
    double cw_cs = vd_side*fabs(vnorm.x) + vd_vert*fabs(vnorm.y) + vd_forw*fabs(vnorm.z);
    Drag += cw_cs * sp.dynp;      // parasite drag magnitude

To sum this all up, if you do not use SetCW() to zero out the wind coefficients and do not specify cross sectional areas with SetCrossSections(), Orbiter will assume that the vessel is an object with projected cross sectional areas of 10 m2 in the x,y, and z directions, and wind coefficients {x=0.3, y=0.3, z=0.1, zn=0.3} and calculate drag forces based on these values.

I like this bit in Vessel.h:

Code:
    void DefaultGenericCaps ();
    // set generic vessel caps to (fairly arbitrary) defaults to prevent
    // catastropic failures for undefined caps

Oh come on. I've been punted into solar orbit in a sailboat so many times that I should make a futuristic anime Gilligan's Island show of it, and I've survived each "catastrophe" just fine. Anybody who applies a force to an object without drag should expect - no, DEMAND, to get punted into deep space. It's hard enough getting out of our gravity well without adding drag! :)
 
Last edited:
Back
Top