예제 #1
0
            private double GetBrakingDistanceThreshold(double shipAcceleration, Vector3D shipVelocityVec)
            {
                double forceSum = GetBrakingForce();

                //some arbitrary number that will stop NaN cases
                if (forceSum == 0)
                {
                    return(1000d);
                }

                double mass = referenceBlock.CalculateShipMass().PhysicalMass;

                //Echo($"Mass: {mass.ToString()}");
                double maxDeceleration       = forceSum / mass;
                double effectiveDeceleration = maxDeceleration - shipAcceleration;
                double wantedDeceleration    = effectiveDeceleration * BURN_THRUST_PERCENTAGE;
                //Echo($"Decel: {deceleration.ToString()}");

                // If speed mod
                double maxSpeed = MAX_SPEED;

                if (shipVelocityVec.LengthSquared() > MAX_SPEED * MAX_SPEED)
                {
                    maxSpeed = shipVelocityVec.Length();
                }

                //cushion to account for discrete time errors
                double safetyCushion = maxSpeed * timeMaxCycle * SafetyCushionConstant;

                //derived from: vf^2 = vi^2 + 2*a*d
                //added for safety :)
                double distanceToStop = shipVelocityVec.LengthSquared() / (2 * wantedDeceleration) + safetyCushion;

                return(distanceToStop);
            }
예제 #2
0
        double GetBrakingAltitudeThreshold()
        {
            double forceSum = 0;

            foreach (IMyThrust thisThrust in brakingThrusters)
            {
                forceSum += thisThrust.MaxEffectiveThrust;
            }

            if (forceSum == 0)
            {
                return(1000d); //some arbitrary number that will stop NaN cases
            }

            //Echo($"Force: {forceSum.ToString()}");
            //Echo($"Speed: {downSpeed.ToString()}");

            double mass = referenceBlock.CalculateShipMass().PhysicalMass;

            //Echo($"Mass: {mass.ToString()}");
            double deceleration = (forceSum / mass - gravityVecMagnitude) * burnThrustPercentage; //Echo($"Decel: {deceleration.ToString()}");

            double safetyCushion = maxSpeed * timeMaxCycle * SafetyCushionConstant;               //cushion to account for discrete time errors

            //derived from: vf^2 = vi^2 + 2*a*d
            double distanceToStop = shipVelocityVec.LengthSquared() / (2 * deceleration) + safetyCushion + altitudeSafetyCushion; //added for safety :)

            return(distanceToStop);
        }
예제 #3
0
            double GetShipMass()
            {
                double totalMass = rc.CalculateShipMass().TotalMass;  // ship total mass including cargo mass
                double baseMass  = rc.CalculateShipMass().BaseMass;   // mass of the ship without cargo
                double cargoMass = totalMass - baseMass;              // mass of the cargo

                return(baseMass + (cargoMass / inventoryMultiplier)); // the mass the game uses for physics calculation
            }
            private double calculateGravityForce()
            {
                double gravityVectorLength = myShipController.GetNaturalGravity().Length();
                float  currentMass         = myShipController.CalculateShipMass().TotalMass;

                return(gravityVectorLength * currentMass);
            }
예제 #5
0
    private void UpdateMass()
    {
        var mass = shipController.CalculateShipMass();

        baseMass  = mass.BaseMass;
        totalMass = mass.TotalMass;
    }
            /// <summary>
            /// returns the optimal max speed based on available braking thrust and ship mass
            /// </summary>
            /// <param name="thrustList">Thrusters to use</param>
            /// <param name="distance">current distance to target location</param>
            /// <returns>optimal max speed (may be game max speed)</returns>
            public double CalculateOptimalSpeed(List <IMyTerminalBlock> thrustList, double distance)
            {
                //
                //            Echo("#thrusters=" + thrustList.Count.ToString());
                if (thrustList.Count < 1)
                {
                    return(thisProgram.wicoControl.fMaxWorldMps);
                }

                MyShipMass myMass;

                myMass = tmShipController.CalculateShipMass();
                double maxThrust = thisProgram.wicoThrusters.calculateMaxThrust(thrustList);
                double maxDeltaV = maxThrust / myMass.PhysicalMass;
                // Magic..
                double optimalV, secondstozero, stoppingM;

                optimalV = ((distance * .75) / 2) / (maxDeltaV); // determined by experimentation and black magic
                                                                 //            Echo("COS");
                do
                {
                    //                Echo("COS:DO");
                    secondstozero = optimalV / maxDeltaV;
                    stoppingM     = optimalV / 2 * secondstozero;
                    if (stoppingM > distance)
                    {
                        optimalV *= 0.85;
                    }
                    //                Echo("stoppingM=" + stoppingM.ToString("F1") + " distance=" + distance.ToString("N1"));
                }while (stoppingM > distance);
                //            Echo("COS:X");
                return(optimalV);
            }
예제 #7
0
            public void Update(Vector3D target)
            {
                MatrixD transpose = MatrixD.Transpose(rc.WorldMatrix);

                Vector3D meToTarget = rc.WorldMatrix.Translation - target;
                Vector3D localError = Vector3D.TransformNormal(meToTarget, transpose);

                localError.Y = 0;
                if (localError.X > -0.5 && localError.X < 0.5)
                {
                    localError.X = 0;
                }
                if (localError.Z > -0.5 && localError.Z < 0.5)
                {
                    localError.Z = 0;
                }

                float correction = (float)forwardPID.Control(localError.Z);
                float force      = correction * rc.CalculateShipMass().TotalMass;

                float    rightLeft     = (float)anglePID.Control(-localError.X);
                Vector3D localVelocity = Vector3D.TransformNormal(rc.GetShipVelocities().LinearVelocity, transpose);
                float    angle         = -rightLeft;

                if (localVelocity.Z < 0)
                {
                    angle *= -1;
                }

                foreach (Wheel w in wheels)
                {
                    IMyMotorSuspension wheel = w.block;
                    if (first)
                    {
                        Vector3D center = Vector3D.TransformNormal(rc.CenterOfMass - rc.GetPosition(), transpose);
                        Vector3D local  = Vector3D.TransformNormal(wheel.GetPosition() - rc.GetPosition(), transpose);
                        wheel.InvertSteer      = (local.Z > center.Z);
                        wheel.InvertPropulsion = (wheel.Orientation.Left != rc.Orientation.Forward);
                        wheel.Brake            = false;
                    }

                    if (wheel.Steering)
                    {
                        wheel.SetValueFloat("Steer override", angle);
                    }

                    if (wheel.Propulsion)
                    {
                        float maxForce = w.maxForce;
                        if (maxForce <= 0)
                        {
                            continue;
                        }
                        float percent = MathHelper.Clamp(force / maxForce, -1, 1);
                        force -= percent * maxForce;
                        wheel.SetValueFloat("Propulsion override", percent);
                    }
                }
                first = false;
            }
 public Program()
 {
     // The constructor, called only once every session and
     // always before any other method is called. Use it to
     // initialize your script.
     //
     // The constructor is optional and can be removed if not
     // needed.
     //
     // It's recommended to set Runtime.UpdateFrequency
     // here, which will allow your script to run itself without a
     // timer block.
     Runtime.UpdateFrequency = UpdateFrequency.Update1;
     g         = GridTerminalSystem.GetBlockWithName("Gyro") as IMyGyro;
     sc        = GridTerminalSystem.GetBlockWithName("Cockpit") as IMyShipController;
     lcd       = GridTerminalSystem.GetBlockWithName("LCD") as IMyTextPanel;
     thrusters = new List <IMyThrust>();
     GridTerminalSystem.GetBlockGroupWithName("Thrusters").GetBlocksOfType <IMyThrust>(thrusters);
     hDamp        = false;
     manualAlt    = true;
     vDamp        = false;
     targAltitude = GetAltitude();
     mass         = sc.CalculateShipMass().PhysicalMass;
     curSpeed     = 0;
     lastHeading  = sc.WorldMatrix.Forward;
 }
