Esempio n. 1
0
        /// <summary>
        /// Creates a new <see cref="L6470"/> instance.
        /// </summary>
        /// <param name="ChipSelectPin">The number of the chip select pin for this device,
        /// using the BCM numbering scheme.</param>
        /// <param name="ResetPin">The number of the reset pin for this device, using the
        /// BCM numbering scheme.</param>
        /// <param name="StepAngle">The angle that a single motor step moves the motor shaft,
        /// in degrees</param>
        /// <param name="MaxCurrent">The max current the motor can sustain, per coil, in amps.</param>
        /// <remarks>
        /// As a quick note, the L6470's SPI spec actually *requires* that the chip select be
        /// put back to high after every byte, then pulled low again to read the next byte.
        /// I don't know why it works this way, but it does. The getters and setters will look
        /// different from the AMT22, where the chip select stays low for the entire exchange...
        /// but that's how it is!
        /// </remarks>
        public L6470(byte ChipSelectPin, byte ResetPin, double StepAngle, double MaxCurrent)
        {
            Spi             = new SpiDevice(ChipSelectPin, 1000000, SpiMode.Mode3, 0, 0, 0, 0);
            this.StepAngle  = StepAngle;
            this.MaxCurrent = MaxCurrent;

            // Reset the driver
            pinMode(ResetPin, PinMode.Output);
            digitalWrite(ResetPin, PinState.Low);
            Thread.Sleep(1);
            digitalWrite(ResetPin, PinState.High);
            Thread.Sleep(1);

            // Get the current config
            ushort      config = GetParam_16Bit(Register.Configuration);
            L6470Status status = GetStatus();

            // Set the overcurrent threshold
            byte overcurrentTheshold = GetClosestOvercurrentThreshold(MaxCurrent);

            SetParam_8Bit(Register.OvercurrentThreshold, overcurrentTheshold);

            // Default to 16 microsteps: SYNC_EN = 0, SYNC_SEL = 0, STEP_SEL = 4
            byte stepMode = (byte)(MicrostepMode._16PerStep);

            SetParam_8Bit(Register.StepMode, stepMode);

            // Default to a max speed of as high as it goes, I guess...
            ushort maxSpeed = 0x03FF;

            SetParam_16Bit(Register.MaximumSpeed, maxSpeed);

            // Set the full-step speed (the threshold at which it disables microstepping)
            // to a default of 300 RPM. That seems like a lot so it's probably a good
            // starting point.
            ushort fullStepSpeed = GetFormattedFullStepSpeed(300.0);

            SetParam_16Bit(Register.FullStepSpeed, fullStepSpeed);

            // Set the acceleration and deceleration to 500 RPM/sec.
            ushort acceleration = GetFormattedAcceleration(500.0);

            SetParam_16Bit(Register.Acceleration, acceleration);
            SetParam_16Bit(Register.Deceleration, acceleration);

            // Set the config register to the following defaults:
            // OSC_SEL and EXT_CLK = 0000; 16 MHz internal clock, no output
            // SW_MODE = 0; hard stop when the kill switch is thrown
            // EN_VSCOMP = 1; enabled
            // OC_SD = 1; enabled
            // POW_SR = 11; 530 V/us for maximum torque
            // F_PWM_INT and F_PWM_DEC = 000111; 62.5 kHz PWM output
            config = 0;
            //config |= (1 << 5); // Set EN_VSCOMP to 1
            config |= (1 << 7);    // Set OC_SD to 1
            config |= (0b11 << 8); // Set POW_SR to 530 V/us
            config |= ((byte)PwmFrequency._31_250 << 10);
            SetParam_16Bit(Register.Configuration, config);
        }
