Example #1
0
        /// <summary>
        /// Changes the angle of the pendulums and calculates the corrections for the feedback controllers.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeAngle(object sender, ElapsedEventArgs e)
        {
            if (DateTime.Now.Subtract(dateTime).TotalSeconds > WaitTimeForCalculation)
            {
                if (!initializeFeedbackControllers)
                {
                    pid  = new PID(kp, ki, kd, maxOutput);
                    adrc = new ADRC_PD(r, c, b, hModifier, kp, kd, maxOutput);

                    this.BeginInvoke((Action)(() =>
                    {
                        label1.Text = "Correction State: True";
                    }));

                    initializeFeedbackControllers = true;
                }

                if (useADRC)
                {
                    currentOutput = adrc.Calculate(SetPoint, currentAngle);
                }
                else
                {
                    currentOutput = pid.Calculate(SetPoint, currentAngle);
                }


                fileWriter.WriteLine(counter + "," + currentOutput + "," + currentAngle);

                counter++;

                PreviousAngles.Add((float)currentAngle);
                PreviousOutputs.Add((float)currentOutput);

                if (counter > FourierTransform.FourierMemory)
                {
                    PreviousAngles.RemoveAt(0);
                    PreviousOutputs.RemoveAt(0);
                }
            }

            Random rand = new Random();

            double noise = rand.NextDouble() * NoiseFactor * (rand.Next(0, 1) * 2 - 1);
            double invertedPendulumAngle = 0;

            invertedPendulumAngle = invertedPendulum.Calculate(-currentOutput);

            currentAngle = (invertedPendulumAngle + noise);
        }
Example #2
0
        /// <summary>
        /// Changes the angle of the pendulums and calculates the corrections for the feedback controllers.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeAngle(object sender, ElapsedEventArgs e)
        {
            if (DateTime.Now.Subtract(dateTime).TotalSeconds > WaitTimeForCalculation)
            {
                if (!initializeFeedbackControllers)
                {
                    pid  = new PID(kp, ki, kd, maxOutput);
                    adrc = new ADRC_PD(r, c, b, hModifier, kp, kd, maxOutput);

                    initializeFeedbackControllers = true;
                }

                correctionState = true;
                outputPID       = pid.Calculate(SetPoint, anglePID);
                outputADRC      = adrc.Calculate(SetPoint, angleADRC);

                pidFileWriter.WriteLine(pidCounter + "," + outputPID + "," + anglePID);
                adrcFileWriter.WriteLine(adrcCounter + "," + outputADRC + "," + angleADRC);

                pidCounter++;
                adrcCounter++;

                ADRCAngle.Add((float)angleADRC);
                PIDAngle.Add((float)anglePID);

                ADRCOutput.Add((float)outputADRC);
                PIDOutput.Add((float)outputPID);

                if (ADRCAngle.ToArray().Length > FourierTransform.FourierMemory)
                {
                    ADRCAngle.RemoveAt(0);
                    PIDAngle.RemoveAt(0);
                    ADRCOutput.RemoveAt(0);
                    PIDOutput.RemoveAt(0);
                }
            }

            Random rand = new Random();

            double noise = rand.NextDouble() * NoiseFactor * (rand.Next(0, 1) * 2 - 1);

            double tempAnglePID  = (invertedPendulumPID.Step(-outputPID) * 180 / Math.PI + noise);   // % 360;
            double tempAngleADRC = (invertedPendulumADRC.Step(-outputADRC) * 180 / Math.PI + noise); // % 360;

            anglePID  = tempAnglePID;
            angleADRC = tempAngleADRC;
        }
Example #3
0
    void yawUpdate()
    {
        // input
        float yaw = (transform.parent.localEulerAngles.z < 180f) ? transform.parent.localEulerAngles.z : transform.parent.localEulerAngles.z - 360;

        // yaw PID
        Vector3 force = -1 * transform.right * yawPid.Calculate(Time.deltaTime, yaw);

        yawError = yawPid.error;
        YawForce = force.magnitude;

        // add force
        _rigidBody.AddForceAtPosition(force, _thrusterCluster1WorldPosition);
        _rigidBody.AddForceAtPosition(force, _thrusterCluster2WorldPosition);

        // draw debug
        Debug.DrawLine(_thrusterCluster1WorldPosition, _thrusterCluster1WorldPosition + (-1) * force, Color.yellow);
        Debug.DrawLine(_thrusterCluster2WorldPosition, _thrusterCluster2WorldPosition + (-1) * force, Color.yellow);
    }