예제 #9
0
            public void ApplyAccel(Vector3D accel)
            {
                if (accel.Equals(Vector3D.Zero, 0.1))
                {
                    accel = Vector3D.Zero;
                }

                Vector3D thrust = accel * rc.CalculateShipMass().TotalMass;

                foreach (IMyThrust t in thrusters)
                {
                    if (!t.IsFunctional)
                    {
                        continue;
                    }

                    float outputThrust = (float)Vector3D.Dot(t.WorldMatrix.Forward, thrust);
                    if (outputThrust > 0)
                    {
                        float outputProportion = MathHelper.Clamp(outputThrust / t.MaxEffectiveThrust, minThrust / t.MaxThrust, 1);
                        t.ThrustOverridePercentage = outputProportion;
                        thrust -= t.WorldMatrix.Forward * outputProportion * t.MaxEffectiveThrust;
                    }
                    else
                    {
                        t.ThrustOverride = minThrust;
                    }
                }
            }
예제 #10
0
        double CalculateRequiredThrust()
        {
            var mass           = controlBlock.CalculateShipMass().TotalMass;
            var requiredThrust = mass * gravityStrength;

            return(requiredThrust);
        }
예제 #11
0
            private bool Travel()
            {
                double distToTarget = GetDistanceToTarget();

                if (distToTarget < 2 * shipCenterToEdge)
                {
                    return(true);
                }

                bool isEnd       = false;
                bool shouldBrake = CheckBrake();

                if (shouldBrake)
                {
                    ManageBrake();
                    if (timeSpentStationary > SHUTDOWN_TIME)
                    {
                        Debug("timeSpentStationary", timeSpentStationary);
                        isEnd = true;
                    }
                }
                else
                {
                    float shipMass         = referenceBlock.CalculateShipMass().PhysicalMass;
                    float speed            = (float)referenceBlock.GetShipSpeed();
                    float secondsUntilVmax = 1;
                    float minLimitToZero   = 1 / 100;
                    float maxLimitPercent  = 98 / 100;
                    // F = m*a
                    // v_t = a_0*t + v_0 => a_0 = (v_t - v_0) / t
                    // F = m * (v_t - v_0) / t
                    float maxForceRequiered     = shipMass * (maxInitialSpeed - speed) / secondsUntilVmax;
                    float percentForceRequiered = maxForceRequiered / GetAcceleratingForce();
                    if (percentForceRequiered > maxLimitPercent)
                    {
                        percentForceRequiered = maxLimitPercent;
                    }
                    if (percentForceRequiered < minLimitToZero)
                    {
                        percentForceRequiered = 0F;
                    }

                    GetThrusters(ThrustersFlag.Accelerating).ForEach(t => t.ThrustOverridePercentage = percentForceRequiered);
                }

                return(isEnd);
            }
예제 #12
0
            public static int GetThrustCapacityRemaining(List <IMyThrust> blocks, IMyShipController shipController, Action <string> Echo)
            {
                //TODO: Need to calculate this
                float localGravity = 9.81f;
                int   newtonsRequiredToLiftShip = (int)(shipController.CalculateShipMass().TotalMass *localGravity);
                float maximumThrustInNewtons    = BlockUtils.GetSumOfBlockAttribute <IMyThrust>(b => b.MaxEffectiveThrust, blocks);

                int percent = (int)(newtonsRequiredToLiftShip / maximumThrustInNewtons * 100);

                return(percent);
            }
예제 #13
0
            public void CheckForMassChange()
            {
                var Masses = cockpit.CalculateShipMass();

                shipMass = Masses.PhysicalMass; //In kg
                if (previousShipMass != shipMass)
                {
                    GatherBasicData();
                }
                previousShipMass = shipMass;
            }
예제 #14
0
    public override string Get(Dictionary <string, int> storage)
    {
        IMyShipController c = owner.gts.GetBlockWithName(COCKPIT_NAME) as IMyShipController;
        int    m            = (int)(c.CalculateShipMass().TotalMass / 1000.0);
        string s            = m.ToString();

        if (vPadWidth <= 0)
        {
            return(s);
        }
        return(PadLeft(s, vPadWidth));
    }
예제 #15
0
            private void UdjustSuspensionStrength()
            {
                float gravityFactor            = (float)_controller.GetNaturalGravity().Length() / 9.81f;
                float truckCurrentMass         = _controller.CalculateShipMass().PhysicalMass *gravityFactor;
                float massToWheelsDifference   = truckCurrentMass / _suspensions.Count;
                float _truckSuspensionStrength = (float)Math.Sqrt(massToWheelsDifference / _suspensionSoftnessFactor);

                SuspensionStrengthChangedEventArgs args = new SuspensionStrengthChangedEventArgs
                {
                    Strength = _truckSuspensionStrength
                };

                ChangeTruckSuspensionStrength?.Invoke(this, args);
            }
        //disconnects the car from any connector, releases the hand brake, takes the batteries off recharge and sets the dampeners
        void disconnect()
        {
            float currentMass = controller.CalculateShipMass().PhysicalMass;
            float massRatio   = currentMass / maxMass;

            //we only want to allow the connectors to unlock if the max mass is not surpassed
            if (massRatio <= 1)
            {
                for (int i = 0; i < wheels.Count; i++)
                {
                    wheels[i].setStrenght(massRatio);
                }
            }
        }
예제 #17
0
        public bool Update()
        {
            if (Controller != null)
            {
                //Masses of ship
                val = Controller.CalculateShipMass().PhysicalMass;

                if (val != Value)
                {
                    Value = val;
                    return(true);
                }
            }
            return(false);
        }
            void UpdateTelemetry()
            {
                prevSpeed = currSpeed;
                currAccl  = (currSpeed = sc.GetShipSpeed()) - prevSpeed;

                gravity = (gravityStrength = sc.GetNaturalGravity().Length()) / 9.81;

                if (shipMassUpdateTick < Pgm.totalTicks)
                {
                    shipMassUpdateTick = Pgm.totalTicks + TPS;
                    shipMass           = sc.CalculateShipMass();
                }
                shipWeight = gravityStrength * shipMass.PhysicalMass;                 // or -> shipMass.TotalMass

                prevAltitude = altitudeSurface;
                if (sc.TryGetPlanetElevation(MyPlanetElevation.Surface, out altitudeSurface))
                {
                    altitudeDiff = altitudeSurface - prevAltitude;
                }
                else
                {
                    altitudeSurface = altitudeDiff = double.NaN;
                }

                atmosphereDensity = parachute?.Atmosphere ?? float.NaN;

                if (null != downCamera)
                {
                    if (downCamera.CanScan(1000))
                    {
                        MyDetectedEntityInfo dei = downCamera.Raycast(1000);
                        double len = 0;
                        if (null != dei.HitPosition)
                        {
                            Vector3D hp = (Vector3D)dei.HitPosition;
                            len = (hp - downCamera.CubeGrid.GetPosition()).Length();
                        }
                        raycastName = dei.Name + "/" + len;                         //downCamera.CubeGrid.GetPosition(); //dei.HitPosition.ToString();
                    }
                    else
                    {
                        raycastName = downCamera.AvailableScanRange.ToString();
                    }
                }
            }
예제 #19
0
        public bool Update()
        {
            if (Controller != null)
            {
                //Masses of ship
                masses = Controller.CalculateShipMass();
                val    = masses.PhysicalMass - masses.BaseMass;
                if (masses.PhysicalMass == 0)
                {
                    val = 0;
                }

                if (val != Value)
                {
                    Value = val;
                    return(true);
                }
            }
            return(false);
        }
