langJapanese
HOME > RT-C Language Controller > Sample "Servo Motor Control"
> Sample for RT-C Language Controller <

 Sample for Servo Motor Control
1. Contents of Sample for Servo Motor Control
Servo motor axix makes 30 rotations from side to side. (60 rotations in total)
 The time from rotation start to stop is 8 ms (acceleration and deceleration).
 The time to target speed is 1sec.
 ※We control it according to CiA402 rule.
 

■Equipments
RT-C Language Controller
RSI-ECAT-Master/DC
Servo Amp:Sanyo RS2E01A0KA4
Servo Motor:Sanyo R2EA04003FXP00

2. Method of Position Control
(1) We provide servo amp with predetermined positon data at regular intervals to control position.
(2) To contro acceleration and deceleration depends on amount of change of above position data
(3) The following chart is velocity diagram and position diagram.(Right rotation is forward.)
velocity diagram
position diagram


3. Flow
(1)EtherCAT® Communication OPEN
次へ ① Do RSI-ECAT-Master OPEN process
(2)ESM goes to OPERATION
次へ ① EtherCAT® state goes to OPERATIONAL
② Then, check whether state change is finished or not. after that go to next step.
(3)Detect Servo Slave
次へ ① Detect target Servo Amp
② Get "Alias" and "R/W position on Process Image" of servo to use it as position control parameter     settings
(4)Settings for servo operation mode
次へ ① Set as "Cycle Synchronous Position Mode"
② You can change by setting object "Modes of Operation" as "8".
(5)Initialize command position to current position.
次へ ① Set value of command position as value of current position.
② It is because of prevention for rapid movement to unexpected position when servo turns ON.
③ Read value of "Actual Position" and write this value to "Target position".
(6)Go to Servo ON state
next ① Go to Servo ON state. When Servo is ON, servo motre is in an overexcitation state.
② Let "PDS (Power Drive System)" move to "Operation Enabled".
③ Set value to "Control word", check state in "Status word" (On more details, please check CiA402     specification.)
(7)Waiting process for Servo brake release
次へ ① Wait for 1 sec to wait for Servo brake release
(8)Position Controll Process
① Predefined position information are notified to servo amp in order per the period of __Process() call.
② It does acceleration and deceleration with right 30 rotation (4 sec) & left 30 rotation (4 sec) - total 60     rotation (8 sec).


