public void TestThermalCalibrateRadioTelescope_TriesThermalCalibrateRadioTelescopeWithAnotherCommandRunning_AlreadyMoving()
        {
            MovementResult   result0  = MovementResult.None;
            MovementResult   result1  = MovementResult.None;
            MovementPriority priority = MovementPriority.Manual;

            // This is running two commands at the same time. One of them should succeed, while
            // the other is rejected

            Thread t0 = new Thread(() =>
            {
                result0 = TestRadioTelescopeController.ThermalCalibrateRadioTelescope(priority);
            });

            Thread t1 = new Thread(() =>
            {
                result1 = TestRadioTelescopeController.ThermalCalibrateRadioTelescope(priority);
            });

            t0.Start();
            t1.Start();

            t0.Join();
            t1.Join();

            Assert.IsTrue(result0 == MovementResult.Success || result1 == MovementResult.Success);
            Assert.IsTrue(result0 == MovementResult.AlreadyMoving || result1 == MovementResult.AlreadyMoving);
        }
Beispiel #2
0
        /// <summary>
        /// Method used to cancel this Radio Telescope's current attempt to change orientation.
        ///
        /// The implementation of this functionality is on a "per-RT" basis, as
        /// in this may or may not work, it depends on if the derived
        /// AbstractRadioTelescope class has implemented it.
        /// </summary>
        public bool CancelCurrentMoveCommand(MovementPriority priority)
        {
            bool result = false;


            if (Monitor.TryEnter(MovementLock) && priority > RadioTelescope.PLCDriver.CurrentMovementPriority)
            {
                result = RadioTelescope.PLCDriver.Cancel_move();
                RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                Monitor.Exit(MovementLock);
            }

            return(result);
        }
Beispiel #3
0
        /// <summary>
        /// Method used to request that all of the Radio Telescope's movement comes
        /// to an immediate stop.
        ///
        /// The implementation of this functionality is on a "per-RT" basis, as
        /// in this may or may not work, it depends on if the derived
        /// AbstractRadioTelescope class has implemented it.
        /// </summary>
        public bool ExecuteRadioTelescopeImmediateStop(MovementPriority priority)
        {
            bool success = false;

            if (Monitor.TryEnter(MovementLock))
            {
                if (priority > RadioTelescope.PLCDriver.CurrentMovementPriority)
                {
                    success = RadioTelescope.PLCDriver.ImmediateStop();
                    RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                }
                Monitor.Exit(MovementLock);
            }

            return(success);
        }
Beispiel #4
0
        /// <summary>
        /// Method used to request to move the Radio Telescope to an objective
        /// right ascension/declination coordinate pair.
        ///
        /// The implementation of this functionality is on a "per-RT" basis, as
        /// in this may or may not work, it depends on if the derived
        /// AbstractRadioTelescope class has implemented it.
        /// </summary>
        public MovementResult MoveRadioTelescopeToCoordinate(Coordinate coordinate, MovementPriority priority)
        {
            MovementResult result = MovementResult.None;

            // Return if incoming priority is equal to or less than current movement
            if (priority <= RadioTelescope.PLCDriver.CurrentMovementPriority)
            {
                return(MovementResult.AlreadyMoving);
            }

            // We only want to do this if it is safe to do so. Return false if not
            if (!AllSensorsSafe)
            {
                return(MovementResult.SensorsNotSafe);
            }

            // If a lower-priority movement was running, safely interrupt it.
            RadioTelescope.PLCDriver.InterruptMovementAndWaitUntilStopped();

            // If the thread is locked (two moves coming in at the same time), return
            if (Monitor.TryEnter(MovementLock))
            {
                RadioTelescope.PLCDriver.CurrentMovementPriority = priority;

                result = RadioTelescope.PLCDriver.MoveToOrientation(CoordinateController.CoordinateToOrientation(coordinate, DateTime.UtcNow), GetCurrentOrientation());
                if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                {
                    RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                }

                Monitor.Exit(MovementLock);
            }
            else
            {
                result = MovementResult.AlreadyMoving;
            }

            return(result);
        }