예제 #20
0
            public float CalculateThrustToHover()
            {
                var gravityDir = controller.GetNaturalGravity();
                var weight     = controller.CalculateShipMass().TotalMass *gravityDir.Length();
                var velocity   = controller.GetShipVelocities().LinearVelocity;

                gravityDir.Normalize();
                var gravityMatrix = Matrix.Invert(Matrix.CreateFromDir(gravityDir));

                velocity = Vector3D.Transform(velocity, gravityMatrix);


                if (Vector3.Transform(controller.WorldMatrix.GetOrientation().Down, gravityMatrix).Z < 0)
                {
                    return((float)(weight + weight * -velocity.Z));
                }
                else
                {
                    return(-(float)(weight + weight * -velocity.Z));
                }
            }
예제 #21
0
            private void CalculateLiftThrustUsage(IMyShipController controller, List <IMyThrust> thrusters)
            {
                float mass            = controller.CalculateShipMass().PhysicalMass;
                float gravityStrength = (float)(controller.GetNaturalGravity().Length() / 9.81);

                LiftThrustNeeded = (mass * (float)gravityStrength / 100) * 1000;

                Vector3 gravity = controller.GetNaturalGravity();


                LiftThrustAvailable = 0;
                thrusters.ForEach(thruster =>
                {
                    if (thruster.IsWorking)
                    {
                        Vector3D thrusterDirection = thruster.WorldMatrix.Forward;
                        double upDot         = Vector3D.Dot(thrusterDirection, Vector3.Normalize(gravity));
                        LiftThrustAvailable += (thruster.MaxEffectiveThrust * (float)upDot);
                    }
                });
            }
예제 #22
0
            private void CalculateStopDistance(IMyShipController controller, List <IMyThrust> thrusters)
            {
                float  mass = controller.CalculateShipMass().PhysicalMass;
                double stopThrustAvailable = 0;
                int    disabledThrusters   = 0;

                thrusters.ForEach(thruster =>
                {
                    if (!thruster.IsWorking)
                    {
                        disabledThrusters++;
                    }
                    if (thruster.IsFunctional)
                    {
                        stopThrustAvailable += thruster.MaxEffectiveThrust;
                    }
                });
                StopThrustersWarning = disabledThrusters > 0;
                double deacceleration = -stopThrustAvailable / mass;
                double currentSpeed   = controller.GetShipSpeed();

                StoppingTime     = (float)(-currentSpeed / deacceleration);
                StoppingDistance = (float)(currentSpeed * StoppingTime + (deacceleration * StoppingTime * StoppingTime) / 2.0f);
            }
예제 #23
0
            public bool CalculateHoverThrust(IMyShipController ShipController, List <IMyTerminalBlock> thrusters, out float atmoPercent, out float hydroPercent, out float ionPercent)
            {
                atmoPercent  = 0;
                hydroPercent = 0;
                ionPercent   = 0;
                double ionThrust   = calculateMaxThrust(thrusters, thrustion);
                double atmoThrust  = calculateMaxThrust(thrusters, thrustatmo);
                double hydroThrust = calculateMaxThrust(thrusters, thrusthydro);

                MyShipMass myMass;

                myMass = ShipController.CalculateShipMass();
                Vector3D vGrav       = ShipController.GetNaturalGravity();
                double   dGravity    = vGrav.Length() / 9.81;
                double   hoverthrust = myMass.PhysicalMass * dGravity * 9.810;

                if (atmoThrust > 0)
                {
                    if (atmoThrust < hoverthrust)
                    {
                        atmoPercent  = 100;
                        hoverthrust -= atmoThrust;
                    }
                    else
                    {
                        atmoPercent = (float)(hoverthrust / atmoThrust * 100);
                        if (atmoPercent > 0)
                        {
                            hoverthrust -= (atmoThrust * atmoPercent / 100);
                        }
                    }
                }
                //	Echo("ALeft over thrust=" + hoverthrust.ToString("N0"));

                if (ionThrust > 0 && hoverthrust > 0)
                {
                    if (ionThrust < hoverthrust)
                    {
                        ionPercent   = 100;
                        hoverthrust -= ionThrust;
                    }
                    else
                    {
                        ionPercent = (float)(hoverthrust / ionThrust * 100);
                        if (ionPercent > 0)
                        {
                            hoverthrust -= ((ionThrust * ionPercent) / 100);
                        }
                    }
                }
                //	Echo("ILeft over thrust=" + hoverthrust.ToString("N0"));

                if (hydroThrust > 0 && hoverthrust > 0)
                {
                    if (hydroThrust < hoverthrust)
                    {
                        hydroPercent = 100;
                        hoverthrust -= hydroThrust;
                    }
                    else
                    {
                        hydroPercent = (float)(hoverthrust / hydroThrust * 100);
                        if (hydroPercent > 0)
                        {
                            hoverthrust -= ((hydroThrust * hydroPercent) / 100);
                        }
                        ;
                    }
                }
                //	Echo("Atmo=" + ((atmoThrust * atmoPercent) / 100).ToString("N0"));
                //	Echo("ion=" + ((ionThrust * ionPercent) / 100).ToString("N0"));
                //	Echo("hydro=" + ((hydroThrust * hydroPercent) / 100).ToString("N0"));
                //	Echo("Left over thrust=" + hoverthrust.ToString("N0"));
                if (hoverthrust > 0)
                {
                    return(false);
                }
                return(true);
            }
예제 #24
0
    public void ProcessCalculations(IMyShipController pController)
    {
        mDirectionStatsList = new List <CGI_ThrusterDirectionStats>();
        double aPhysicalMass = pController.CalculateShipMass().PhysicalMass;


        Dictionary <Base6Directions.Direction, double> aLocalGravity = new Dictionary <Base6Directions.Direction, double>();

        if (COMPENSATE_GRAVITY)
        {
            /// this is the local gravity acceleration
            Vector3D aGravity = pController.GetNaturalGravity();

            Vector3D aUp      = pController.WorldMatrix.Up;
            Vector3D aLeft    = pController.WorldMatrix.Left;
            Vector3D aForward = pController.WorldMatrix.Forward;

            aLocalGravity[Base6Directions.Direction.Forward]  = aGravity.Dot(aForward);  // FORWARD;
            aLocalGravity[Base6Directions.Direction.Backward] = -aLocalGravity[Base6Directions.Direction.Forward];

            aLocalGravity[Base6Directions.Direction.Up]   = aGravity.Dot(aUp); // UP;
            aLocalGravity[Base6Directions.Direction.Down] = -aLocalGravity[Base6Directions.Direction.Up];

            aLocalGravity[Base6Directions.Direction.Left]  = aGravity.Dot(aLeft);  // UP;
            aLocalGravity[Base6Directions.Direction.Right] = -aLocalGravity[Base6Directions.Direction.Left];
        }


        foreach (KeyValuePair <Base6Directions.Direction, List <IMyThrust> > aPair in myThrustDirections)
        {
            CGI_ThrusterDirectionStats aDirectionStats = new CGI_ThrusterDirectionStats();

            Base6Directions.Direction aKey   = aPair.Key;
            List <IMyThrust>          aValue = aPair.Value;

            aDirectionStats.mDirection = aKey;

            foreach (IMyThrust aThruster in aValue)
            {
                if (aThruster.Enabled && aThruster.IsFunctional)
                {
                    aDirectionStats.mDirectionForceCurrent   += aThruster.CurrentThrust;
                    aDirectionStats.mDirectionForceEffective += aThruster.MaxEffectiveThrust;
                    aDirectionStats.mDirectionForceMax       += aThruster.MaxThrust;
                    aDirectionStats.mThrusters += 1;
                }
            }

            if (COMPENSATE_GRAVITY)
            {
                double aGravityDirectionForce = aLocalGravity[aKey] * aPhysicalMass;
                aDirectionStats.mDirectionForceCurrent   -= aGravityDirectionForce;
                aDirectionStats.mDirectionForceEffective -= aGravityDirectionForce;
                aDirectionStats.mDirectionForceMax       -= aGravityDirectionForce;
            }

            aDirectionStats.mAccelerationMax       = aDirectionStats.mDirectionForceMax / aPhysicalMass;
            aDirectionStats.mAccelerationEffective = aDirectionStats.mDirectionForceEffective / aPhysicalMass;
            aDirectionStats.mAccelerationCurrent   = aDirectionStats.mDirectionForceCurrent / aPhysicalMass;

            aDirectionStats.mEfficiency = aDirectionStats.mDirectionForceCurrent / aDirectionStats.mDirectionForceMax;

            mDirectionStatsList.Add(aDirectionStats);
        }
        ProcessVelocities(pController);
    }
