Welcome to Keen Software House Forums! Log in or Sign up to interact with the KSH community.
  1. You are currently browsing our forum as a guest. Create your own forum account to access all forum functionality.

Satellite gravity awareness and thrust managment

Discussion in 'Programming (In-game)' started by gothosan, Nov 21, 2016.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. gothosan Junior Engineer

    Messages:
    723
    I'm trying to write code to make my satellite aware to the gravity well (that it may be inside of).
    I've been reading few of the posts here about doing that and on how to rotate a ship which is inside gravity well,
    however I did not understand enough as of how it works.
    Basically I'm trying to make gravity stabilizer so the satellite will keep the position it is on and rotation of the satellite, so down facing thrusters will keep facing the right way and it won't fall from the sky because of a small hit (due to meteors or maintainance ship attempting to dock to the sat).

    So far I only know how to get altitude, tell if the sat is inside gravity well and get gravity vector.
    From what I did understand a second vector is needed for this calculation, but thats all I could understand.

    Another thing I'm trying to do is thrust control system so where possible the minimal amount of down facing thrusters will be used to keep the sat in air and that while perfectly aligned to gravity all thrusters of all sides (but minimum down needed) will be off for
    power conservation.
    I know how to get the total mass of the sat but not sure how to extract the gravity acceleration from the vector in order to calculate needed thrust.
    The satellite has 4 large ion thrusters and 6 small ones on the bottom, my guess is for reading current thrust in need to cycle those thrusters and read and add MaxThrust property? Is that correct?
     
  2. Elfi Wolfe Apprentice Engineer

    Messages:
    498
    Take a look at http://steamcommunity.com/sharedfiles/filedetails/?id=423016495

    Look inside method orbital.
    Also look at method, GetGravity.

    Be a few hours before I am home and can boot up visual studio to show code here.

    I use auto-level to level satellite and then total mass is used to figure the thruster power needed to hold orbit.

    You can also find me on SE discord chat.
     
    • Agree Agree x 1
  3. gothosan Junior Engineer

    Messages:
    723
    Thanks I will have a look at it
    --- Automerge ---
    There is no GetGravity method..
    And I really don't understand what is going on in Orbital
     
  4. Elfi Wolfe Apprentice Engineer

    Messages:
    498
    I will get home in 2 hours and will post the code snippet for you.
     
  5. plaYer2k Master Engineer

    Messages:
    3,160
    Code:
    using System;
    using VRage.Game.ModAPI.Ingame;
    using VRageMath;
    namespace Sandbox.ModAPI.Ingame
    {
    	public interface IMyShipController : IMyTerminalBlock, IMyCubeBlock, IMyEntity
    	{
    		/// <summary>
    		/// Indicates whether a block is locally or remotely controlled.
    		/// </summary>
    		bool IsUnderControl
    		{
    			get;
    		}
    		/// <summary>
    		/// Indicates whether wheels are being controlled by this controller.
    		/// </summary>
    		bool ControlWheels
    		{
    			get;
    		}
    		/// <summary>
    		/// Indicates whether thrusters are being controlled by this controller.
    		/// </summary>
    		bool ControlThrusters
    		{
    			get;
    		}
    		/// <summary>
    		/// Indicates the current state of the handbrake.
    		/// </summary>
    		bool HandBrake
    		{
    			get;
    		}
    		/// <summary>
    		/// Indicates whether dampeners are currently enabled.
    		/// </summary>
    		bool DampenersOverride
    		{
    			get;
    		}
    		/// <summary>
    		/// Gets the detected natural gravity vector and power at the current location.
    		/// </summary>
    		/// <returns></returns>
    		Vector3D GetNaturalGravity();
    		/// <summary>
    		/// Gets the detected artificial gravity vector and power at the current location.
    		/// </summary>
    		/// <returns></returns>
    		Vector3D GetArtificialGravity();
    		/// <summary>
    		/// Gets the total accumulated gravity vector and power at the current location,
    		/// taking both natural and artificial gravity into account.
    		/// </summary>
    		/// <returns></returns>
    		Vector3D GetTotalGravity();
    		/// <summary>
    		/// Gets the basic ship speed in meters per second, for when you just need to know how fast you're going.
    		/// </summary>
    		/// <returns></returns>
    		double GetShipSpeed();
    		/// <summary>
    		/// Determines the linear velocities in meters per second and angular velocities in radians per second.
    		/// Provides a more accurate representation of the directions and axis speeds.
    		/// </summary>
    		MyShipVelocities GetShipVelocities();
    		/// <summary>
    		/// Gets information about the current mass of the ship.
    		/// </summary>
    		/// <returns></returns>
    		MyShipMass CalculateShipMass();
    		/// <summary>
    		/// Attempts to get the world position of the nearest planet. This method is only available when a ship is
    		/// within the gravity well of a planet.
    		/// </summary>
    		/// <param name="position"></param>
    		/// <returns></returns>
    		bool TryGetPlanetPosition(out Vector3D position);
    		/// <summary>
    		/// Attempts to get the elevation of the ship in relation to the nearest planet. This method is only available
    		/// when a ship is within the gravity well of a planet.
    		/// </summary>
    		/// <param name="detail"></param>
    		/// <param name="elevation"></param>
    		/// <returns></returns>
    		bool TryGetPlanetElevation(MyPlanetElevation detail, out double elevation);
    	}
    }
    
    That should help.
     
    • Informative Informative x 1
  6. Elfi Wolfe Apprentice Engineer

    Messages:
    498
    Find local gravity
    Code:
            double FindGravity() {
                var shipControl = new List<IMyShipController>();
                GridTerminalSystem.GetBlocksOfType(shipControl);
                if (shipControl.Count < 1) { return 0; }
                return shipControl[0].GetNaturalGravity().Length() / 9.81;
            }
    autogyro

    http://forums.keenswh.com/threads/aligning-ship-to-planet-gravity.7373513/#post-1286885461

    Now for effective thrust for ion/atmo you need MaxEffectiveThrust() but that is not yet in.
    you can use a work around as long as the override is 1.0001% or greater
    Code:
                //for (int i = 0; i < thrusters.Count; ++i) normalThrust += thrusters[i].MaxEffectiveThrust;
                for (int i=0; i<thrusters.Count; ++i) {
                    if (thrusters[i].GetValueFloat("Override") > 1.0001){
                        normalThrust += thrusters[i].CurrentThrust * 100 / thrusters[i].GetValueFloat("Override");
                    }
                }
    Thrust needed to maintain current velocity (not position)
    Code:
                float thrustNeeded = (float)(massShip * normalGravity * 9.81);
    Here is my code to adjust velocity to move torward a target alttitude.
    to maintain current altitude just feed in current altitude into target or change (target - seaLevelAltitude) to 0
    vLimit is the limit of up or down velocity allowed
    target is desired altitude
    seaLevelAltitude is current altitude.
    velocityGravity is local natural gravity
    tempA is the max acceleration the ship can do after removing thrust needed to maintain current velocity
    double availableThrust = Math.Max(maxThrust - thrustNeeded, 0);
    double tempA = MathHelper.Clamp(availableThrust / massShip, 0, vLimit / 2);
    Code:
                    if (seaLevelAltitude < target - 5) {
                        //targetV = MathHelper.Clamp(Math.Sqrt(Math.Abs((target - seaLevelAltitude-velocityGravity) * normalGravity * 9.81)), 0d, vLimit);
                        targetV = MathHelper.Clamp(Math.Sqrt(tempAG * Math.Abs(target - seaLevelAltitude - velocityGravity)), 0, vLimit);
                    }
                    else if (seaLevelAltitude > target + 5) {
                        if (surfaceAltitude < (heightCockpit + 100 + velocityGravity * velocityGravity / tempA)) {
                            //landing
                            targetV = -Math.Max(Math.Sqrt(Math.Abs(MathHelper.Clamp((surfaceAltitude - heightCockpit - 12.5), 0d, 100) * tempA)), 1d);
                        }
                        else targetV = -MathHelper.Clamp(Math.Sqrt(0.7 * tempA * Math.Abs(seaLevelAltitude - target + velocityGravity)), 0, vLimit);
                    }
    
    Ops forgot thrust code. give me 10 minutes

    Code:
                //Normal Drive
                if (thrusters.Count > 0 && requestedThrust > 0) {
                    thrustApply = Math.Min(requestedThrust, normalThrust);
                    requestedThrust -= thrustApply;
                }
                float normalThrustPer = (float)(100 * thrustApply / normalThrust);
                if (normalThrustPer < 1.0001) { normalThrustPer = 1.0001f; }
                for (int i = 0; i < thrusters.Count; ++i) {
                    thrusters[i].SetValueFloat("Override", normalThrustPer);
                }
     
    Last edited: Nov 22, 2016
    • Informative Informative x 1
  7. gothosan Junior Engineer

    Messages:
    723
    I will try to play around with this as soon as I get home.
    Thanks
    --- Automerge ---
    Its nice but sadly alone does not help me enough.. Still thanks :)

    I don't understand from where normalGravity variable is, also why to multiply it by 9.81? isn't it alone representing current gravity strength?
    Does it need to be assigned via the FindGravity method?
     
  8. Elfi Wolfe Apprentice Engineer

    Messages:
    498
    Thus will give the acceleration due to natural gravity.
    shipControl[0].GetNaturalGravity().Length();

    NormalGravity was a var that was holding G instead of m/s2

    So try
    float thrustNeeded = (float)(massShip *shipcontroller.GetNaturalGravity().Length(); );
    --- Automerge ---
    Doh

    Thrust is mass * acceleration.

    N = kg * m/s2

    1g = 9.81 m/s2. (in Space Engineer)
     
    Last edited: Nov 23, 2016
    • Informative Informative x 1
  9. gothosan Junior Engineer

    Messages:
    723
    thrust sould be mass * acceleration no?
     
  10. DS_Marine Apprentice Engineer

    Messages:
    494
    I have to ask why do you want to manually override the thrusters instead of just using the inertia dampeners?
     
  11. gothosan Junior Engineer

    Messages:
    723
    I actually use inertia dampners, I want to use minimal thrusters but if the sat is being hit or moved in any way i want it to auto adjust so it wont fall..
    --- Automerge ---
    by the way whats the difference between LengthSquared() and Length when getting gravity vector?
    --- Automerge ---
    Okay, I figured out how to get how much thrust is produced and how much is needed at different altitudes.
    If I'm not mistaken there should be a way to sort thrusters by their direction so no special names needed right?
    I'm working now on the thrust control method :)
    After that I'll have a look for gyro control since its needed too
     
  12. Wicorel Senior Engineer

    Messages:
    1,243
    I have the code for that in my craft control script. Check for the THRUSTER region of code (Recommend using Visual Studio to edit code).
     
    • Like Like x 1
  13. gothosan Junior Engineer

    Messages:
    723
    Thank you very much
    I'll have a look there :)
     
  14. Elfi Wolfe Apprentice Engineer

    Messages:
    498
    here is what I use to find out which grav generator is up or down in reference to natural gravity.
    you should be able to use that to find out which thrusters are facing down at that time.
    Code:
     
    //cs is a control station
    Vector3D grav = cs.GetNaturalGravity();
    
                  for (int i = 0; i < gravDrive.Count; ++i) {
                        for (int j = 0; j < masses.Count; ++j) {
                            if (gravDrive[i].IsPositionInRange(masses[j].GetPosition())) {
                                Base6Directions.Direction dir = gravDrive[i].WorldMatrix.GetClosestDirection(grav);
                                switch (dir) {
                                    case Base6Directions.Direction.Up:
                                        gravDrivePos.Add(gravDrive[i]);
                                        break;
                                    case Base6Directions.Direction.Down:
                                        gravDriveNeg.Add(gravDrive[i]);
                                        break;
                                }
                            }
                        }
                    }
    
     
  15. DS_Marine Apprentice Engineer

    Messages:
    494
    Check your velocity. If non-zero, turn on all thrusters. Otherwise just leave down-facing thrusters on...
     
  16. gothosan Junior Engineer

    Messages:
    723
    That's one idea however out of down thrusters I want to keep on only the minimal needed for holding in gravity well, better power conservation than letting all down thrusters on.
    The satellite has 10 down facing ion thrusters, 6 small and 4 large, at some altitudes just 1 large is enough to hold, at the 6 small ones are enough and they consume less power.

    Now this is the code I wrote to try and sort thrusters by directions:
    Code:
                Vector3D gravity = RC_Unit.GetNaturalGravity();
                Base6Directions.Direction dir;
                for(int i = 0; i < allThrusters.Count; i++)
                {
                    dir = allThrusters[i].WorldMatrix.GetClosestDirection(gravity);
                    switch(dir)
                    {
                        case Base6Directions.Direction.Up:
                            upFaceThrusters.Add(allThrusters[i]);
                            break;
                        case Base6Directions.Direction.Down:
                            downFaceThrusters.Add(allThrusters[i]);
                            break;
                        case Base6Directions.Direction.Forward:
                            forwardFaceThrusters.Add(allThrusters[i]);
                            break;
                        case Base6Directions.Direction.Backward:
                            backwardFaceThrusters.Add(allThrusters[i]);
                            break;
                        case Base6Directions.Direction.Right:
                            rightFaceThrusters.Add(allThrusters[i]);
                            break;
                        case Base6Directions.Direction.Left:
                            leftFaceThrusters.Add(allThrusters[i]);
                            break;
                    }
                }
    Its been called at Boot() when getting all blocks and on Main I echo the number of downfacing thrusters, however it actually find 16 insted of 10.
    Attached sat pictures:
    1)
    [​IMG]

    2)
    [​IMG]
    --- Automerge ---
    I guess a possible solution to the thruster part could be special names and since the script is designed only for this satellite that
    might not be such a bad idea but I still prefer a more elegant solution...
     
  17. Wicorel Senior Engineer

    Messages:
    1,243
    I find the directions based on the orientation of a block such as a remote control or cockpit.

    Your code will have problems if the ship is not exactly aligned to gravity. Including, for example, if it is pasted up-side-down.
     
  18. gothosan Junior Engineer

    Messages:
    723
    I guess I'll resort for special names for thrusters..
    Now I need to figure out what to do with the gyroscope so it will auto align to gravity..
    --- Automerge ---
    I have few problems with the following code:
    Code:
            public void ThrustControlModule(string state)
            {           
                currentThrust = 0f;
                for(int i = 0; i < downFaceThrusters.Count; i++)
                {
                    currentThrust = +downFaceThrusters[i].CurrentThrust;
                }
    
                totalMass = RC_Unit.CalculateShipMass().TotalMass;
    
                neededThrust = (float)(totalMass * RC_Unit.GetNaturalGravity().Length() / 9.81f);
               
                if (currentThrust > neededThrust + thrustOffset)
                {
                    MsgBox("Ok", true);
                }
                else if(currentThrust < neededThrust)
                {
                    //if (!downFaceThrusters[thrusterIndex].IsWorking) downFaceThrusters[thrusterIndex].ApplyAction(ON_ACTION);               
                    //if (thrusterIndex > downFaceThrusters.Count) thrusterIndex = 0;
    
                }
                MsgBox("Current thrust is: " + currentThrust + NLCR + "Needed thrust is: " + neededThrust, true);
            }
    I test the satellite at altitude of 15km, at that altitude two large ion thrusters are enough to hold it with a current mass of 50,000kg.
    However I get a wierd data output saying current thrust is 0 when only two large thrusters are on and at other times it show other wierd numbers.
    What am I doing wrong? How can I fix it so it conserve energy by not having all down facing thrusters on when only some are enough?
     
  19. Decker_MMIV Trainee Engineer

    Messages:
    29
    Could be that the code does not actually accumulate all current thrust, but only uses the last thruster's value.

    I suppose this is what you want:
    Code:
        currentThrust   +=   downFaceThrusters[i].CurrentThrust;
    which is the same as:
    Code:
        currentThrust   =   currentThrust  +  downFaceThrusters[i].CurrentThrust;
     
    • Agree Agree x 1
  20. gothosan Junior Engineer

    Messages:
    723
    I'm thinking of a different approach of maybe getting each thruster max thrust and check it against needed thrust so it will decide which to keep on and which to turn off..
    But I still didn't figure out the part of the gyroscope...
     
  21. Wicorel Senior Engineer

    Messages:
    1,243
    I have code to do all of this. So does Elfi.

    Take a look at our scripts on the workshop.
     
  22. gothosan Junior Engineer

    Messages:
    723
    I have tried to look there but still did not understand...
     
  23. Wicorel Senior Engineer

    Messages:
    1,243
    Ok, I understand. the code can be quite complex.

    Do you want to use my code? I can instruct you how to do that.

    Or do you want to figure out how to create your own code ? please ask questions so we can help you.
     
  24. gothosan Junior Engineer

    Messages:
    723
    I am trying to incorporate it into my own code along with on/off switch so during maintenance of the satellite it won't try to balance while connected to maintenance ship, and in that would probably fight the pilot.
     
  25. Wicorel Senior Engineer

    Messages:
    1,243
    By "It" I assume you mean the gyro code from my examples.

    You call GyroMain() each run to do the auto-level. if you don't want to do it, calls gyrosoff() (to stop any leveling currently in progress) and don't call GyroMain().
     
  26. gothosan Junior Engineer

    Messages:
    723
    I will try that
     
  27. Elfi Wolfe Apprentice Engineer

    Messages:
    498
    neededThrust = (float)(totalMass * RC_Unit.GetNaturalGravity().Length() / 9.81f);
    GetNaturalGravity is in m/s2 so I think this should be
    neededThrust = (float)(totalMass * RC_Unit.GetNaturalGravity().Length());
     
  28. gothosan Junior Engineer

    Messages:
    723
    Can it work with single gyroscope?
    Do I have to use the loop?
    --- Automerge ---
    Thanks will test this :)
     
  29. Wicorel Senior Engineer

    Messages:
    1,243
    Yes, it will work with a single gyro.

    What do you mean by loop?

    You have to call GyroMain() to update the gyro settings. You should do this as often as possible if you want them to update.
     
  30. gothosan Junior Engineer

    Messages:
    723
    Code has a loop in it.
    I slightly modified the code and will test when I get home.
    And anyway turning the timer to update every tick :)
    --- Automerge ---
    I modified the code a bit and tested it in creative at altitude of 15km above earthlike planet.
    Spwaned a new satellite and tilted a bit before pasting.
    Result: Had to chase the satellite as it begun to fall down and only when I clicked a button on the rotating door (it hold a display and 3 other buttons on the other side)
    the satellite stabilized itself.
    The opening button send an argument to the script which unlock the rotor, rotate, and once in position lock the safety again.
    Current code:
    Code:
            void GyroStabilizerOff()
            {
                gyro.SetValueBool("Override", false);
            }
    
            void GyroStabilizerOn()
            {
                Matrix or;
                RC_Unit.Orientation.GetMatrix(out or);
                Vector3D down;
                down = or.Down;
                Vector3D grav = RC_Unit.GetNaturalGravity();
                grav.Normalize();
                gyro.Orientation.GetMatrix(out or);
                var localDown = Vector3D.Transform(down, MatrixD.Transpose(or));
                var localGrav = Vector3D.Transform(grav, MatrixD.Transpose(gyro.WorldMatrix.GetOrientation()));
                //Since the gyro ui lies, we are not trying to control yaw,pitch,roll but rather we 
                //need a rotation vector (axis around which to rotate) 
                var rot = Vector3D.Cross(localDown, localGrav);
                double ang = rot.Length();
                ang = Math.Atan2(ang, Math.Sqrt(Math.Max(0.0, 1.0 - ang * ang)));
                if (double.IsNaN(ang))
                { // not in gravity
                    gyro.SetValueBool("Override", false);
                    return;
                }
                if (ang < minAngleRad)
                { // close enough 
                    gyro.SetValueBool("Override", false);
                    //continue;
                }
                //WriteToLCD("\nAuto-Level:Off level: " + (ang * 180.0 / 3.14).ToString("0.000") + " deg");
                double ctrl_vel = gyro.GetMaximum<float>("Yaw") * (ang / Math.PI) * CTRL_COEFF;
                ctrl_vel = Math.Min(gyro.GetMaximum<float>("Yaw"), ctrl_vel);
                ctrl_vel = Math.Max(0.01, ctrl_vel);
                rot.Normalize();
                rot *= ctrl_vel;
                gyro.SetValueFloat("Pitch", (float)rot.GetDim(0));
                gyro.SetValueFloat("Yaw", -(float)rot.GetDim(1));
                gyro.SetValueFloat("Roll", -(float)rot.GetDim(2));
                gyro.SetValueFloat("Power", 1.0f);
                gyro.SetValueBool("Override", true);
    
            }
    
    Its called from Main via these lines:
    Code:
            void Main(string argument)
            {
                if (isFirstRun) Boot();
    
                lightDriver.Check_Screen(0);
                currentAngle = rotor.Angle;
                CheckDoor();
                UpdateElevation();
                UpdatePowerLvl();
                //CheckSpeed();
                ThrustControlModule();
    
                if (gyroStabilizer) GyroStabilizerOn();
                else if (!gyroStabilizer && gyro.GetValueBool("Override") == true) GyroStabilizerOff();
    .
    .
    .
    I guess that tiny problem accured since I've pasted it as opposed to launch it from the ground..
     
Thread Status:
This last post in this thread was made more than 31 days old.