Digital switch complete code

This page contains the complete code of Digital Switch.

In DigitalSwitch.cpp, your digital switch code should be as follows:

Copy
#include "RT_Project_01.h"
#include "SingleAxisMotion.h"
#include "GroupMotion.h"
#include "DigitalSwitch.h"
#include <vector>
using namespace std;

VOID DigitalCamSwitch(int Index)
{
    RtPrintf("Enable digital cam switches using an axis' position.\n\n");

    BOOL Value = FALSE;

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero: %d\n\n", Value);

    //Defines each switch. Each track can have up to eight switches.
    //TrackNumber: the index of the track a switch belongs to.
    //FirstOnPosition: the position at which the switch is enabled.
    //LastOnPosition: the position at which the switch is disabled for distance switches.
    //AxisDirection: the direction in which the switch is triggered. 0: Both, 1: Positive, 2: Negative.
    //CamSwitchMode: the switch mode. 0: Distance, 1: Time.
    //Duration: the duration in seconds the switch stays enabled. For time switches.
    //The first three switches correspond to Output[0], the last corresponds to Output[1].
    McCamSwitch Switches[4] =
    {
        //TrackNumber  FirstOnPosition  LastOnPosition  AxisDirection   CamSwitchMode   Duration
        {     0,            2000,           3000,             1,              0,           0      },
        {     0,            2500,           3000,             2,              0,           0      },
        {     0,            4000,           6000,             0,              0,           0      },
        {     1,            3000,           0,                0,              1,           1.35   }
    };

    //On compensation is a delay in seconds before the output is turned on when a switch becomes active.
    //Off compensation is a delay in seconds before the outout is turned off when a switch becomes inactive.
    //Hysteresis adds a minimum distance in between switches to prevent an output from switching on and off.
    McTrack Tracks[2] =
    {
        //OnCompensation   OffCompensation   Hysteresis
        {    -0.125,            0.25,            0    },
        {       0,               0,              0    }
    };

    //Defines the output for each track.
    //Each track controls one output.
    //The type selects between axes and I/O modules. TRUE: Axis, FALSE: I/O module.
    //The index of the axis or I/O module.
    //The offset of the output bit in the output buffer of a device.
    McOutput Outputs[2] =
    {
        //Axis          Index        Offset
        { FALSE,          2,           0 },
        { FALSE,          3,           0 }
    };

    KsCommandStatus camSwitch = WaitForCommand(5, FALSE, SetAxisCamSwitch(
        Index,              //Index
        4,                  //SwitchLength
        Switches,           //Switches
        2,                  //TrackLength
        Outputs,            //Outputs
        Tracks,             //Tracks
        3,                  //EnableMask, enabling Track Zero and One
        mcSetValue          //ValueSource
    ));

    /*-----Trigger the first switch-----*/
    RtPrintf("-----Trigger the first switch-----\n\n");
    //Move an axis to trigger a switch.
    RtPrintf("Make an absolute move.\n\n");

    //Start an absolute move.
    KsCommandStatus absolute = WaitForCommand(30, TRUE, MoveAxisAbsolute(Index, 2700,
        1000, 10000, 10000, 1000000, mcPositiveDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero, 1st switch: %d\n\n", Value);

    /*-----Trigger the second switch-----*/
    RtPrintf("-----Trigger the second switch-----\n\n");

    /*Reset Value to zero to check whether the value become one when 2nd switch is triggered.
      If we don't reset it, we won't know the "1" in value is from the 1st or 2nd switch.*/
    Value = 0;
    RtPrintf("Reset output bit to %d.\n\n", Value);

    //Move the axis to the position 3600.
    RtPrintf("Make absolute moves.\n\n");

    absolute = WaitForCommand(30, TRUE, MoveAxisAbsolute(Index, 3600, 1000,
        10000, 10000, 1000000, mcPositiveDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    //Move the axis to the position 2800.
    /*We do this because the AxisDirection of the 2nd switch is negative.
      The axis needs to past LastOnPosition first, and then move back to the
      switch-on range so the switch can be triggered.*/
    absolute = WaitForCommand(30, TRUE, MoveAxisAbsolute(Index, 2800, 1000,
        10000, 10000, 1000000, mcNegativeDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero, 2nd switch: %d\n\n", Value);

    /*-----Trigger the third switch-----*/
    RtPrintf("-----Trigger the third switch-----\n\n");

    Value = 0;
    RtPrintf("Reset output bit to %d.\n\n", Value);

    //Move the axis to the position 5000.
    RtPrintf("Make an absolute move.\n\n");

    absolute = WaitForCommand(30, TRUE, MoveAxisAbsolute(Index, 5000, 1000,
        10000, 10000, 1000000, mcPositiveDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    ReadOutputBit(2, 0, &Value);
    RtPrintf("Read the output bit corresponding to Track Zero, 3rd switch: %d\n\n", Value);

    /*-----Trigger the fourth switch-----*/

    RtPrintf("-----Trigger the fourth switch-----\n\n");

    Value = 0;
    RtPrintf("Reset output bit to %d.\n\n", Value);

    //Move the axis to the position 3000.
    RtPrintf("Make an absolute move.\n\n");

    absolute = WaitForCommand(30, TRUE, MoveAxisAbsolute(Index, 3000, 1000,
        10000, 10000, 1000000, mcNegativeDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    ReadOutputBit(3, 0, &Value);
    RtPrintf("Read the output bit corresponding to Track One, 4th switch: %d\n\n", Value);
}

VOID GroupCamSwitch(int Group)
{
    RtPrintf("Enable group digital cam switches using a group's distance.\n\n");

    /*Value is used to check whether a switch has been triggered. By default,
      it is FALSE (zero).*/
    BOOL Value = FALSE;

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero: %d\n\n", Value);

    //Defines each switch. Each track can have up to eight switches.
    //TrackNumber: the index of the track a switch belongs to.
    /*FirstOnPosition: the distance between the original starting position and FirstOnPosition
      in a path motion command, must be nonnegative.*/
    /*LastOnPosition: the distance between the original starting position and LastOnPosition
      in a path motion command, must be positive and greater than FirstOnPosition.*/
    //AxisDirection: not used, because FirstOnPosition and LastOnPosition are distance.
    //CamSwitchMode: the switch mode. 0: Distance, 1: Time.
    //Duration: the duration in seconds the switch stays enabled. For time switches.
    //The first three switches correspond to Output[0], the last corresponds to Output[1].

    McCamSwitch Switches[3] =
    {
        //TrackNumber  FirstOnPosition  LastOnPosition  AxisDirection   CamSwitchMode   Duration
        {     0,            2000,           3000,             0,              0,           0      },
        {     0,            1000,           1500,             0,              0,           0      },
        {     1,            4000,           6000,             0,              1,           3      },
    };

    //On compensation is a delay in seconds before the output is turned on when a switch becomes active.
    //Off compensation is a delay in seconds before the outout is turned off when a switch becomes inactive.
    //Hysteresis adds a minimum distance in between switches to prevent an output from switching on and off.
    McTrack Tracks[2] =
    {
        //OnCompensation   OffCompensation   Hysteresis
        {       0,                0,             0    },
        {       0,                0,             0    }
    };

    //Defines the output for each track.
    //Each track controls one output.
    //The type selects between axes and I/O modules. TRUE: Axis, FALSE: I/O module.
    //The index of the axis or I/O module.
    //The offset of the output bit in the output buffer of a device.
    McOutput Outputs[2] =
    {
        //Axis          Index        Offset
        { FALSE,          2,           0 },
        { FALSE,          3,           0 }
    };

    const int LENGTH = 3;   //The length of the Position array.

    //First switch on: (1046.8, 1151.6, 1256.2) off: (1570.2, 1727.4, 1884.3)
    //Second switch on: (523.4, 575.8, 628.1) off: (785.1, 863.65, 942.16)
    //Third switch on: (2093.6, 2303.2, 2512.4) off: (3140.4, 3454.8, 3768.6)
    //Unit vector: (0.5234, 0.5758, 0.6281)
    double EndPositions[LENGTH] = { 5000, 5500, 6000 };

    //Move an axis to trigger a switch.
    RtPrintf("Make a linear absolute move.\n\n");

    KsCommandStatus absolute = MoveLinearAbsolute(Group, LENGTH,
        EndPositions, 500, 5000, 5000, 500000, mcAxisCoordSystem,
        mcAborting, mcNone, NULL);
    if (absolute.Error)
        RtPrintf("MoveLinearAbsolute failed: %d\n", absolute.ErrorId);

    KsCommandStatus groupCamSwitch = SetGroupPathCamSwitch(
        Group,              //Index
        absolute,           //MotionCommand
        3,                  //SwitchLength
        Switches,           //Switches
        2,                  //TrackLength
        Outputs,            //Outputs
        Tracks,             //Tracks
        3                   //EnableMask, enabling Track Zero and One
    );

    /*-----Calculate where the switches will be triggered-----*/
    RtPrintf("Calculate where the switches will be triggered.\n\n");

    double axisDistance[3] = { 0 };
    double startPosition[3] = { 0 };
    double currentPosition[3] = { 0 };
    double Square[3] = { 0 };

    //Calculate the square of each EndPosition.
    Square[0] = pow(EndPositions[0], 2);
    Square[1] = pow(EndPositions[1], 2);
    Square[2] = pow(EndPositions[2], 2);

    //Calculate the square root of the sum of each EndPositions' square number.
    double sqrtRoot = sqrt(Square[0] + Square[1] + Square[2]);
    printf("Square root: %f\n\n", sqrtRoot);

    //Calculate the unit vector for each axis.
    double unitVector[3] = { 0 };
    unitVector[0] = EndPositions[0] / sqrtRoot;
    unitVector[1] = EndPositions[1] / sqrtRoot;
    unitVector[2] = EndPositions[2] / sqrtRoot;

    //Display each unit vector.
    /*After we get unit vectors, we need to calculate how many units an axis should
      move to trigger a switch. The equations are as follows:
      unitVector * FirstOnPosition = A
      unitVector * LastOnPosition = B
      The range between A and B is where a switch is triggered.*/
    printf("unitVector[0]: %f\n", unitVector[0]);
    printf("unitVector[1]: %f\n", unitVector[1]);
    printf("unitVector[2]: %f\n\n", unitVector[2]);

    for (int i = 0; i < 3; i++)
    {
        printf("unitVector[%d] * Switches[%d].FirstOnPosition: %f\n", i, i, unitVector[i] * Switches[i].FirstOnPosition);
        printf("unitVector[%d] * Switches[%d].LastOnPosition: %f\n", i, i, unitVector[i] * Switches[i].LastOnPosition);
    }

    RtPrintf("\n");

    /*-----Trigger the switches-----*/
    RtPrintf("Trigger the switches.\n\n");

    //Use vector to declare a dynamic array that creates a range-based for loop.
    vector<int> Loop = { 1, 0, 2 };

    /*Count is a flag used to check whether a switch's output has been read and displayed.
      If it has, the count value will be incremented. This flag can ensure RtPrintf is executed
      only once when it displays the output of the switch.*/
    int Count = 0;

    while (!absolute.Done)
    {
        //Get the state of MoveLinearAbsolute and pass it to absolute.
        absolute = GetCommandStatus(absolute);

        //Get the set position of a group.
        GetGroupPosition(Group, mcAxisCoordSystem, mcSetValue, LENGTH, currentPosition);

        //Calculate how far three axes move.
        axisDistance[0] = currentPosition[0] - startPosition[0];
        axisDistance[1] = currentPosition[1] - startPosition[1];
        axisDistance[2] = currentPosition[2] - startPosition[2];

        /*Use for loop to check whether the switches are triggered.
          The switches are triggered in this sequence: 2->1->3.*/
        for (auto i : Loop)
        {
            /*Value is used to check whether a switch has been triggered. If it has,
              Value will be changed to one and displayed, and then be reset for the
              next switch.*/
            Value = 0;

            //Check whether the axes trigger their own switches.
            if (axisDistance[i] >= (unitVector[i] * Switches[i].FirstOnPosition) &&
                axisDistance[i] <= (unitVector[i] * Switches[i].LastOnPosition))
            {
                /*Use switch-case statement to test whether a switch has been triggered.
                  If it has, display its output value once.*/
                switch (i)
                {
                //Check whether the second switch is triggered.
                case 1:
                    if (Count >= 1)
                        continue;
                    ReadOutputBit(2, 0, &Value);
                    RtPrintf("Read the output bit corresponding to Track Zero, 2nd switch: %d\n", Value);
                    Count++;
                    break;

                //Check whether the first switch is triggered.
                case 0:
                    if (Count >= 2)
                        continue;
                    ReadOutputBit(2, 0, &Value);
                    RtPrintf("Read the output bit corresponding to Track Zero, 1st switch: %d\n", Value);
                    Count++;
                    break;

                //Check whether the third switch is triggered.
                case 2:
                    if (Count >= 3)
                        continue;
                    ReadOutputBit(3, 0, &Value);
                    RtPrintf("Read the output bit corresponding to Track One, 1st switch: %d\n\n", Value);
                    Count++;
                    break;

                default:
                    RtPrintf("Out of range.\n\n");
                }
            }
        }
    }

    //Wait 1 millisecond to make sure everything is done.
    //On the computers that have better performance, this command can be skipped.
    Sleep(1);

    //Get the state of SetGroupPathCamSwitch and pass it to groupCamSwitch.
    groupCamSwitch = GetCommandStatus(groupCamSwitch);

    //Display the Done state of MoveLinearAbsolute and SetGroupPathCamSwitch.
    RtPrintf("MoveLinearAbsolute.Done: %d\n", absolute.Done);
    RtPrintf("SetGroupPathCamSwitch.Done: %d\n\n", groupCamSwitch.Done);

    //Display end positions of all axes.
    RtPrintf("End position:\n");
    GetAGroupPosition(Group);
}

VOID DigitalCyclicSwitch(int Index)
{
    RtPrintf("Enable a cyclic switch using an axis' position.\n\n");

    BOOL Value = FALSE;
    BOOL Switches = 0;

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero: %d\n\n", Value);

    //The position at which the switch is enabled.
    //The position at which the switch is disabled for distance switches.
    //The direction in which the switch is triggered. 0: Both, 1: Positive, 2: Negative.
    //The switch mode. 0: Distance, 1: Time.
    //The duration in seconds the switch stays enabled. For time switches.
    //TrackNumber: must be zero.
    /*FirstOnPosition: must be nonnegative. It is the distance relative to each cycle's
      starting position.*/
    /*LastOnPosition: must be positive and greater than FirstOnPosition. It is the distance
      relative to each cycle's starting position.*/
    //Duration: must be positive.

    //Trigger the switch by distance.
    McCamSwitch cyclicSwitch1 =
    {
        //TrackNumber  FirstOnPosition  LastOnPosition  AxisDirection  CamSwitchMode  Duration
             0,             300,             600,             1,             0,          0
    };

    //Trigger the switch by time.
    McCamSwitch cyclicSwitch2 =
    {
        //TrackNumber  FirstOnPosition  LastOnPosition  AxisDirection  CamSwitchMode  Duration
             0,             400,             700,             1,             1,         0.5
    };

    //Defines the output for the track.
    //The type selects between axes and I/O modules. TRUE: Axis, FALSE: I/O module.
    //The index of the axis or I/O module.
    //The offset of the output bit in the output buffer of a device.
    McOutput Output =
    {
          //Axis        Index        Offset
           FALSE,         2,            0
    };

    if (Switches == 0)
    {
        //Trigger the switch by distance.
        KsCommandStatus digitalCyclicSwitch = WaitForCommand(5, FALSE, SetAxisCyclicSwitch(
            Index,              //Index
            Output,             //Output
            100,                //StartPosition
            cyclicSwitch1,      //CyclicSwitch
            mcDistance,         //IntervalType
            1000,               //Intreval
            mcDistance,         //Durationtype
            3500,               //Duration
            mcSetValue          //ValueSource
        ));
        RtPrintf("Trigger the switch by distance.\n\n");
    }
    else
    {
        //Trigger the switch by time.
        KsCommandStatus digitalCyclicSwitch = WaitForCommand(5, FALSE, SetAxisCyclicSwitch(
            Index,              //Index
            Output,             //Output
            1000,               //StartPosition
            cyclicSwitch2,      //CyclicSwitch
            mcTime,             //IntervalType
            1,                  //Intreval
            mcDistance,         //Durationtype
            3500,               //Duration
            mcSetValue          //ValueSource
        ));
        RtPrintf("Trigger the switch by time.\n\n");
    }

    /*-----Trigger the switch in the first cycle-----*/
    RtPrintf("-----Trigger the switch in the first cycle-----\n\n");
    //Move an axis to trigger a switch.
    RtPrintf("Make an absolute move.\n\n");

    //Start an absolute move.
    KsCommandStatus absolute = WaitForCommand(10, TRUE, MoveAxisAbsolute(Index, 1500,
        1000, 10000, 10000, 1000000, mcPositiveDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero, 1st cycle: %d\n\n", Value);

    /*-----Trigger the switch in the second cycle-----*/
    RtPrintf("-----Trigger the switch in the second cycle-----\n\n");

    Value = 0;
    RtPrintf("Reset output bit to %d.\n\n", Value);

    absolute = WaitForCommand(5, TRUE, MoveAxisAbsolute(Index, 2500,
        1000, 10000, 10000, 1000000, mcPositiveDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero, 2nd cycle: %d\n\n", Value);

    /*-----Trigger the switch in the third cycle-----*/
    RtPrintf("-----Trigger the switch in the third cycle-----\n\n");

    Value = 0;
    RtPrintf("Reset output bit to %d.\n\n", Value);

    absolute = WaitForCommand(5, TRUE, MoveAxisAbsolute(Index, 3500,
        1000, 10000, 10000, 1000000, mcPositiveDirection, mcAborting));
    if (absolute.Error)
        RtPrintf("MoveAxisAbsolute failed: %d\n", absolute.ErrorId);

    //Wait a few cycles to get the correct end positions.
    Sleep(5);

    RtPrintf("End position:\n");
    GetAnAxisPosition(Index);

    ReadOutputBit(2, 0, &Value);

    RtPrintf("Read the output bit corresponding to Track Zero, 3rd cycle: %d\n\n", Value);
}