예제 #25
0
            /// <summary>
            ///     Gathers the blocks that relate to the ship. This includes:<br />The cockpit, thrusters, gyros, (main)
            ///     connector.
            /// </summary>
            public void GatherBasicData()
            {
                if (!firstTime && !parent_program.scriptEnabled)
                {
                    parent_program.shipIOHandler.Echo(
                        "RE-INITIALIZED\nSome change was detected\nso I have re-checked ship data, " +
                        parent_program.your_title + ".");
                }


                cockpit = FindCockpit();
                if (cockpit != null)
                {
                    var Masses = cockpit.CalculateShipMass();
                    shipMass         = Masses.PhysicalMass; //In kg
                    previousShipMass = shipMass;
                }
                else
                {
                    parent_program.shipIOHandler.Error(
                        "The ship systems analyzer couldn't find some sort of cockpit or remote control.\nPlease check you have one of these, " +
                        parent_program.your_title + ".");
                }

                if (parent_program.Me.CubeGrid.GridSize == 0.5)
                {
                    isLargeShip = false;
                }
                else
                {
                    isLargeShip = true;
                }

                //myConnector = FindConnector();
                thrusters = FindThrusters();
                gyros     = FindGyros();


                var antenna_result = "";

                if (parent_program.enable_antenna_function)
                {
                    antenna_result = parent_program.antennaHandler.CheckAntenna();
                }
                if (!parent_program.errorState)
                {
                    if (firstTime)
                    {
                        parent_program.shipIOHandler.Echo("Waiting for orders, " + parent_program.your_title + ".\n");
                        if (!parent_program.extra_info)
                        {
                            parent_program.shipIOHandler.Echo("Ready for Waypoints.\n");
                        }

                        if (antenna_result != "")
                        {
                            parent_program.shipIOHandler.Echo(antenna_result);
                        }

                        if (parent_program.extra_info)
                        {
                            if (shipMass != 0)
                            {
                                parent_program.shipIOHandler.Echo("Mass: " + shipMass);
                            }
                            parent_program.shipIOHandler.Echo("Thruster count: " + thrusters.Count);
                            parent_program.shipIOHandler.Echo("Gyro count: " + gyros.Count);
                            parent_program.shipIOHandler.Echo("Main control: " + cockpit.CustomName);
                            parent_program.shipIOHandler.Echo("Is large ship: " + isLargeShip);
                            //if (parent_program.homeLocations.Count > 0) {
                            parent_program.shipIOHandler.OutputHomeLocations();
                            //}
                        }
                    }
                }

                Populate6ThrusterGroups();
                parent_program.shipIOHandler.EchoFinish();
                firstTime = false;
            }
        void GetMovementVectors(Vector3D target, IMyShipController controller, IMyTerminalBlock reference, float maxThrust, float maxSpeed, out Vector3D AutopilotMoveIndicator, ref Vector3D D, ref Vector3D I)
        {
            if (controller == null)
            {
                AutopilotMoveIndicator = Vector3D.Zero;
                return;
            }
            var      speed           = (float)(controller.GetShipVelocities().LinearVelocity - targetDrift).Length();
            Vector3D currentVelocity = controller.GetShipVelocities().LinearVelocity;
            float    aMax            = 0.8f * maxThrust / controller.CalculateShipMass().PhysicalMass;
            Vector3D desiredVelocity = targetDrift;
            Vector3D posError        = target - reference.WorldMatrix.Translation;
            var      distance        = (float)posError.Length();

            posError.Normalize();

            if (target != Vector3D.Zero)
            {
                float desiredSpeed = Math.Min((float)Math.Sqrt(2f * aMax * distance) * 0.01f * (100 - (float)targetDrift.Length()), maxSpeed);
                desiredSpeed     = Math.Min(distance * distance * 2f, desiredSpeed);
                desiredVelocity += posError * desiredSpeed;
            }

            Vector3D adjustVector = currentVelocity - targetDrift - VectorHelpers.VectorProjection(currentVelocity - targetDrift, desiredVelocity - targetDrift);

            if (adjustVector.Length() < (currentVelocity - targetDrift).Length() * 0.1)
            {
                adjustVector = Vector3.Zero;
            }

            Vector3D Error = (desiredVelocity - currentVelocity - adjustVector * 1) * 60 / (aMax * kRunEveryXUpdates);

            float kP = TP;
            float kI = TI;
            float kD = TD;

            if (Error.LengthSquared() > 1)
            {
                Error.Normalize();
            }
            else
            {
                kP = TP2;
                kI = TI2;
                kD = TD2;
            }

            if (D == Vector3.Zero)
            {
                D = Error;
            }

            AutopilotMoveIndicator = kP * Error + kD * (Error - D) * kInverseTimeStep + kI * I;

            // decrease speed when close and slow
            if (distance < 10 && speed < 10)
            {
                AutopilotMoveIndicator *= 0.5f;
            }

            if (AutopilotMoveIndicator.Length() > 1)
            {
                AutopilotMoveIndicator /= AutopilotMoveIndicator.Length();
            }

            I += Error * kRunEveryXUpdates;
            if (I.Length() > 5)
            {
                I *= 5 / I.Length();
            }
            D = Error;

            // if close enough, stop.
            if (targetDrift == Vector3D.Zero && distance < 0.25f && speed < 0.25f)
            {
                targetPosition         = Vector3.Zero;
                AutopilotMoveIndicator = Vector3.Zero;
                I = Vector3.Zero;
                D = Vector3.Zero;
            }
        }
