Start the KINGSTAR Subsystem

In Configure the settings, you have learned how to use the variables to configure the KINGSTAR settings in SystemInitialization.h. In this section, you'll learn how to pass the variables to the functions that configure KINGSTAR settings, and start the KINGSTAR Subsystem.

Functions and structures

In this section, the following functions and structures are used.

Start the KINGSTAR Subsystem

  1. Double-click SystemInitialization.cpp to open it.
  2. In SystemInitialization.cpp, add the following code to include RT_Project_01.h and SystemInitialization.h.
  3. Copy
    #include "RT_Project_01.h"
    #include "SystemInitialization.h"
  4. Next, we are adding the functions to create an EtherCAT link and configure KINGSTAR settings. Each function has an if statement to detect whether the function is run successfully. We create the variable nRet of the KsError enum type and use it to receive the return value from each function.
  5. Under #include "SystemInitialization.h", add the following code:

    Copy
    BOOL StartKingstar()
    {
        //Launch or connect to the KINGSTAR Subsystem process.
        KsError nRet = errNoError;
        nRet = Create(INSTANCE, 0);
        if (nRet != errNoError)
        {
            RtPrintf("InitializeLink failed: %x\n", nRet);
            return FALSE;
        }

        //Configure the Subsystem settings. We set it cycle500.
        //You can find the corresponding cycle time in ksapi.h.
        //Time unit: second.
        /*cycle100 = 0.0001
          cycle125 = 0.000125
          cycle250 = 0.000250
          cycle500 = 0.0005
          cycle1000 = 0.001*/
        nRet = SetCycleTime(CYCLE_TIME);
        if (nRet != errNoError)
        {
            RtPrintf("SetCycleTime failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        /*We use accessPos, which supports modeDirectPos, modeMasterIntPos, and modeManual.
          By default, it uses modeMasterIntPos.*/
        nRet = SetAxisAccessMode(ACCESS_MODE);
        if (nRet != errNoError)
        {
            RtPrintf("SetAxisAccessMode failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //VERBOSITY is FALSE.
        nRet = EnableServerLog(VERBOSITY);
        if (nRet != errNoError)
        {
            RtPrintf("EnableServerLog failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //SERVO_INPUT is TRUE.
        nRet = EnableAxisInput(SERVO_INPUT);
        if (nRet != errNoError)
        {
            RtPrintf("EnableAxisInput failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //SERVO_OUTPUT is FALSE.
        nRet = EnableAxisOutput(SERVO_OUTPUT);
        if (nRet != errNoError)
        {
            RtPrintf("EnableAxisOutput failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //SECOND_ENCODER is FALSE.
        nRet = EnableSecondEncoder(SECOND_ENCODER);
        if (nRet != errNoError)
        {
            RtPrintf("EnableSecondEncoder failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //ACTUAL_VELOCITY is TRUE.
        nRet = EnableActualVelocity(ACTUAL_VELOCITY);
        if (nRet != errNoError)
        {
            RtPrintf("EnableActualVelocity failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //ACTUAL_TORQUE is TRUE.
        nRet = EnableActualTorque(ACTUAL_TORQUE);
        if (nRet != errNoError)
        {
            RtPrintf("EnableActualTorque failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //ACTUAL_CURRENT is TRUE.
        nRet = EnableActualCurrent(ACTUAL_CURRENT);
        if (nRet != errNoError)
        {
            RtPrintf("EnableActualCurrent failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //FOLLOWING_ERROR is TRUE.
        nRet = EnableFollowingError(FOLLOWING_ERROR);
        if (nRet != errNoError)
        {
            RtPrintf("EnableFollowingError failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //MAX_TORQUE is FALSE.
        nRet = EnableMaxTorque(MAX_TORQUE);
        if (nRet != errNoError)
        {
            RtPrintf("EnableMaxTorque failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //MAX_CURRENT is FALSE.
        nRet = EnableMaxCurrent(MAX_CURRENT);
        if (nRet != errNoError)
        {
            RtPrintf("EnableMaxCurrent failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        /*Enable the control mode change through PDO. This way, you can change
          the control mode while the drive is enabled, but when you change the mode,
          the motor can't be running. Not all drives support this feature.*/

        //SYNCHORNIZED_CONTROL_MODE is TRUE.
        nRet = EnableSynchronizedControlMode(SYNCHORNIZED_CONTROL_MODE);
        if (nRet != errNoError)
        {
            RtPrintf("EnableSynchronizedControlMode failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
         }
         
        //AUTO_RESTART is TRUE.
        nRet = EnableAutoRestart(AUTO_RESTART);
        if (nRet != errNoError)
        {
            RtPrintf("EnableAutoRestart failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //AUTO_REPAIR is TRUE.
        nRet = EnableAutoRepair(AUTO_REPAIR);
        if (nRet != errNoError)
        {
            RtPrintf("EnableAutoRepair failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //AUTO_CONFIG is TRUE.
        nRet = EnableAutoConfig(AUTO_CONFIG);
        if (nRet != errNoError)
        {
            RtPrintf("EnableAutoConfig failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }

        //ENABLE_DC is TRUE, DC_CHECK is TRUE, DC_MASTER_SHIFT is FALSE.
        nRet = ConfigureDc(ENABLE_DC, DC_CHECK, DC_MASTER_SHIFT, 0);
        if (nRet != errNoError)
        {
            RtPrintf("ConfigureDc failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //HOT_CONNECT is FALSE.
        nRet = EnableHotConnect(HOT_CONNECT);
        if (nRet != errNoError)
        {
            RtPrintf("EnableHotConnect failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //REDUNDANCY is FALSE.
        nRet = EnableRedundancy(REDUNDANCY);
        if (nRet != errNoError)
        {
            RtPrintf("EnableRedundancy failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
  6. After the settings are configured, we add simulated axes and I/O modules. To create simulated axes, we use SetConfiguredAxesCount, in which fill a number for simulated axes and they'll be created.
  7. Creating simulated I/O modules need a little more effort. The following process shows how to create simulated I/O modules:

    SetConfiguredIoCount -> Create an instance of SlaveStatus structure -> Set input and output length of the instance -> ConfigureIo

    First, we use SetConfiguredIoCount to set the number of simulated I/O modules, which is determined by how much the given value exceeds the number of the real hardware. If the given number is greater than the number of the real I/Os, KINGSTAR will display all real I/Os plus simulated ones. For example, if you have five real I/Os and you set the number seven in SetConfiguredIoCount, you'll get five real I/Os plus two simulated I/Os. If the given number is less than or equal to the number of the real I/Os, KINGSTAR will display all real I/Os without simulated ones.

    Next, we create the instance simulatedIo of the SlaveStatus structure. Then, we set simulatedIo.InputLength and simulatedIo.OutputLength. Finally, we use ConfigureIo to apply the length settings to the simulated I/Os. You must assign values to InputLength and OutputLength for simulated I/Os, so they have inputs and outputs to contain data. Other fields will be filled with default values by the KINGSTAR Subsystem.

    Under the block of EnableRedundancy, add the following code:

    Copy
        //AXES_COUNT is two.
        nRet = SetConfiguredAxesCount(AXES_COUNT);
        if (nRet != errNoError)
        {
            RtPrintf("SetConfiguredAxesCount failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //IO_COUNT is three.
        nRet = SetConfiguredIoCount(IO_COUNT);
        if (nRet != errNoError)
        {
            RtPrintf("SetConfiguredIoCount failed: %x\n", nRet);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
        
        //IO_INPUT_LENGTH is 16. IO_OUTPUT_LENGTH is 16.
        SlaveStatus simulatedIo = { 0 };
        simulatedIo.InputLength = IO_INPUT_LENGTH;
        simulatedIo.OutputLength = IO_OUTPUT_LENGTH;
        for (int i = 0; i < IO_COUNT; i++)
        {
            nRet = ConfigureIo(i, simulatedIo);
            if (nRet != errNoError)
            {
                RtPrintf("ConfigureIo failed: %x\n", nRet);
                WaitForCommand(5, FALSE, Stop());
                Destroy();
                return FALSE;
            }
        }
  8. After all the settings are done, we use Start to start the KINGSTAR Subsystem. We use WaitForCommand to wait 30 seconds for Start. If the KINGSTAR Subsystem is not started within the given time, Start will be aborted.
  9. Under the block of SlaveStatus simulatedIo = { 0 }, add the following code:

    Copy
        //Start the EtherCAT network.
        //This function is asynchronous so the network is not started yet when it returns.
        /*Some hardware may require more than 30 seconds to start because DC check needs
          some time to complete.*/
        KsCommandStatus status = WaitForCommand(40, TRUE, Start());
        if (status.Error)
        {
            RtPrintf("Start failed: %d\n", status.ErrorId);
            WaitForCommand(5, FALSE, Stop());
            Destroy();
            return FALSE;
        }
  10. After Start is used, the KINGSTAR Subsystem is being started and the EtherCAT link between the Subsystem and the hardware is being created. To make sure everything is working, we use the following process to check it:
  11. Create an instance of the SubsystemStatus structure -> GetStatus -> Use an if-else statement to detect whether the EtherCAT link is successfully created

    First we create an instance of the SubsystemStatus structure, which represents the EtherCAT link created by Create. Then, we use GetStatus to get the state of the link. The if-else statement is used to check whether the data member State is equal to ecatOP, which means the link is created successfully.

    Under the block of KsCommandStatus status = WaitForCommand(40, TRUE, Start()), add the following code. This is the last part of the code in StartKingstar. We add return TRUE before the last curly brace. If all the if statements above are FALSE, the StartKingstar is run successfully and returns TRUE.

    Copy
        SubsystemStatus Subsystem = { ecatOffline, ecatOffline, 0, 0, 0, {ecatOffline}, {ecatOffline}, {axisOffline} };
        GetStatus(&Subsystem, NULL);
        if (Subsystem.State != ecatOP && Subsystem.State != ecatOffline)
        {
            RtPrintf("The KINGSTAR Subsystem in an unexpected state: %d\n", Subsystem.State);
            return FALSE;
        }
        
        return TRUE;
    }