Example #4
0
    void pitchUpdate()
    {
        // input
        float pitch = (transform.parent.localEulerAngles.x < 180f) ? transform.parent.localEulerAngles.x : transform.parent.localEulerAngles.x - 360;

        // picth PID
        Vector3 force = transform.forward * pitchPid.Calculate(Time.deltaTime, pitch);

        pitchError = pitchPid.error;
        PitchForce = force.magnitude;

        // add force
        _rigidBody.AddForceAtPosition(force, _thrusterCluster1WorldPosition);
        _rigidBody.AddForceAtPosition(force, _thrusterCluster2WorldPosition);

        // draw debug
        Debug.DrawLine(_thrusterCluster1WorldPosition, _thrusterCluster1WorldPosition + (-1) * force, Color.yellow);
        Debug.DrawLine(_thrusterCluster2WorldPosition, _thrusterCluster2WorldPosition + (-1) * force, Color.yellow);
    }
Example #5
0
    void rollUpdate()
    {
        // input
        float roll = (transform.parent.localEulerAngles.y < 180f) ? transform.parent.localEulerAngles.y : transform.parent.localEulerAngles.y - 360;

        // roll PID
        Vector3 force = transform.forward * rollPid.Calculate(Time.deltaTime, roll);

        rollError = rollPid.error;
        RollForce = force.magnitude;

        // add force
        _rigidBody.AddForceAtPosition(-force, _thrusterCluster1WorldPosition);
        _rigidBody.AddForceAtPosition(force, _thrusterCluster2WorldPosition);

        // draw debug
        Debug.DrawLine(_thrusterCluster1WorldPosition, _thrusterCluster1WorldPosition + (-1) * force, Color.yellow);
        Debug.DrawLine(_thrusterCluster2WorldPosition, _thrusterCluster2WorldPosition + (-1) * force, Color.yellow);
    }