Beispiel #5
0
        public int ResolveConflictFreeOperations(InconsistencyCoverage ic, EntityChange.ExecutionContext ctx)
        {
            int errors = 0;

            Parallel.ForEach(deferredInserts.Values, bag =>
            {
                Entity e;
                InsertPriority best = new InsertPriority();
                Interlocked.Add(ref errors, bag.Count - 1);
                while (bag.TryTake(out e))
                {
                    var candidate = new InsertPriority(e, ctx, ic);
                    if (candidate > best)
                    {
                        best = candidate;
                    }
                }
                if (best.Destination == null || !Insert(best.Destination))
                {
                    Interlocked.Increment(ref errors);
                }
            });
            deferredInserts.Clear();

            Parallel.ForEach(fullMap.Values, ctr =>
            {
                if (ctr.deferredUpdates.IsEmpty)
                {
                    return;
                }
                Tuple <EntityID, Entity> tuple;
                bool inc = ic.IsInconsistentR(ctx.LocalSpace.Relativate(ctr.entity.ID.Position));
                MovementPriority best = new MovementPriority();
                Interlocked.Add(ref errors, ctr.deferredUpdates.Count - 1);
                while (ctr.deferredUpdates.TryTake(out tuple))
                {
                    bool destInc  = ic.IsInconsistentR(ctx.LocalSpace.Relativate(tuple.Item2.ID.Position));
                    var candidate = new MovementPriority(ctr.entity, tuple.Item1, tuple.Item2, ctx, inc, destInc);
                    if (candidate > best)
                    {
                        best = candidate;
                    }
                }
                if (best.Destination != null)
                {
                    ctr.entity = best.Destination;
                    tree       = null;
                }
                else
                {
                    Interlocked.Increment(ref errors);
                }
            });
            EntityID id;

            while (deferredRemovals.TryTake(out id))
            {
                if (CheckFindAndRemove(id))
                {
                    tree = null;
                }
                else
                {
                    errors++;
                }
            }


            return(errors);
        }
        public void TestAllTelescopeMovements_RunABunchOfCommandsAtTheSameTime_OnlyOneCommandSucceedsWhileTheRestAreAlreadyMoving()
        {
            int threadCount = 7;

            MovementPriority priority = MovementPriority.Manual;
            Coordinate       c        = new Coordinate(0, 0);
            Orientation      o        = new Orientation(0, 0);

            // movement result array
            MovementResult[] results = new MovementResult[threadCount];
            for (int i = 0; i < threadCount; i++)
            {
                results[i] = MovementResult.None;
            }

            Thread[] threads = new Thread[7];

            threads[0] = new Thread(() =>
            {
                results[0] = TestRadioTelescopeController.HomeTelescope(priority);
            });
            threads[1] = new Thread(() =>
            {
                results[1] = TestRadioTelescopeController.SnowDump(priority);
            });
            threads[2] = new Thread(() =>
            {
                results[2] = TestRadioTelescopeController.MoveRadioTelescopeToCoordinate(c, priority);
            });
            threads[3] = new Thread(() =>
            {
                results[3] = TestRadioTelescopeController.MoveRadioTelescopeToOrientation(o, priority);
            });
            threads[4] = new Thread(() =>
            {
                results[4] = TestRadioTelescopeController.ThermalCalibrateRadioTelescope(priority);
            });
            threads[5] = new Thread(() =>
            {
                results[5] = TestRadioTelescopeController.StartRadioTelescopeJog(5, RadioTelescopeDirectionEnum.ClockwiseOrNegative, RadioTelescopeAxisEnum.AZIMUTH);
            });
            threads[6] = new Thread(() =>
            {
                results[6] = TestRadioTelescopeController.FullElevationMove(priority);
            });

            // Run all threads concurrently
            // These cannot be looped through because a loop adds enough delay to throw off concurrency
            threads[0].Start();
            threads[1].Start();
            threads[2].Start();
            threads[3].Start();
            threads[4].Start();
            threads[5].Start();
            threads[6].Start();

            // Wait for all threads to complete
            foreach (Thread thread in threads)
            {
                thread.Join();
            }

            int successes      = 0;
            int alreadyMovings = 0;

            for (int i = 0; i < threadCount; i++)
            {
                if (results[i] == MovementResult.Success)
                {
                    successes++;
                }
                else if (results[i] == MovementResult.AlreadyMoving)
                {
                    alreadyMovings++;
                }
            }

            Assert.AreEqual(1, successes);
            Assert.AreEqual(threadCount - 1, alreadyMovings);
        }
        /// <summary>
        /// fires whenever the data on the modbus server changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Server_Written_to_handler(object sender, DataStoreEventArgs e)
        {
            //e.Data.B //array representing data
            if (is_test)
            {
                logger.Info(Utilities.GetTimeStamp() + ": recived message from PLC");
            }
            PLC_last_contact = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            switch (e.StartAddress)
            {
            case (ushort)PLC_modbus_server_register_mapping.AZ_0_LIMIT: {
                bool previous = limitSwitchData.Azimuth_CCW_Limit;
                limitSwitchData.Azimuth_CCW_Limit = !Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.AZ_0_LIMIT]);
                if (previous != limitSwitchData.Azimuth_CCW_Limit)
                {
                    pLCEvents.PLCLimitChanged(limitSwitchData, PLC_modbus_server_register_mapping.AZ_0_LIMIT, limitSwitchData.Azimuth_CCW_Limit);
                }
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.AZ_0_HOME: {
                bool previous = homeSensorData.Azimuth_Home_One;
                homeSensorData.Azimuth_Home_One = Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.AZ_0_HOME]);
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.AZ_0_SECONDARY: {
                bool previous = homeSensorData.Azimuth_Home_Two;
                homeSensorData.Azimuth_Home_Two = Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.AZ_0_SECONDARY]);
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.AZ_375_LIMIT: {
                bool previous = limitSwitchData.Azimuth_CW_Limit;
                limitSwitchData.Azimuth_CW_Limit = !Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.AZ_375_LIMIT]);
                if (previous != limitSwitchData.Azimuth_CW_Limit)
                {
                    pLCEvents.PLCLimitChanged(limitSwitchData, PLC_modbus_server_register_mapping.AZ_375_LIMIT, limitSwitchData.Azimuth_CW_Limit);
                }
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.EL_10_LIMIT: {
                bool previous = limitSwitchData.Elevation_Lower_Limit;
                limitSwitchData.Elevation_Lower_Limit = !Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.EL_10_LIMIT]);
                if (previous != limitSwitchData.Elevation_Lower_Limit)
                {
                    pLCEvents.PLCLimitChanged(limitSwitchData, PLC_modbus_server_register_mapping.EL_10_LIMIT, limitSwitchData.Elevation_Lower_Limit);
                    if (limitSwitchData.Elevation_Lower_Limit)
                    {
                        logger.Info(Utilities.GetTimeStamp() + ": Elevation Lower Limit Switch Hit");

                        pushNotification.sendToAllAdmins("LIMIT SWITCH", "Elevation lower limit switch hit");
                        EmailNotifications.sendToAllAdmins("LIMIT SWITCH", "Elevation lower limit switch hit");
                    }
                }
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.EL_0_HOME: {
                bool previous = homeSensorData.Elevation_Home;
                homeSensorData.Elevation_Home = Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.EL_0_HOME]);
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.EL_90_LIMIT: {
                bool previous = limitSwitchData.Elevation_Upper_Limit;
                limitSwitchData.Elevation_Upper_Limit = !Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.EL_90_LIMIT]);
                if (previous != limitSwitchData.Elevation_Upper_Limit)
                {
                    pLCEvents.PLCLimitChanged(limitSwitchData, PLC_modbus_server_register_mapping.EL_90_LIMIT, limitSwitchData.Elevation_Upper_Limit);
                    if (limitSwitchData.Elevation_Upper_Limit)
                    {
                        logger.Info(Utilities.GetTimeStamp() + ": Elevation Upper Limit Switch Hit");

                        pushNotification.sendToAllAdmins("LIMIT SWITCH", "Elevation upper limit switch hit");
                        EmailNotifications.sendToAllAdmins("LIMIT SWITCH", "Elevation upper limit switch hit");
                    }
                }
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.Gate_Safety_INTERLOCK: {
                bool previous = plcInput.Gate_Sensor;
                plcInput.Gate_Sensor = !Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.Gate_Safety_INTERLOCK]);
                if (previous != plcInput.Gate_Sensor)
                {
                    if (plcInput.Gate_Sensor)
                    {
                        logger.Info(Utilities.GetTimeStamp() + ": gate opened");

                        pushNotification.sendToAllAdmins("GATE ACTIVITY", "Gate has been opened.");
                        EmailNotifications.sendToAllAdmins("GATE ACTIVITY", "Gate has been opened.");
                    }
                    else
                    {
                        logger.Info(Utilities.GetTimeStamp() + ": gate closed");

                        pushNotification.sendToAllAdmins("GATE ACTIVITY", "Gate has been closed.");
                        EmailNotifications.sendToAllAdmins("GATE ACTIVITY", "Gate has been closed.");
                    }
                }
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.E_STOP: {
                bool previous = plcInput.Estop;
                plcInput.Estop = !Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.E_STOP]);
                if (previous != plcInput.Estop)
                {
                    if (plcInput.Estop)
                    {
                        logger.Info(Utilities.GetTimeStamp() + ": Estop Hit");
                        CurrentMovementPriority = MovementPriority.Critical;

                        pushNotification.sendToAllAdmins("E-STOP ACTIVITY", "E-stop has been hit.");
                        EmailNotifications.sendToAllAdmins("E-STOP ACTIVITY", "E-stop has been hit.");
                    }
                    else
                    {
                        logger.Info(Utilities.GetTimeStamp() + ": Estop released");
                        CurrentMovementPriority = MovementPriority.None;

                        pushNotification.sendToAllAdmins("E-STOP ACTIVITY", "E-stop has been released.");
                        EmailNotifications.sendToAllAdmins("E-STOP ACTIVITY", "E-stop has been released.");
                    }
                }
                break;
            }

            case (ushort)PLC_modbus_server_register_mapping.EL_SLIP_CAPTURE: {
                bool previous = plcInput.EL_Slip_CAPTURE;
                plcInput.EL_Slip_CAPTURE = Int_to_bool(PLC_Modbusserver.DataStore.HoldingRegisters[(int)PLC_modbus_server_register_mapping.EL_SLIP_CAPTURE]);
                break;
            }
            }
        }
        private async void DefaultLimitSwitchHandle(object sender, limitEventArgs e)
        {
            if (e.Value)
            {
                switch (e.ChangedValue)
                {
                case PLC_modbus_server_register_mapping.AZ_0_LIMIT:
                {
                    if (!Overrides.overrideAzimuthProx0)
                    {
                        CurrentMovementPriority = MovementPriority.Critical;
                        MCU.SendSingleAxisJog(RadioTelescopeAxisEnum.AZIMUTH, RadioTelescopeDirectionEnum.ClockwiseOrNegative, 0.25);
                    }
                    break;
                }

                case PLC_modbus_server_register_mapping.AZ_375_LIMIT:
                {
                    if (!Overrides.overrideAzimuthProx375)
                    {
                        CurrentMovementPriority = MovementPriority.Critical;
                        MCU.SendSingleAxisJog(RadioTelescopeAxisEnum.AZIMUTH, RadioTelescopeDirectionEnum.CounterclockwiseOrPositive, 0.25);
                    }
                    break;
                }

                case PLC_modbus_server_register_mapping.EL_10_LIMIT:
                {
                    if (!Overrides.overrideElevatProx0)
                    {
                        CurrentMovementPriority = MovementPriority.Critical;
                        MCU.SendSingleAxisJog(RadioTelescopeAxisEnum.ELEVATION, RadioTelescopeDirectionEnum.CounterclockwiseOrPositive, 0.25);
                    }
                    break;
                }

                case PLC_modbus_server_register_mapping.EL_90_LIMIT:
                {
                    if (!Overrides.overrideElevatProx90)
                    {
                        CurrentMovementPriority = MovementPriority.Critical;
                        MCU.SendSingleAxisJog(RadioTelescopeAxisEnum.ELEVATION, RadioTelescopeDirectionEnum.ClockwiseOrNegative, 0.25);
                    }
                    break;
                }
                }
            }
            if (!e.Value)
            {
                switch (e.ChangedValue)
                {
                case PLC_modbus_server_register_mapping.AZ_0_LIMIT:
                {
                    if (!Overrides.overrideAzimuthProx0)
                    {
                        MCU.StopSingleAxisJog(RadioTelescopeAxisEnum.AZIMUTH);
                        CurrentMovementPriority = MovementPriority.None;
                    }
                    break;
                }

                case PLC_modbus_server_register_mapping.AZ_375_LIMIT:
                {
                    if (!Overrides.overrideAzimuthProx375)
                    {
                        MCU.StopSingleAxisJog(RadioTelescopeAxisEnum.AZIMUTH);
                        CurrentMovementPriority = MovementPriority.None;
                    }
                    break;
                }

                case PLC_modbus_server_register_mapping.EL_10_LIMIT:
                {
                    if (!Overrides.overrideElevatProx0)
                    {
                        MCU.StopSingleAxisJog(RadioTelescopeAxisEnum.ELEVATION);
                        CurrentMovementPriority = MovementPriority.None;
                    }
                    break;
                }

                case PLC_modbus_server_register_mapping.EL_90_LIMIT:
                {
                    if (!Overrides.overrideElevatProx90)
                    {
                        MCU.StopSingleAxisJog(RadioTelescopeAxisEnum.ELEVATION);
                        CurrentMovementPriority = MovementPriority.None;
                    }
                    break;
                }
                }
            }
        }