예제 #27
0
        public void Main(string input)
        {
            lcds = SearchBlocksWithName <IMyTextPanel>(lcdSearchName);
            ClearOutput();

            if (input == "start")
            {
                Runtime.UpdateFrequency = UpdateFrequency.Update10;
                Autopilot = true;
            }

            IMyShipController controlBlock = (IMyShipController)GridTerminalSystem.GetBlockWithName(ShipControllerName);

            double altitude             = 0;
            bool   InsideNaturalGravity = controlBlock.TryGetPlanetElevation(MyPlanetElevation.Surface, out altitude);

            Vector3D velocity3D = controlBlock.GetShipVelocities().LinearVelocity;

            if (!InsideNaturalGravity)
            {
                if (Autopilot)
                {
                    WriteLine("Waiting for entering natural gravity");
                    if (input == "stop")
                    {
                        Autopilot = false;
                        WriteLine("Autopilot deactivated (manually)");
                    }
                }
                return;
            }
            else
            {
                if (Autopilot && AutoFall)
                {
                    if (!AutoFallUsed)
                    {
                        input        = "fall";
                        AutoFallUsed = true;
                    }
                }
            }

            List <IMyThrust> thrusters        = GetBlocksInGroup <IMyThrust>(HydrogenThrustersGroupName);
            ThrustController thrustController = new ThrustController(thrusters);

            gyros          = GetBlocksOfType <IMyGyro>();
            gyroController = new GyroController(controlBlock, gyros, Base6Directions.Direction.Down, RotationSpeedLimit);

            Vector3D gravity         = controlBlock.GetNaturalGravity();
            Vector3D position        = controlBlock.GetPosition();                   // ship coords
            double   gravityStrength = gravity.Length();                             // gravity in m/s^2
            double   totalMass       = controlBlock.CalculateShipMass().TotalMass;   // ship total mass including cargo mass
            double   baseMass        = controlBlock.CalculateShipMass().BaseMass;    // mass of the ship without cargo
            double   cargoMass       = totalMass - baseMass;                         // mass of the cargo
            double   actualMass      = baseMass + (cargoMass / InventoryMultiplier); // the mass the game uses for physics calculation
            double   shipWeight      = actualMass * gravityStrength;                 // weight in newtons of the ship
            double   velocity        = controlBlock.GetShipSpeed();                  // ship velocity
            double   brakeDistance   = CalculateBrakeDistance(gravityStrength, actualMass, altitude, thrustController.availableThrust, velocity);
            double   brakeAltitude   = StopAltitude + brakeDistance;                 // at this altitude the ship will start slowing Down

            if (Autopilot)
            {
                gyroController.Align(gravity);

                if (input == "fall")
                {
                    // This is a workaround to a game bug (ship speed greater than speed limit when free falling in natural gravity)
                    // Pros: your ship will not crash. Cons: you will waste a tiny amount of hydrogen.
                    thrustController.ApplyThrust(1);
                }

                if (altitude <= (brakeAltitude + AltitudeMargin))
                {
                    // BRAKE!!!
                    thrustController.ApplyFullThrust(); // Maybe just enable dampeners
                }

                if (altitude <= (StopAltitude + DisableMargin + AltitudeMargin))
                {
                    if (velocity < StopSpeed)
                    {
                        gyroController.Stop();
                        WriteLine("Autopilot deactivated (automatically)");
                    }

                    if (SmartDeactivation)
                    {
                        if (OldVelocity3D.X * velocity3D.X < 0 || OldVelocity3D.Y * velocity3D.Y < 0 || OldVelocity3D.Z * velocity3D.Z < 0)
                        {
                            gyroController.Stop();
                            WriteLine("Autopilot deactivated (automatically)");
                        }
                    }
                }
            }

            OldVelocity3D = velocity3D;

            if (input == "stop")
            {
                Runtime.UpdateFrequency = UpdateFrequency.None;
                gyroController.Stop();
                thrustController.Stop();
                WriteLine("Autopilot deactivated (manually)");
            }
        }