4.Program (C# Source Code)
namespace MotionDemo
{
    [FUNCTION_BLOCK]
    public class program
    {

        /***********************************************************************
         * SLAVE DEFINE
        ************************************************************************/
        private readonly static uint VENDOR_ID    = 441;
        private readonly static uint PRODUCT_CODE = 2;
        private readonly static uint REVISION_NO  = 3;

        // PI/IN
        private readonly static uint STATUSWORD_OFFSET  = 0;
        private readonly static uint POS_ACUTUAL_OFFSET = 4;
        // PI/OUT
        private readonly static uint CONTROLWORD_OFFSET = 0;
        private readonly static uint TARGET_POS_OFFSET  = 2;

        public Boolean IsError         = false;
        public Boolean IsDone          = false;
        private EhApi hEcat            = null;
        private ushort Alias           = 0;
        private uint ViosInBaseOffset  = 0;
        private uint ViosOutBaseOffset = 0;
        private uint ActualPos         = 0;
        private uint TargetPos         = 0;
        private ushort ControlWord     = 0;
        private ushort StatusWord      = 0;
        private uint rcpIdx            = 0;
        private uint loopCnt           = 0;
        private Recipe recipeData      = null;


        /***********************************************************************
        * Constructor
        ************************************************************************/
        public program()
        {
            hEcat = new EhApi();

        }

        private bool EndProcess()
        {
            IsDone = true;
            return IsDone;
        }

        private bool ErrorInit()
        {
            IsError = true;
            return IsError;
        }


        /***********************************************************************
        *CiA402 Servo Driver state transition process
        ************************************************************************/
        ushort fnChgMotionGoState(ushort woStWd, ref ushort pCrWd)
        {
            switch ((0x6F & woStWd))
            {
                // Not initialized -> Request initialization
                case 0x00: pCrWd = (ushort)((0xFF70 & pCrWd) | 0x00); break;

                // Initialized -> Request turn off main circuit power
                case 0x40:  // (0x60と同じ)
                case 0x60: pCrWd = (ushort)((0xFF70 & pCrWd) | 0x06); break;

                // Main circuit power OFF -> Request servo ready
                case 0x21: pCrWd = (ushort)((0xFF70 & pCrWd) | 0x07); break;

                // Servo ready -> Request turn on Servo
                case 0x23: pCrWd = (ushort)((0xFF70 & pCrWd) | 0x0F); break;

                // Servo  ON (=Start operation is OK.)
                case 0x27: break;

                // Abnornal State
                case 0x2F: break;

                // Abnornal State -> Request initialization
                case 0x28: pCrWd = (ushort)((0xFF70 & pCrWd) | 0x80); break;
            }
            return (ushort)(0x6F & woStWd);
        }


        /***********************************************************************
        *Init Process (__Init() is once execued when program is booted)
        ************************************************************************/
        public void __Init()
        {

            ushort Status = 0;

            Console.WriteLine(\"\\n === Start Program ===\");

            // Read recipe data
            recipeData = new Recipe(\"C:\\\\ReceipeData.dat\");


            //========================
            //(1)EtherCAT® communication OPEN
            //========================
            Status = hEcat.EhOpen();
            if (0 != Status)
            {
                Console.WriteLine(\"EhOpen is failed.\");
                ErrorInit();
                return;
            }

            //========================
            //(2)Go to ESMをOPERATION
            //========================
            Status = hEcat.EhRqState(8);
            if (0 != Status)
            {
                Console.WriteLine(\"EhRqState is failed.\");
                ErrorInit();
                return;
            }


            //========================
            //(3)Detect Servo Slave
            //========================
            Status = hEcat.EhFindSlave(VENDOR_ID,
                                       PRODUCT_CODE,
                                       REVISION_NO,
                                       out Alias,
                                       out ViosInBaseOffset,
                                       out ViosOutBaseOffset);
            if (0 != Status)
            {
                Console.WriteLine(\"EhFindSlave is failed.\");
                ErrorInit();
                return;
            }


            //========================
            //(4)Set Servo operation mode(request change to cyclic synchronous position mode)
            //========================
            Status = hEcat.EhWriteODByAlias(Alias, 0x6060, 0x00, 8, 0, 1);
            if (0 != Status)
            {
                Console.WriteLine(\"EhWriteODByAlias is failed.\");
                ErrorInit();
                return;
            }


            //========================
            //(5)Initialize command position to current position
            //========================

            // Get current position
            //-----------------------
            Status = hEcat.EhReadDword(ViosInBaseOffset + POS_ACUTUAL_OFFSET,
                                       out ActualPos);
            if (0 != Status)
            {
                Console.WriteLine(\"EhReadDword is failed.\");
                ErrorInit();
                return;
            }


            // Write current position
            //-----------------------
            TargetPos = TargetPos + ActualPos;
            Status = hEcat.EhWriteDword(ViosOutBaseOffset + TARGET_POS_OFFSET,
                                        TargetPos);
            if (0 != Status)
            {
                Console.WriteLine(\"EhWriteDword is failed.\");
                ErrorInit();
                return;
            }


            //========================
            //(6)Go to Serve ON state
            //========================

            // Get current servo driver state
            //-----------------------
            while (true)
            {
                ControlWord = 0;

                // Wait for cyclic process
                Status = hEcat.EhWaitForCyclic(EhApi.NO_WAIT);
                if (EhApi.ER_EHAPI_TIMEOUT == Status)
                {
                    return;
                }
                if (0 != Status)
                {
                    // End since cyclic process is interrupted
                    Console.WriteLine(\"EhWaitForCyclic is failed.\");
                    ErrorInit();
                    return;
                }

                // Get current servo driver state
                Status = hEcat.EhReadWord(ViosInBaseOffset + STATUSWORD_OFFSET,
                                          out StatusWord);
                if (0 != Status)
                {
                    Console.WriteLine(\"EhReadWord is failed.\");
                    ErrorInit();
                    return;
                }

                // Get COntrolword value for next PDS state transition
                if (0x27 == fnChgMotionGoState(StatusWord, ref ControlWord))
                {
                    // [Servo ON is done]:to waiting for brake release
                    break;
                }

                // Write next servo diver transition value
                Status = hEcat.EhWriteWord(ViosOutBaseOffset + CONTROLWORD_OFFSET,
                                           ControlWord);
                if (0 != Status)
                {
                    Console.WriteLine(\"EhWriteWord is failed.\");
                    ErrorInit();
                    return;
                }
            }


            //========================
            //(7)Wait process for Servo brake release (according to Sanyo servo specification)
            //========================
            Thread.Sleep(1000);
        }


        /***********************************************************************
        * Regular interval period method (function called at 1msec interval)
        ************************************************************************/
        public void __Process()
        {

            // State judgement
            if (IsDone)  { return; }
            if (IsError) { return; }


            //========================
            //(8)Position Control Process
            //========================

            // Wait for cyclic process
            ushort Status = 0;
            Status = hEcat.EhWaitForCyclic(EhApi.NO_WAIT);
            if (EhApi.ER_EHAPI_TIMEOUT == Status)
            {
                return;
            }
            if (0 != Status)
            {
	            // End since cyclic process is interrupted
                Console.WriteLine(\"EhWaitForCyclic is failed.\");
                EndProcess();
            }

            // Request movement per loop
            TargetPos = recipeData.Data[rcpIdx] + ActualPos;// Refresh requied position
            hEcat.EhWriteDword(ViosOutBaseOffset + TARGET_POS_OFFSET, TargetPos);

            // Refresh target position
            loopCnt++;
            if (loopCnt < recipeData.Data.Length)
            {
                rcpIdx++; // Forward
            }
            else
            {
                rcpIdx--; // Reverse
            }

            // Completion Judgement
            if (loopCnt >= (recipeData.Data.Length * 2) - 1)
            {
                // All movement (to defined position) is complete.
                EndProcess();       // Process End
            }
        }
    }

}