Beispiel #9
0
        /// <summary>
        /// This is a script that is called when we want to dump snow out of the dish
        /// </summary>
        public MovementResult SnowDump(MovementPriority priority)
        {
            MovementResult result = MovementResult.None;

            // Return if incoming priority is equal to or less than current movement
            if (priority <= RadioTelescope.PLCDriver.CurrentMovementPriority)
            {
                return(MovementResult.AlreadyMoving);
            }

            // We only want to do this if it is safe to do so. Return false if not
            if (!AllSensorsSafe)
            {
                return(MovementResult.SensorsNotSafe);
            }

            // If a lower-priority movement was running, safely interrupt it.
            RadioTelescope.PLCDriver.InterruptMovementAndWaitUntilStopped();

            // If the thread is locked (two moves coming in at the same time), return
            if (Monitor.TryEnter(MovementLock))
            {
                RadioTelescope.PLCDriver.CurrentMovementPriority = priority;

                // insert snow dump movements here
                // default is azimuth of 0 and elevation of 0
                previousSnowDumpAzimuth += 45;
                if (previousSnowDumpAzimuth >= 360)
                {
                    previousSnowDumpAzimuth -= 360;
                }

                Orientation dump    = new Orientation(previousSnowDumpAzimuth, -5);
                Orientation current = GetCurrentOrientation();

                Orientation dumpAzimuth   = new Orientation(dump.Azimuth, current.Elevation);
                Orientation dumpElevation = new Orientation(dump.Azimuth, dump.Elevation);

                // move to dump snow
                result = RadioTelescope.PLCDriver.MoveToOrientation(dumpAzimuth, current);
                if (result != MovementResult.Success)
                {
                    if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                    {
                        RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                    }
                    Monitor.Exit(MovementLock);
                    return(result);
                }

                result = RadioTelescope.PLCDriver.MoveToOrientation(dumpElevation, dumpAzimuth);
                if (result != MovementResult.Success)
                {
                    if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                    {
                        RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                    }
                    Monitor.Exit(MovementLock);
                    return(result);
                }

                // move back to initial orientation
                result = RadioTelescope.PLCDriver.MoveToOrientation(current, dumpElevation);

                if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                {
                    RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                }

                Monitor.Exit(MovementLock);
            }
            else
            {
                result = MovementResult.AlreadyMoving;
            }

            return(result);
        }