Example #6
0
    void FixedUpdate()
    {
        if (StaticDataAccess.config == null)
        {
            Debug.LogWarning("StaticDataAccess.config not found");
            return;
        }
        if (StaticDataAccess.config.input == null)
        {
            Debug.LogWarning("StaticDataAccess.config.input not found");
            return;
        }

        if (StaticDataAccess.config.input.GetBtnReset())
        {
            transform.position = startPos;
            transform.rotation = startRot;
            rb.velocity        = Vector3.zero;
            rb.angularVelocity = Vector3.zero;

            if (lipo != null)
            {
                lipo.ChargeTo(lipo.maxVoltage);
            }
        }

        if (StaticDataAccess.config.input.GetBtnFlip())
        {
            RaycastHit rayHit;
            if (Physics.Raycast(transform.position, Vector3.down, out rayHit, LayerMask.GetMask("Terrain")))
            {
                transform.position = rayHit.point + Vector3.up * 3.0f;
            }
            else
            {
                transform.position += Vector3.up * 5.0f;
            }
            transform.rotation = Quaternion.identity;
            rb.velocity        = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
        }

        float throttle = StaticDataAccess.config.input.GetAxisThrottle();
        float roll     = StaticDataAccess.config.input.GetAxisRoll();
        float pitch    = StaticDataAccess.config.input.GetAxisPitch();
        float yaw      = StaticDataAccess.config.input.GetAxisYaw();

        throttle = Mathf.Clamp01(throttle + idleThrottle);
        roll     = rateProfile.ApplyRoll(roll) * Mathf.Deg2Rad;
        pitch    = rateProfile.ApplyPitch(pitch) * Mathf.Deg2Rad;
        yaw      = rateProfile.ApplyYaw(yaw) * Mathf.Deg2Rad;

        pidRoll.ApplyProfile(pidProfile, PIDAxis.Roll);
        pidPitch.ApplyProfile(pidProfile, PIDAxis.Pitch);
        pidYaw.ApplyProfile(pidProfile, PIDAxis.Yaw);

        Vector3 localRot = transform.InverseTransformVector(rb.angularVelocity);
        float   rollOut  = pidRoll.Calculate(-localRot.z, roll);
        float   pitchOut = pidPitch.Calculate(localRot.x, pitch);
        float   yawOut   = pidYaw.Calculate(localRot.y, yaw);

        Vector3 force  = Vector3.zero;
        Vector3 torque = Vector3.zero;

        if (lipo == null)
        {
            force  = Vector3.up * throttle * thrust;
            torque = new Vector3(pitch, yaw, -roll);
        }
        else
        {
            float thrCurrent = 0.0f;
            float rotCurrent = 0.0f;
            if (powertrain == null)
            {
                thrCurrent = Mathf.Abs(throttle * 200);
                rotCurrent = new Vector3(pitch, yaw, -roll).magnitude * 20;
            }
            else
            {
                thrCurrent = powertrain.throttleCurrentCurve.Evaluate(throttle);
                // might need to tweak the scale
                rotCurrent = powertrain.throttleCurrentCurve.Evaluate(new Vector3(pitch, yaw, -roll).magnitude / 30.0f);
            }
            lipo.expectedCurrent = thrCurrent + rotCurrent;
            if (lipo.expectedCurrent > 0)
            {
                float thrFraction  = thrCurrent / lipo.expectedCurrent;
                float rotFraction  = rotCurrent / lipo.expectedCurrent;
                float power        = lipo.actualCurrent * lipo.totalVoltage;
                float groundEffect = 0.0f;
                if (groundEffectFactor > 0)
                {
                    RaycastHit rayHit;
                    if (Physics.Raycast(transform.position, Vector3.down, out rayHit, groundEffectHeight, LayerMask.GetMask("Terrain")))
                    {
                        groundEffect = (groundEffectHeight - rayHit.distance) * groundEffectFactor / groundEffectHeight;
                    }
                }

                if (powertrain == null)
                {
                    force  = 0.017f * Vector3.up * power * thrFraction * (1 + groundEffect);
                    torque = 0.01f * new Vector3(pitchOut, yawOut, -rollOut) * power * rotFraction;
                }
                else
                {
                    force  = 0.025f * Vector3.up * power * thrFraction * (1 + groundEffect);
                    torque = 0.07f * new Vector3(pitchOut, yawOut, -rollOut) * power * rotFraction;
                }
            }
        }

        if (propwashFactor > 0)
        {
            Vector2 forw2d   = new Vector2(transform.forward.x, transform.forward.z);
            Vector2 vel2d    = new Vector2(rb.velocity.x, rb.velocity.z);
            float   propwash = force.magnitude * propwashFactor * (1 - Vector2.Dot(forw2d.normalized, vel2d.normalized)) / (0.1f * vel2d.magnitude + 1.5f);
            if (vel2d.magnitude < 2.0f)
            {
                // fixes too much propwash while hovering
                propwash *= vel2d.magnitude + 0.05f;
            }
            quadMesh.localEulerAngles = new Vector3(
                UnityEngine.Random.Range(-1.0f, 1.0f),
                UnityEngine.Random.Range(-1.0f, 1.0f),
                UnityEngine.Random.Range(-1.0f, 1.0f)
                ) * propwash;
        }
        else
        {
            quadMesh.localEulerAngles = Vector3.zero;
        }

        float aoaSine = Vector3.Dot(transform.forward, rb.velocity.normalized);
        float drag    = Mathf.Lerp(areaFront, areaTop, Mathf.Abs(aoaSine)) * rb.velocity.sqrMagnitude * Cd;

        rb.drag = drag;
        if (torque.magnitude < 0.1f)
        {
            rb.angularDrag = rotDrag;
        }
        else
        {
            rb.angularDrag = rotDrag / 5.0f / Mathf.Max(1.0f, torque.magnitude);
        }

        rb.AddRelativeForce(force);
        rb.AddRelativeTorque(torque);
    }