예제 #28
0
        private void TestMotionInput()
        {
            if (!EngineIsON)
            {
                return;
            }

            Vector3D moveInput = Cockpit.MoveIndicator;

            //ToLog("\nmoveInput: " + VectToStr(moveInput), true);

            InertiaDampeners = Cockpit.DampenersOverride;
            //ToLog("\nDampeners: " + InertiaDampeners.ToString(), true);

            Vector3D WorldSpeed  = Cockpit.GetShipVelocities().LinearVelocity;
            Vector3D WorldAngVel = Cockpit.GetShipVelocities().AngularVelocity;

            Vector3D Gravity      = Cockpit.GetNaturalGravity();
            Vector3D normVertical = -Vector3D.Normalize(Gravity);

            //матрица вращения в СО, связанную с вектором гравитации
            if (!PlanetMatrixReady)
            {
                Vector3D normForward = normVertical.Cross(Cockpit.WorldMatrix.Right);
                PlanetMatrix      = MatrixD.CreateWorld(Vector3D.Zero, normForward, normVertical);
                PlanetMatrixInv   = MatrixD.Invert(PlanetMatrix);
                PlanetMatrixReady = true;
            }

            Vector3D PlanetSpeed = Vector3D.Rotate(WorldSpeed, PlanetMatrixInv);
            //ToLog("\nSpeed 3D: " + VectToStr(PlanetSpeed), true);
            Vector3D PlanetAngularVelocity = Vector3D.Rotate(WorldAngVel, PlanetMatrixInv);

            //test!!!
            //Vector3D vForw = Vector3D.Rotate(Cockpit.WorldMatrix.Forward, PlanetMatrixInv);
            //ToLog("\nForw. test: " + VectToStr(vForw), true);

            Vector3D moveInputSign = Vector3D.Sign(moveInput);
            double   curAltitude, deltaAlt = 0;

            Cockpit.TryGetPlanetElevation(MyPlanetElevation.Surface, out curAltitude);
            if (InertiaDampeners)
            {
                DesiredSpeed.X = MaxSpeed * moveInputSign.X;
                if (AltitudeHoldMode)
                {
                    deltaAlt = Math.Abs(DesiredAltitude) * 0.01;
                    if (deltaAlt < 0.1)
                    {
                        deltaAlt = 0.1;
                    }
                    if (moveInputSign.Y != 0.0)
                    {
                        DesiredAltitude += deltaAlt * moveInputSign.Y;
                        if (DesiredAltitude < 0.0)
                        {
                            DesiredAltitude = 0;
                        }
                    }
                    deltaAlt = DesiredAltitude - curAltitude;
                    //ускорение потом вычислим, желаемая скорость для этого не нужна
                }
                DesiredSpeed.Y = MaxSpeed * moveInputSign.Y;

                if (CruiseControl)
                {
                    DesiredSpeed.Z += DeltaSpeed * moveInputSign.Z;
                }
                else
                {
                    DesiredSpeed.Z = MaxSpeed * moveInputSign.Z;
                }

                //DesiredSpeed = Vector3D.Sign(moveInput) * MaxSpeed;
            }
            else
            {
                //DesiredSpeed = PlanetSpeed;
                if (moveInput.X == 0d)
                {
                    DesiredSpeed.X = PlanetSpeed.X;
                }
                else
                {
                    DesiredSpeed.X = MaxSpeed * moveInputSign.X;
                }
                if (moveInput.Y == 0d)
                {
                    DesiredSpeed.Y = PlanetSpeed.Y;
                }
                else
                {
                    DesiredSpeed.Y = MaxSpeed * moveInputSign.Y;
                }
                if (moveInput.Z == 0d)
                {
                    DesiredSpeed.Z = PlanetSpeed.Z;
                }
                else
                {
                    if (CruiseControl)
                    {
                        DesiredSpeed.Z += DeltaSpeed * moveInputSign.Z;
                    }
                    else
                    {
                        DesiredSpeed.Z = MaxSpeed * moveInputSign.Z;
                    }
                }
            }
            DesiredSpeed = Vector3D.Clamp(DesiredSpeed, MaxSpeedMin, MaxSpeedMax);
            if (CruiseControl)
            {
                ToLog("\nСкорость: " + (-PlanetSpeed.Z).ToString("#0") + " / " + (-DesiredSpeed.Z).ToString("#0"), true);
            }
            else
            {
                ToLog("\nСкорость: " + (-PlanetSpeed.Z).ToString("#0"), true);
            }

            if (InertiaDampeners && AltitudeHoldMode)
            {
                ToLog("\nВысота: " + curAltitude.ToString("#0") + " / " + DesiredAltitude.ToString("#0"), true);
            }
            else
            {
                ToLog("\nВысота: " + curAltitude.ToString("#0"), true);
            }

            Vector3D SpeedDeviation = DesiredSpeed - PlanetSpeed;
            //ToLog("\nDes.spd: " + VectToStr(DesiredSpeed), true);
            //ToLog("\nSpd.dev: " + VectToStr(SpeedDeviation), true);

            //Z - вперед, X - вправо, Y - вверх
            Vector3D     DesiredAccelerations;
            const double SigmoidFactorAlpha = 0.5;

            DesiredAccelerations.X = Sigmoid(SpeedDeviation.X, SigmoidFactorAlpha) * CurrentRegimeAccel;
            DesiredAccelerations.Z = Sigmoid(SpeedDeviation.Z, SigmoidFactorAlpha) * CurrentRegimeAccel;
            if (AltitudeHoldMode && InertiaDampeners)
            {
                ToLog("\ndeltaAlt: " + deltaAlt.ToString("#0.000000"), true);
                //ToLog("\nPlanetSpeed.Y: " + PlanetSpeed.Y.ToString("#0.000000"), true);

                ////нужно такое ускорение, чтобы корабль остановился при нулевом отклонении по высоте
                //double absDeltaAlt = Math.Abs(deltaAlt);
                //if (absDeltaAlt >= 0.5)
                //{
                //    int signDeltaAlt = Math.Sign(deltaAlt);
                //    //минимальное расстояние, на котором мы еще успеем затормозить
                //    if (Math.Sign(PlanetSpeed.Y) != signDeltaAlt)
                //    {
                //        //удаляемся
                //        DesiredAccelerations.Y = CurrentRegimeAccel * signDeltaAlt;
                //        //ToLog("\nудаляемся", true);
                //    }
                //    else
                //    {
                //        //приближаемся, оценим тормозной путь
                //        double temp = 0.5 * PlanetSpeed.Y * PlanetSpeed.Y;
                //        double brakingDist = temp / CurrentRegimeAccel;
                //        //ToLog("\nbrakingDist: " + brakingDist.ToString("#0.00000"), true);

                //        if (absDeltaAlt > brakingDist)
                //        {
                //            //еще успеваем затормозить, поэтому даем максимальное ускорение
                //            DesiredAccelerations.Y = CurrentRegimeAccel * signDeltaAlt;
                //        }
                //        else
                //        {
                //            //уменьшаем ускорение
                //            DesiredAccelerations.Y = MathHelperD.Clamp(-temp / deltaAlt, -CurrentRegimeAccel, CurrentRegimeAccel);
                //        }
                //    }
                //}
                //else
                //{
                //    DesiredAccelerations.Y = Sigmoid(SpeedDeviation.Y, SigmoidFactorAlpha) * CurrentRegimeAccel;
                //    //ToLog("\n!!!", true);
                //}

                DesiredAccelerations.Y = CalcAccelToStopAtPos(deltaAlt, PlanetSpeed.Y, CurrentRegimeAccel, 0.5, 0.5);
            }
            else
            {
                DesiredAccelerations.Y = Sigmoid(SpeedDeviation.Y, SigmoidFactorAlpha) * CurrentRegimeAccel;
            }

            ToLog("\nDes.acc: " + VectToStr(DesiredAccelerations), true);

            //double PlanetElevation;
            //Cockpit.TryGetPlanetElevation(MyPlanetElevation.Surface, out PlanetElevation);

            double MaxDownThrust = 0;

            foreach (IMyThrust t in DownTrusters)
            {
                MaxDownThrust += t.MaxEffectiveThrust;
            }
            double ShipMass = Cockpit.CalculateShipMass().PhysicalMass;
            //ToLog("\nMax thr: " + MaxDownThrust.ToString("#0.0"), true);
            //ToLog("\nMass: " + ShipMass.ToString("#0.0"), true);

            double DesiredVertivalAcc = DesiredAccelerations.Y + Gravity.Length();

            if (DesiredVertivalAcc < 1.0)
            {
                DesiredVertivalAcc = 1.0;
            }
            ToLog("\nDes.vert.acc: " + DesiredVertivalAcc.ToString("#0.000"), true);

            double cosGravityToUp = normVertical.Dot(Cockpit.WorldMatrix.Up);
            double Thrust         = ShipMass * DesiredVertivalAcc / cosGravityToUp;
            //ToLog("\nThrust: " + Thrust.ToString("#0.000"), true);

            //раздадим на движки
            float ThrustFactor = (float)(Thrust / MaxDownThrust);

            ToLog("\nThr.factor: " + ThrustFactor.ToString("#0.000"), true);

            if (ThrustFactor > 1f)
            {
                ThrustFactor = 1f;
            }
            foreach (IMyThrust t in DownTrusters)
            {
                t.ThrustOverridePercentage = ThrustFactor;
            }

            //углы откладываются от вертикали, X - тангаж, Y - крен
            Vector2D DesiredAngles;

            DesiredAngles.X = Math.Atan2(DesiredAccelerations.Z, DesiredVertivalAcc);
            DesiredAngles.Y = Math.Atan2(DesiredAccelerations.X, DesiredVertivalAcc);
            DesiredAngles   = Vector2D.Clamp(DesiredAngles, MaxDeviationAngleMin, MaxDeviationAngleMax);
            ToLog("\nDes.angl: " + Vect2ToStr(DesiredAngles), true);

            double cosGravityToForward = normVertical.Dot(Cockpit.WorldMatrix.Forward);
            double cosGravityToRight   = normVertical.Dot(Cockpit.WorldMatrix.Left);
            //ToLog("\nCos(G) to F/R: " + cosGravityToForward.ToString("#0.000") + " / " + cosGravityToRight.ToString("#0.000"), true);
            Vector2D CurrentAngles;

            CurrentAngles.X = Math.Atan2(cosGravityToForward, cosGravityToUp);
            CurrentAngles.Y = Math.Atan2(cosGravityToRight, cosGravityToUp);
            ToLog("\nCur.angl: " + Vect2ToStr(CurrentAngles), true);

            //ошибка угла
            Vector2D AnglesDeviation = Vector2D.Clamp(NormAngles2D(DesiredAngles - CurrentAngles), MaxDeviationAngleMin, MaxDeviationAngleMax);

            ToLog("\nAngl.dev: " + Vect2ToStr(AnglesDeviation, "#0.00000"), true);

            Vector2D GyroSignals;

            ////демфируем сигнал при приближении отклонения к максимальному значению
            //GyroSignals.X = SignalDamper(AnglesDeviation.X, MaxDeviationAngle, CurrentAngles.X, MaxDeviationAngle, 0.5);
            //GyroSignals.Y = SignalDamper(AnglesDeviation.Y, MaxDeviationAngle, CurrentAngles.Y, MaxDeviationAngle, 0.5);

            ToLog("\nPAV: " + VectToStr(PlanetAngularVelocity), true);
            GyroSignals.X = CalcAccelToStopAtPos(AnglesDeviation.X, PlanetAngularVelocity.X, MaxAngularAcceleration, 0.5 * Math.PI / 180.0, 1);
            GyroSignals.Y = CalcAccelToStopAtPos(AnglesDeviation.Y, -PlanetAngularVelocity.Z, MaxAngularAcceleration, 0.5 * Math.PI / 180.0, 1);
            ToLog("\nGyroSignals: " + Vect2ToStr(GyroSignals, "#0.00000"), true);

            //раздадим на гороскопы
            GyroPitch = -(float)(GyroPithPID.Reaction(GyroSignals.X) * GyroFactor);
            GyroRoll  = (float)(GyroRollPID.Reaction(GyroSignals.Y) * GyroFactor);
            //GyroPitch = -(float)(AnglesDeviation.X * GyroFactor);
            //GyroRoll = (float)(AnglesDeviation.Y * GyroFactor);

            ToLog("\nGyro P/Y/R: " + GyroPitch.ToString("#0.000") + " / " + GyroYaw.ToString("#0.000") + " / " + GyroRoll.ToString("#0.000"), true);

            foreach (GyroDefinition g in Gyros)
            {
                SetGyroParams(g, true, GyroPitch, GyroYaw, GyroRoll);
            }
        }