Beispiel #10
0
        /// <summary>
        /// A demonstration script that moves the elevation motor to its maximum and minimum.
        /// </summary>
        /// <param name="priority">Movement priority.</param>
        /// <returns></returns>
        public MovementResult FullElevationMove(MovementPriority priority)
        {
            MovementResult result = MovementResult.None;

            // Return if incoming priority is equal to or less than current movement
            if (priority <= RadioTelescope.PLCDriver.CurrentMovementPriority)
            {
                return(MovementResult.AlreadyMoving);
            }

            // We only want to do this if it is safe to do so. Return false if not
            if (!AllSensorsSafe)
            {
                return(MovementResult.SensorsNotSafe);
            }

            // If a lower-priority movement was running, safely interrupt it.
            RadioTelescope.PLCDriver.InterruptMovementAndWaitUntilStopped();

            // If the thread is locked (two moves coming in at the same time), return
            if (Monitor.TryEnter(MovementLock))
            {
                RadioTelescope.PLCDriver.CurrentMovementPriority = priority;

                Orientation origOrientation = GetCurrentOrientation();

                Orientation move1 = new Orientation(origOrientation.Azimuth, 0);
                Orientation move2 = new Orientation(origOrientation.Azimuth, 90);

                // Move to a low elevation point
                result = RadioTelescope.PLCDriver.MoveToOrientation(move1, origOrientation);
                if (result != MovementResult.Success)
                {
                    if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                    {
                        RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                    }
                    Monitor.Exit(MovementLock);
                    return(result);
                }

                // Move to a high elevation point
                result = RadioTelescope.PLCDriver.MoveToOrientation(move2, move1);
                if (result != MovementResult.Success)
                {
                    if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                    {
                        RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                    }
                    Monitor.Exit(MovementLock);
                    return(result);
                }

                // Move back to the original orientation
                result = RadioTelescope.PLCDriver.MoveToOrientation(origOrientation, move2);

                if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                {
                    RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                }

                Monitor.Exit(MovementLock);
            }
            else
            {
                result = MovementResult.AlreadyMoving;
            }

            return(result);
        }
