Esempio n. 1
0
        private void UpdatePredictionPI()
        {
            // velcity relative to the target is the minus of the velocity relative to the vessel
            // (The PID moves the vessel to zero in the target frame)
            Omega = -ac.vessel.angularVelocity;

            UpdateError();

            // see https://archive.is/NqoUm and the "Alt Hold Controller", the acceleration PID is not implemented so we only
            // have the first two PIDs in the cascade.
            for (int i = 0; i < 3; i++)
            {
                MaxAlpha[i] = ControlTorque[i] / ac.vesselState.MoI[i];
                // scale the LD the user inputs to get the actual LD we use
                // (this was determined entirely empirically by seeing that vessels with appx 1000x range of MaxAlpha
                // needed a roughly 10x different LD, so by scaling here, we produce a user tunable which should be
                // fairly constant across a large range of vessels)
                double effLD = LD * Math.Pow(MaxAlpha[i], 1.0 / 3.0);
                double Gain  = Math.Sqrt(0.5 * MaxAlpha[i] / effLD);
                if (Math.Abs(errorVector[i]) <= 2 * effLD)
                {
                    // linear ramp down of acceleration
                    TargetOmega[i] = Gain * errorVector[i];
                }
                else
                {
                    // v = - sqrt(2 * F * x / m) is target stopping velocity based on distance
                    TargetOmega[i] = Math.Sqrt(2 * MaxAlpha[i] * (Math.Abs(errorVector[i]) - effLD)) * Math.Sign(errorVector[i]);
                }

                if (useStoppingTime)
                {
                    MaxOmega[i] = MaxAlpha[i] * maxStoppingTime;
                    if (useFlipTime)
                    {
                        MaxOmega[i] = Math.Max(MaxOmega[i], Math.PI / minFlipTime);
                    }
                    TargetOmega[i] = MuUtils.Clamp(TargetOmega[i], -MaxOmega[i], MaxOmega[i]);
                }
            }

            if (useControlRange && errorTotal * Mathf.Rad2Deg > rollControlRange)
            {
                TargetOmega[1] = 0;
                Pid[1].ResetI();
            }

            for (int i = 0; i < 3; i++)
            {
                Pid[i].Ki = Ki;
                Pid[i].Kp = Kp / TimeWarp.CurrentRate;
                Pid[i].Kd = Kd;

                Actuation[i]    = Pid[i].Update(Omega[i] / MaxAlpha[i], TargetOmega[i] / MaxAlpha[i], 1.0);
                TargetTorque[i] = Actuation[i] * ControlTorque[i]; // for display
            }
        }
Esempio n. 2
0
        public void UpdatePhi()
        {
            Transform vesselTransform = ac.vessel.ReferenceTransform;

            // 1. The Euler(-90) here is because the unity transform puts "up" as the pointy end, which is wrong.  The rotation means that
            // "forward" becomes the pointy end, and "up" and "right" correctly define e.g. AoA/pitch and AoS/yaw.  This is just KSP being KSP.
            // 2. We then use the inverse ship rotation to transform the requested attitude into the ship frame.
            Quaternion deltaRotation = Quaternion.Inverse(vesselTransform.transform.rotation * Quaternion.Euler(-90, 0, 0)) * ac.RequestedAttitude;

            // get us some euler angles for the target transform
            Vector3d ea    = deltaRotation.eulerAngles;
            double   pitch = ea[0] * UtilMath.Deg2Rad;
            double   yaw   = ea[1] * UtilMath.Deg2Rad;
            double   roll  = ea[2] * UtilMath.Deg2Rad;

            // law of cosines for the "distance" of the miss in radians
            phiTotal = Math.Acos(MuUtils.Clamp(Math.Cos(pitch) * Math.Cos(yaw), -1, 1));

            // this is the initial direction of the great circle route of the requested transform
            // (pitch is latitude, yaw is -longitude, and we are "navigating" from 0,0)
            Vector3d temp = new Vector3d(Math.Sin(pitch), Math.Cos(pitch) * Math.Sin(-yaw), 0);

            temp = temp.normalized * phiTotal;

            // we assemble phi in the pitch, roll, yaw basis that vessel.MOI uses (right handed basis)
            Vector3d phi = new Vector3d(
                MuUtils.ClampRadiansPi(temp[0]),    // pitch distance around the geodesic
                MuUtils.ClampRadiansPi(roll),
                MuUtils.ClampRadiansPi(temp[1])     // yaw distance around the geodesic
                );

            phi.Scale(ac.AxisState);

            if (useInertia)
            {
                phi -= ac.inertia;
            }

            phiVector = phi;
        }