예제 #29
0
    public void Main(string argument)
    {
        //Обработка команд с контроллера.
        DesiredElevation       += RemCon.MoveIndicator.Y / 5;
        DesiredForwardVelocity -= RemCon.MoveIndicator.Z / 5;

        //Обработка аргументов.
        if (argument != "")
        {
            switch (argument)
            {
            //Аргумент для полной остановки.
            case "Stop":
            {
                DesiredForwardVelocity = 0;
                break;
            }

            default:
                break;
            }
        }

        //Получаем и нормализуем вектор гравитации. Это наше направление "вниз" на планете.
        Vector3D GravityVector    = RemCon.GetNaturalGravity();
        Vector3D GravNorm         = Vector3D.Normalize(GravityVector);
        Vector3D MyVelocityVector = RemCon.GetShipVelocities().LinearVelocity;

        //получаем текущую высоту и вертикальную скорость и вес
        RemCon.TryGetPlanetElevation(MyPlanetElevation.Surface, out CurrentElevation);
        DeltaElevation = (float)(DesiredElevation - CurrentElevation);

        float VerticalVelocity = -(float)MyVelocityVector.Dot(GravNorm);

        // float Weight = (float)GravityVector.Length()*RemCon.CalculateShipMass().PhysicalMass;

        //Защита крафта от падений.
        //Защита от резкого роста высоты (при пролёте над оврагами, резкий спуск с горы).

        //Защита от разряда баттарей.
        foreach (IMyBatteryBlock bat in batList)
        {
            BatteryStored    += bat.CurrentStoredPower;
            BatteryMaxStored += bat.MaxStoredPower;
        }
        BatteryCharged = BatteryStored / (BatteryMaxStored / 100);

        if (BatteryCharged <= 8)
        {
            DesiredElevation = 0;
        }
        //Вывод сервисной информации.
        Display("", "infoLCD", true);
        Display("Speed: " + DesiredForwardVelocity + "\r\n", "infoLCD");
        Display("Height: " + DesiredElevation, "infoLCD");
        Display("DeltaElevation: " + DeltaElevation, "infoLCD");
        Display("BatteryCharged: " + BatteryCharged, "infoLCD");

        //Считаем косинус угла наклона крафта
        float TiltCos = (float)RemCon.WorldMatrix.Down.Dot(GravNorm);
        //Считаем тягу
        float Thrust = (float)((1 + (DeltaElevation * kV - VerticalVelocity) * kA) * GravityVector.Length() * RemCon.CalculateShipMass().PhysicalMass / TiltCos);

        if (Thrust <= 0)
        {
            Thrust = 1;
        }

        /*
         * float HoverCorrection = (DeltaElevation * kV - VerticalVelocity) * kA;
         * float Thrust = (float)(GravityVector.Length() * RemCon.CalculateShipMass().PhysicalMass * (1 + HoverCorrection) / TiltCos);
         * if (Thrust <= 0)
         *  Thrust = 1;
         *
         * Echo(""+ HoverCorrection + "\n" + TiltCos + "\n"+ thrList.Count+ "\n" + DeltaElevation + "\n" + VerticalVelocity); */

        Vector3D MyVelocityVectorNorm = Vector3D.Reject(MyVelocityVector, RemCon.WorldMatrix.Forward) / 10;

        if (MyVelocityVectorNorm.Length() > 1)
        {
            MyVelocityVectorNorm = Vector3D.Normalize(MyVelocityVectorNorm);
        }

        Vector3D ForwardInput = Vector3D.Normalize(Vector3D.Reject(RemCon.WorldMatrix.Forward, GravNorm)) * RemCon.MoveIndicator.Z;
        Vector3D LeftInput    = Vector3D.Normalize(Vector3D.Reject(RemCon.WorldMatrix.Left, GravNorm)) * RemCon.RollIndicator;

        //Управляем скоростью
        CurrentForwardVelocity    = MyVelocityVector.Dot(Vector3D.Normalize(Vector3D.Reject(RemCon.WorldMatrix.Forward, GravNorm)));
        ForwardAccel              = CurrentForwardVelocity - OldCurrentForwardVelocity;
        OldCurrentForwardVelocity = CurrentForwardVelocity;
        double VelocityDelta = DesiredForwardVelocity - CurrentForwardVelocity;

        double   VelocityFactor = (VelocityDelta * Tilt_kV - ForwardAccel) * Tilt_kA;
        Vector3D TiltCorrector  = -Vector3D.Normalize(Vector3D.Reject(RemCon.WorldMatrix.Forward, GravNorm)) * VelocityFactor;


        Vector3D AlignVector = Vector3D.Normalize(GravNorm + TiltCorrector + MyVelocityVectorNorm / 2 + (LeftInput) / 1.2);

        //Получаем проекции вектора прицеливания на все три оси блока ДУ.
        float PitchInput = -(float)AlignVector.Dot(RemCon.WorldMatrix.Forward);
        float RollInput  = (float)AlignVector.Dot(RemCon.WorldMatrix.Left);

        //На рыскание просто отправляем сигнал рыскания с контроллера. Им мы будем управлять вручную.
        float YawInput = RemCon.MoveIndicator.X;


        //для каждого гироскопа устанавливаем текущие значения по тангажу, крену, рысканию.
        foreach (IMyGyro gyro in gyroList)
        {
            gyro.GyroOverride = true;
            gyro.Yaw          = YawInput;
            gyro.Roll         = RollInput;
            gyro.Pitch        = PitchInput;
        }

        //раздаем тягу на движки

        foreach (IMyThrust thr in thrList)
        {
            thr.ThrustOverride = Thrust / thrList.Count;
        }
    }
        public void Update(double deltaTime)
        {
            if (!Enabled)
            {
                return;
            }

            //Reduces the target speed in relation to altitude.
            double height;
            double newTarget;

            if (descending)
            {
                if (controller.TryGetPlanetElevation(MyPlanetElevation.Surface, out height))
                {
                    if (height > TargetAltDescending)
                    {
                        newTarget = -((height - TargetAltDescending) / deceleration);
                    }
                    else
                    {
                        newTarget = ((TargetAltDescending - height) / deceleration);
                    }
                    if (newTarget < TargetSpeed)
                    {
                        AdaptiveTargetSpeed = TargetSpeed;
                    }
                    else
                    {
                        AdaptiveTargetSpeed = newTarget;
                    }
                    //screen.WriteText("\nGnd alt: " + height.ToString("n3"), true);
                }
            }
            else
            {
                if (controller.TryGetPlanetElevation(elevationType, out height))
                {
                    if (height > TargetAltAcending)
                    {
                        newTarget = -((height - TargetAltAcending) / deceleration);
                    }
                    else
                    {
                        newTarget = ((TargetAltAcending - height) / deceleration);
                    }
                    if (newTarget > TargetSpeed)
                    {
                        AdaptiveTargetSpeed = TargetSpeed;
                    }
                    else
                    {
                        AdaptiveTargetSpeed = newTarget;
                    }
                    //screen.WriteText("\nSea alt: " + height.ToString("n3"), true);
                }
                else
                {
                    //Failed at getting planet elevation, means we're not in gravity well.
                    if (DisableOnNaturalGravityExit && startedInNaturalGravity)
                    {
                        Stop();
                        return;
                    }
                }
            }



            //Mass/Gravity
            double mass    = controller.CalculateShipMass().PhysicalMass;
            double gravity = Vector3D.Dot(controller.GetNaturalGravity(), controller.WorldMatrix.GetOrientation().Down);             //TODO: Is this supposed to be down or dependent on selected thrusters?
            //mass *= 9.80665f; //Convert to newton.
            double weight = mass * gravity;

            //Speed
            var vel = controller.GetShipVelocities().LinearVelocity;

            if (forward == Base6Directions.Direction.Up)
            {
                Speed = (Vector3D.TransformNormal(vel, MatrixD.Transpose(controller.WorldMatrix))).Y;
            }
            else if (forward == Base6Directions.Direction.Down)
            {
                Speed = -(Vector3D.TransformNormal(vel, MatrixD.Transpose(controller.WorldMatrix))).Y;
            }
            else if (forward == Base6Directions.Direction.Forward)
            {
                Speed = -(Vector3D.TransformNormal(vel, MatrixD.Transpose(controller.WorldMatrix))).Z;
            }
            else if (forward == Base6Directions.Direction.Backward)
            {
                Speed = (Vector3D.TransformNormal(vel, MatrixD.Transpose(controller.WorldMatrix))).Z;
            }


            double difference     = AdaptiveTargetSpeed - Speed;
            double errorMagnitude = MathHelper.Clamp(difference / 5, -1, 1);             //More than 5 away from target = full thrust.


            float electricThrust    = GetElectricThrust(forward);
            float electricThrustRev = GetElectricThrust(reverse);

            float hydroThrust    = GetHydrogenThrust(forward);
            float hydroThrustRev = GetHydrogenThrust(reverse);



            //TODO: Calulate thrust needed, tanking speed into account. MAss isnt just kg * gravity when hurling towards earth. Need how many newtons it takes to reach a specific speed, 0 in this case.
            //That should work for liftoff as well.

            //a = (v1 - v0) / t
            //F = m * a

            //Time is 1.
            //F = m * (v1 - v0)

            //double thrustNeeded = mass * difference;
            //This is not more stable than what I did before.


            //screen.WriteText("\nTS: " + AdaptiveTargetSpeed.ToString("n3") + ", S: " + Speed.ToString("n3"), true);
            //screen.WriteText("\nerr " + errorMagnitude.ToString("n3"), true);
            ////screen.WriteText("\nneed " + thrustNeeded.ToString("n3"), true);
            //screen.WriteText("\nthr " + (electricThrust + hydroThrust).ToString("n3"), true);

            //Dividing by zero will happen here, but since it's float it will result in infinity instead of exception, which is fine.
            float thrustOverride      = MathHelper.Clamp((float)weight / electricThrust, 0, 1);        //Convert to percent
            float hydroThrustOverride = MathHelper.Clamp(((float)weight - electricThrust) / hydroThrust, 0, 1);

            float thrustOverrideRev      = 0;
            float hydroThrustOverrideRev = 0;

            float thrustExcess      = 0;
            float hydroThrustExcess = 0;

            thrustExcess      = 1 - thrustOverride;
            hydroThrustExcess = 1 - hydroThrustOverride;

            if (Speed < AdaptiveTargetSpeed)
            {
                thrustOverride      += thrustExcess * (float)errorMagnitude;
                hydroThrustOverride += hydroThrustExcess * (float)errorMagnitude;
            }
            else
            {
                //thrustOverride *= 1 - (float)errorMagnitude;
                //hydroThrustOverride *= 1 - (float)errorMagnitude;
                thrustOverride      *= 1 + (float)errorMagnitude;
                hydroThrustOverride *= 1 + (float)errorMagnitude;
            }



            thrustOverrideRev      = -MathHelper.Clamp((electricThrustRev * (float)errorMagnitude) / electricThrustRev, -1, 0);
            hydroThrustOverrideRev = -MathHelper.Clamp((hydroThrustRev * (float)errorMagnitude) / hydroThrustRev, -1, 0);

            //Not using h2 thruster if setting says so
            //if (electricThrust > mass) hydroThrustOverride = 0.000001f;



            //DEBUGLCD?.WritePublicText($"mass kg {mass2}\nmass n {mass.ToString("n3")}\ne thrust {thrust.ToString("n3")}\nh thrust {hydroThrust.ToString("n3")}\ne override {thrustOverride.ToString("n3")}\nh override {hydroThrustOverride.ToString("n3")}\ne excess {thrustExcess.ToString("n3")}\nh excess {hydroThrustExcess.ToString("n3")}\ndiff {difference.ToString("n3")}\nerr {errorMagnitude.ToString("n3")}\ngrav {gravity.ToString("n3")}\nelevation {elevation.ToString("n3")}");

            //Prevent setting thrust override to 0, as that turns it off.
            if (thrustOverride <= 0 || double.IsNaN(thrustOverride))
            {
                thrustOverride = 0.000001f;
            }
            if (hydroThrustOverride <= 0 || double.IsNaN(hydroThrustOverride))
            {
                hydroThrustOverride = 0.000001f;
            }

            if (thrustOverrideRev <= 0 || double.IsNaN(thrustOverrideRev))
            {
                thrustOverrideRev = 0.000001f;
            }
            if (hydroThrustOverrideRev <= 0 || double.IsNaN(hydroThrustOverrideRev))
            {
                hydroThrustOverrideRev = 0.000001f;
            }

            ThrustOverrideElectric = 0;

            for (int i = 0; i < electricThrusters[forward].Count; i++)
            {
                if (electricThrusters[forward][i].MaxEffectiveThrust / electricThrusters[forward][i].MaxThrust <= cutoff)
                {
                    electricThrusters[forward][i].ThrustOverridePercentage = 0.000001f;                                                                                                                       //If max effective trhust is less than 5%, don't use the thruster
                }
                else
                {
                    electricThrusters[forward][i].ThrustOverridePercentage = thrustOverride;
                    ThrustOverrideElectric += thrustOverride;
                }
            }

            for (int i = 0; i < hydrogenThrusters[forward].Count; i++)
            {
                hydrogenThrusters[forward][i].ThrustOverridePercentage = hydroThrustOverride;
            }

            //screen.WriteText("\novr-rev " + thrustOverrideRev.ToString("n3"), true);
            //screen.WriteText("\novr-hrev " + hydroThrustOverrideRev.ToString("n3"), true);

            for (int i = 0; i < electricThrusters[reverse].Count; i++)
            {
                if (electricThrusters[reverse][i].MaxEffectiveThrust / electricThrusters[reverse][i].MaxThrust <= cutoff)
                {
                    electricThrusters[reverse][i].ThrustOverridePercentage = 0.000001f;                                                                                                                       //If max effective trhust is less than 5%, don't use the thruster
                }
                else
                {
                    electricThrusters[reverse][i].ThrustOverridePercentage = thrustOverrideRev;
                    ThrustOverrideElectric += thrustOverrideRev;
                }
            }

            for (int i = 0; i < hydrogenThrusters[reverse].Count; i++)
            {
                hydrogenThrusters[reverse][i].ThrustOverridePercentage = hydroThrustOverrideRev;
            }

            ThrustOverrideElectric = ThrustOverrideElectric / (electricThrusters[forward].Count + electricThrusters[reverse].Count);
            ThrustOverrideHydrogen = hydroThrustOverride + hydroThrustOverrideRev;

            //screen.WriteText("\nTS: " + AdaptiveTargetSpeed.ToString("n3") + ", S: " + speed.ToString("n3"), true);
            //screen.WriteText("\nE: " + electricThrusters[forward].Count + ", ovr " + thrustOverride.ToString("n3") + ", thr " + electricThrust.ToString("n3"), true);
            //screen.WriteText("\nH " + hydrogenThrusters[forward].Count + ", ovr " + hydroThrustOverride.ToString("n3") + ", thr " + hydroThrust.ToString("n3"), true);
            //screen.WriteText("\nerr " + errorMagnitude.ToString("n3"), true);
        }