Beispiel #11
0
        /// <summary>
        /// This is used to home the telescope. Immediately after homing, the telescope will move to "Stow" position.
        /// This will also zero out the absolute encoders and account for the true north offset.
        /// </summary>
        /// <param name="priority">The priority of this movement.</param>
        /// <returns>True if homing was successful; false if homing failed.</returns>
        public MovementResult HomeTelescope(MovementPriority priority)
        {
            MovementResult result = MovementResult.None;

            // Return if incoming priority is equal to or less than current movement
            if (priority <= RadioTelescope.PLCDriver.CurrentMovementPriority)
            {
                return(MovementResult.AlreadyMoving);
            }

            // We only want to do this if it is safe to do so. Return false if not
            if (!AllSensorsSafe)
            {
                return(MovementResult.SensorsNotSafe);
            }

            // If a lower-priority movement was running, safely interrupt it.
            RadioTelescope.PLCDriver.InterruptMovementAndWaitUntilStopped();

            // If the thread is locked (two moves coming in at the same time), return
            if (Monitor.TryEnter(MovementLock))
            {
                RadioTelescope.PLCDriver.CurrentMovementPriority = priority;

                // Remove all offsets first so we can accurately zero out the positions
                RadioTelescope.SensorNetworkServer.AbsoluteOrientationOffset = new Orientation(0, 0);
                FinalCalibrationOffset = new Orientation(0, 0);

                // Perform a home telescope movement
                result = RadioTelescope.PLCDriver.HomeTelescope();

                // Zero out absolute encoders
                RadioTelescope.SensorNetworkServer.AbsoluteOrientationOffset = (Orientation)RadioTelescope.SensorNetworkServer.CurrentAbsoluteOrientation.Clone();

                // Allow the absolute encoders' positions to even out
                Thread.Sleep(100);

                // Verify the absolute encoders have successfully zeroed out. There is a bit of fluctuation with their values, so homing could have occurred
                // with an outlier value. This check (with half-degree of precision) verifies that did not happen.
                Orientation absOrientation = RadioTelescope.SensorNetworkServer.CurrentAbsoluteOrientation;
                if ((Math.Abs(absOrientation.Elevation) > 0.5 && !overrides.overrideElevationAbsEncoder) ||
                    (Math.Abs(absOrientation.Azimuth) > 0.5 && !overrides.overrideAzimuthAbsEncoder))
                {
                    result = MovementResult.IncorrectPosition;
                }

                // Apply final calibration offset
                FinalCalibrationOffset = RadioTelescope.CalibrationOrientation;

                if (RadioTelescope.PLCDriver.CurrentMovementPriority == priority)
                {
                    RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                }

                Monitor.Exit(MovementLock);
            }
            else
            {
                result = MovementResult.AlreadyMoving;
            }

            return(result);
        }