Esempio n. 2
0
        /// <summary>
        /// Immediately stops the motor, ignoring the deceleration curve,
        /// and disenages the coils. This is like an "EMERGENCY STOP!" function.
        /// This will block until the driver reports that the stop has finished
        /// and the system is now idle.
        /// </summary>
        public void HardHiZ()
        {
            byte[] buffer = { 0b10101000 };
            Spi.TransferData(buffer);

            // Wait for the HiZ to finish
            L6470Status status = GetStatus();

            while (status.IsBusy || status.BridgesActive)
            {
                Thread.Sleep(10);
                status = GetStatus();
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Immediately stops the motor, ignoring the deceleration curve,
        /// but keeps the coils engaged (holding). This will block until the driver
        /// reports that the stop has finished and the system is now idle.
        /// </summary>
        public void HardStop()
        {
            byte[] buffer = { 0b10111000 };
            Spi.TransferData(buffer);

            // Wait for the stop finish
            L6470Status status = GetStatus();

            while (status.IsBusy)
            {
                Thread.Sleep(10);
                status = GetStatus();
            }
        }
Esempio n. 4
0
        public void RefreshStatus_Click(object sender, RoutedEventArgs e)
        {
            int position = Encoder.GetPosition();

            ShaftPositionBox.Text = position.ToString();

            L6470Status status = Driver.GetStatus();

            CoilAStalledBox.Text      = (status.BridgeAStalled ? "YES" : "");
            CoilBStalledBox.Text      = (status.BridgeBStalled ? "YES" : "");
            OvercurrentBox.Text       = (status.OvercurrentDetected ? "YES" : "");
            ThermalShutdownBox.Text   = (status.ThermalShutdownTriggered ? "YES" : "");
            ThermalWarningBox.Text    = (status.ThermalWarningTriggered ? "YES" : "");
            UndervoltageBox.Text      = (status.UndervoltageDetected ? "YES" : "");
            UnknownCommandBox.Text    = (status.ReceivedUnknownCommand ? "YES" : "");
            LastCommandFailedBox.Text = (status.LastCommandFailed ? "YES" : "");
            MotorStateBox.Text        = status.MotorState.ToString();
            DirectionBox.Text         = status.Direction.ToString();
            KillSwitchTriggerBox.Text = (status.KillSwitchTriggered ? "YES" : "");
            KillSwitchActiveBox.Text  = (status.KillSwitchActive ? "YES" : "");
            IsBusyBox.Text            = (status.IsBusy ? "YES" : "");
            HiZBox.Text = (status.BridgesActive ? "YES" : "");
        }
Esempio n. 5
0
 private void CheckL6470State(L6470Status Status)
 {
     if (Status.BridgeAStalled)
     {
         throw new Exception($"Focus motor bridge A is stalled.");
     }
     if (Status.BridgeBStalled)
     {
         throw new Exception($"Focus motor bridge B is stalled.");
     }
     if (Status.OvercurrentDetected)
     {
         throw new Exception($"Focus motor exceeded its current limit.");
     }
     if (Status.ThermalShutdownTriggered)
     {
         throw new Exception($"Focus motor driver overheated.");
     }
     if (Status.UndervoltageDetected)
     {
         throw new Exception($"Focus motor fell below its motor voltage threshold.");
     }
 }
Esempio n. 6
0
        private void MovementLoop()
        {
            FocusMoveResult result;

            while (!StopMove)
            {
                // Check the current status and report any failures
                L6470Status status = Driver.GetStatus();
                try
                {
                    CheckL6470State(status);
                }
                catch (Exception ex)
                {
                    Driver.SoftHiZ();
                    MoveTask = null;
                    result   = new FocusMoveResult(false, ex.Message);
                    MoveFinished?.Invoke(this, result);
                    return;
                }

                // Get the current position and distance to the target
                int currentPosition = Encoder.GetPosition();
                int delta           = Math.Abs(currentPosition - DesiredPosition);

                // See which direction we're supposed to go, or if we're close enough
                MotorAction action = MotorAction.Stop;
                if (delta < TargetThreshold)
                {
                    action = MotorAction.Stop;
                }
                else if (DesiredPosition > currentPosition)
                {
                    action = MotorAction.Forward;
                    delta  = Math.Min(delta, UpperEncoderBound - BoundSafetyThreshold - currentPosition);
                }
                else if (DesiredPosition < currentPosition)
                {
                    action = MotorAction.Reverse;
                    delta  = Math.Min(delta, currentPosition - LowerEncoderBound - BoundSafetyThreshold);
                }

                // See if the move would take us out of bounds, and if so, don't do it!
                if (action == MotorAction.Forward && currentPosition >= (UpperEncoderBound - BoundSafetyThreshold))
                {
                    action = MotorAction.Stop;
                }
                else if (action == MotorAction.Reverse && currentPosition <= (LowerEncoderBound + BoundSafetyThreshold))
                {
                    action = MotorAction.Stop;
                }

                double newRpm = GetSpeedSetting(delta);

                // Perform the requested action
                switch (action)
                {
                // Shut it down and consider this move a success
                case MotorAction.Stop:
                    Driver.SoftHiZ();
                    MoveTask = null;
                    result   = new FocusMoveResult(true, null);
                    MoveFinished?.Invoke(this, result);
                    return;

                // Go forward if it isn't already going forward
                case MotorAction.Forward:
                    if (Driver.Direction == MotorDirection.Reverse ||
                        status.MotorState == MotorActivity.Stopped ||
                        newRpm != CurrentSpeed)
                    {
                        Driver.Direction    = MotorDirection.Forward;
                        Driver.DesiredSpeed = newRpm;
                        Driver.Run();
                        CurrentSpeed = newRpm;
                    }
                    break;

                // Go backward if it isn't already going backward
                case MotorAction.Reverse:
                    if (Driver.Direction == MotorDirection.Forward ||
                        status.MotorState == MotorActivity.Stopped ||
                        newRpm != CurrentSpeed)
                    {
                        Driver.Direction    = MotorDirection.Reverse;
                        Driver.DesiredSpeed = newRpm;
                        Driver.Run();
                        CurrentSpeed = newRpm;
                    }
                    break;
                }

                Thread.Sleep(MoveLoopDelay);
            }

            // If we get here, the system requested a stop.
            Driver.SoftHiZ();
            MoveTask = null;
            result   = new FocusMoveResult(true, null);
            MoveFinished?.Invoke(this, result);
            return;
        }