Esempio n. 3
0
            void descend()
            {
                Quaternion courseCorrection = Quaternion.identity;

                // we aim for parachute break point with half deploy time for opening, which we can anticipate
                breakDiff = targetInfo.backwardDifference - (core.landing.deployChutes ? 0.5D * parachuteInfo.undeployedDistance : 0);

                status = String.Format("Holding planned descent attitude, break diff={0:F1}", breakDiff);

                String logs = String.Format("Atmo Correction alt:{0:F0}, speed hor:{1:F0}, AoA: {2:F1}, dist:{3:F0}", vesselState.altitudeASL.value, vesselState.speedSurfaceHorizontal.value, vesselState.AoA.value, targetInfo.forwardDistance);


                double backwardCorrection = breakDiff / targetInfo.forwardDistance;

                logs += String.Format(", target back:{0:F0} corr:{1:F4} break:{2:F0}", targetInfo.backwardDifference, backwardCorrection, breakDiff);


                if (targetInfo.isValid)
                {
                    double AoA = TrajectoriesConnector.API.AoA.Value;
                    //if we are less than 0°-60° turned on entry or 0-30° otherwise, simply turn more or less to hit target
                    if (!TrajectoriesConnector.API.isBelowEntry() && Math.Abs(backwardCorrection) > 0.02)
                    {
                        AoA = MuUtils.Clamp(AoA - Math.Sign(backwardCorrection) * 0.5, 120d, 180d, out aeroClamp, out _);
                        if (Math.Abs(TrajectoriesConnector.API.AoA.Value - AoA) > 0.1)
                        {
                            TrajectoriesConnector.API.AoA = AoA;
                            logs += String.Format(", changed AoA=>{0:F1}", AoA);
                        }
                    }
                    else if (Math.Abs(backwardCorrection) > 0.02)
                    {
                        AoA = MuUtils.Clamp(AoA - Math.Sign(backwardCorrection) * 0.5, 150d, 180d, out aeroClamp, out _);
                        if (TrajectoriesConnector.API.AoA != AoA)
                        {
                            TrajectoriesConnector.API.AoA = AoA;
                            logs += String.Format(", changed AoA=>{0:F1}", AoA);
                        }
                    }
                    if (aeroClamp && (core.thrust.targetThrottle != 0 || backwardCorrection > 0.03))
                    {
                        core.thrust.targetThrottle = Mathf.Clamp01((float)(gee / vesselState.limitedMaxThrustAccel * backwardCorrection)); // set thrust at 1G for 10% over target => early corrections, but slow enough for Trajectories
                        logs   += String.Format(", reverse thrust=>{0:P0}", core.thrust.targetThrottle);
                        status += ", +THRUST";
                    }
                    else if (!aeroClamp)
                    {
                        core.thrust.targetThrottle = 0; // safeguard, actually backwardCorrection should be 0 before Angle gets reduced
                    }
                }

                float rollForTarget = 0;

                // roll plannedOrientation towards target if we have signifikant lift
                if (vesselState.lift > 1)
                {
                    rollForTarget = -Mathf.Asin((float)(2.0 * targetInfo.normalDifference / targetInfo.distanceTarget.magnitude
                                                        * vesselState.mass * vesselState.speedSurface / (targetInfo.TimeTillImpact * vesselState.lift))) * Mathf.Rad2Deg;
                    rollForTarget = Mathf.Clamp(rollForTarget, -30, 30);
                }

                logs += String.Format(", normalDiff: {0:F0}, time: {1:F0}s, rollAngle={2:F1}", targetInfo.normalDifference, targetInfo.TimeTillImpact, rollForTarget);
                if (Mathf.Abs(rollForTarget) < 0.0005 || targetInfo.normalDifference < 50)
                {
                    rollForTarget = 0;                                                                         //neglect very small differences
                }
                if (Mathf.Abs(rollForTarget) > 0 && TrajectoriesConnector.API.isBelowEntry())
                {
                    status          += String.Format(", roll towards target with {0:F1}", rollForTarget);
                    courseCorrection = Quaternion.AngleAxis(rollForTarget, Vector3.forward);
                }
                Debug.Log(logs);

                Quaternion plannedOrientation = (Quaternion)TrajectoriesConnector.API.PlannedOrientation();

                core.attitude.attitudeTo(courseCorrection * plannedOrientation, AttitudeReference.SURFACE_VELOCITY, this);
            }