Beispiel #12
0
 /// <summary>
 /// This is a method used to move the radio telescope by X degrees.
 /// Entering 0 for an axis will not move that motor.
 /// </summary>
 /// <param name="degreesToMoveBy">The number of degrees to move by.</param>
 /// <param name="priority">The movement's priority.</param>
 /// <returns></returns>
 public MovementResult MoveRadioTelescopeByXDegrees(Orientation degreesToMoveBy, MovementPriority priority)
 {
     // TODO: Implement (issue #379)
     return(MovementResult.None);
 }
Beispiel #13
0
        /// <summary>
        /// Method used to calibrate the Radio Telescope before each observation.
        ///
        /// The implementation of this functionality is on a "per-RT" basis, as
        /// in this may or may not work, it depends on if the derived
        /// AbstractRadioTelescope class has implemented it.
        /// </summary>
        public MovementResult ThermalCalibrateRadioTelescope(MovementPriority priority)
        {
            MovementResult moveResult = MovementResult.None;

            // Return if incoming priority is equal to or less than current movement
            if (priority <= RadioTelescope.PLCDriver.CurrentMovementPriority)
            {
                return(MovementResult.AlreadyMoving);
            }

            // We only want to do this if it is safe to do so. Return false if not
            if (!AllSensorsSafe)
            {
                return(MovementResult.SensorsNotSafe);
            }

            // If a lower-priority movement was running, safely interrupt it.
            RadioTelescope.PLCDriver.InterruptMovementAndWaitUntilStopped();

            // If the thread is locked (two moves coming in at the same time), return
            if (Monitor.TryEnter(MovementLock))
            {
                Orientation current = GetCurrentOrientation();

                moveResult = RadioTelescope.PLCDriver.MoveToOrientation(MiscellaneousConstants.THERMAL_CALIBRATION_ORIENTATION, current);

                if (moveResult != MovementResult.Success)
                {
                    if (RadioTelescope.PLCDriver.CurrentMovementPriority != MovementPriority.Critical)
                    {
                        RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                    }
                    Monitor.Exit(MovementLock);
                    return(moveResult);
                }

                // start a timer so we can have a time variable
                Stopwatch stopWatch = new Stopwatch();
                stopWatch.Start();

                // temporarily set spectracyber mode to continuum
                RadioTelescope.SpectraCyberController.SetSpectraCyberModeType(SpectraCyberModeTypeEnum.CONTINUUM);

                // read data
                SpectraCyberResponse response = RadioTelescope.SpectraCyberController.DoSpectraCyberScan();

                // end the timer
                stopWatch.Stop();
                double time = stopWatch.Elapsed.TotalSeconds;

                RFData rfResponse = RFData.GenerateFrom(response);

                // move back to previous location
                moveResult = RadioTelescope.PLCDriver.MoveToOrientation(current, MiscellaneousConstants.THERMAL_CALIBRATION_ORIENTATION);
                if (moveResult != MovementResult.Success)
                {
                    if (RadioTelescope.PLCDriver.CurrentMovementPriority != MovementPriority.Critical)
                    {
                        RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                    }
                    RadioTelescope.SpectraCyberController.StopScan();
                    Monitor.Exit(MovementLock);
                    return(moveResult);
                }

                // analyze data
                // temperature (Kelvin) = (intensity * time * wein's displacement constant) / (Planck's constant * speed of light)
                double weinConstant   = 2.8977729;
                double planckConstant = 6.62607004 * Math.Pow(10, -34);
                double speedConstant  = 299792458;
                double temperature    = (rfResponse.Intensity * time * weinConstant) / (planckConstant * speedConstant);

                // convert to fahrenheit
                temperature = temperature * (9 / 5) - 459.67;

                // check against weather station reading
                double weatherStationTemp = RadioTelescope.WeatherStation.GetOutsideTemp();

                // Set SpectraCyber mode back to UNKNOWN
                RadioTelescope.SpectraCyberController.SetSpectraCyberModeType(SpectraCyberModeTypeEnum.UNKNOWN);

                // return true if working correctly, false if not
                if (Math.Abs(weatherStationTemp - temperature) < MiscellaneousConstants.THERMAL_CALIBRATION_OFFSET)
                {
                    moveResult = RadioTelescope.PLCDriver.MoveToOrientation(MiscellaneousConstants.Stow, current);
                }

                if (RadioTelescope.PLCDriver.CurrentMovementPriority != MovementPriority.Critical)
                {
                    RadioTelescope.PLCDriver.CurrentMovementPriority = MovementPriority.None;
                }

                RadioTelescope.SpectraCyberController.StopScan();
                Monitor.Exit(MovementLock);
            }
            else
            {
                moveResult = MovementResult.AlreadyMoving;
            }

            return(moveResult);
        }