RapidCode API homing error. Version 10.2.2.0

I get an occasional error when running through my homing routine in a system with 23 axis.
These are Kollmorgen AKD drives.
Each axis homes on its own Thread, and I have been starting them all at roughly at the same time.
Here is the error that is occasionally thrown:
“Timeout Timed out trying to write Service Channel (SDO) (Error 10) (RapidCodeNetworkNode::ServiceChannelWriteCore) (Object 40) (File rapidcodenetworknode.cpp) (Line 450) (Version 10.2.2.0)”

I tried adding a 10ms wait between starting each thread and it seemed to make no difference.

Could anyone help with what may be causing this error and what we can do to prevent it?
Thanks!

Perhaps try this overload and set a higher timeout in milliseconds: ServiceChannelWrite()

The AKDs can also be homed via ASCII instead of SDO for drive based homing if that is of interest to you.

Can you give us your homing code or a snippet that includes the ServiceChannelWrite/AsciiChannel commands used within?

    public void HomeMethod()
    {
        try
        {
            if (Settings.Any(s => s.Disabled)) return;
            lock (_isHomedLock)
                _isHomed = false;
            Error = false;
            var laneNames = string.Join(", ", Settings.Select(s => s.Name).ToList());
            NewMessage($"Homing Initializing {laneNames}...", null);
            // 1. READY DRIVE
            Axis.OperationModeSet(RSIOperationMode
                .RSIOperationModeHOMING_MODE); // Mode of Operation set to Homing Mode.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "DRV.OPMODE 2"); // Sets the drive operation mode (0 - current | 1 = velocity | 2 = position).
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.AUTOMOVE 0"); // 0 = Disabled | 1 = Homing starts when drive is enabled.
            // Make sure you know your motor's position, velocity, and acceleration units before you send any values.                

            // 2. SET YOUR LIMIT SWITCHES
            Axis.NetworkNode
                .AKDASCIICommand(
                    "DIN1.MODE 0"); // Sets the digital input modes. - DI1 is now our Home Switch.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "DIN1.INV 0"); // Sets the indicated polarity of a digital input mode. - DI1 is now active when High.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "DIN2.MODE 0"); // Sets the digital input modes.                        
            Axis.NetworkNode
                .AKDASCIICommand("DIN2.INV 0"); // Sets the indicated polarity of a digital input mode. 
            Axis.NetworkNode
                .AKDASCIICommand(
                    "DIN3.MODE 11"); // Sets the digital input modes.                        
            Axis.NetworkNode
                .AKDASCIICommand("DIN3.INV 0"); // Sets the indicated polarity of a digital input mode. 

            // 3. CONFIGURE DRIVE HOMING PARAMETERS
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.MODE 16"); // Selects the homing method; active in opmode 2 (position) only. MODE 16 = Find Home switch using dual edges
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.V 0.2"); // Sets homing velocity; active in opmode 2 (position) only.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.ACC 1"); // Sets homing acceleration; active in opmode 2 (position) only.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.DEC 1"); // Sets homing deceleration; active in opmode 2 (position) only.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.DIR 1"); // Sets homing direction; active in opmode 2 (position) only. (0 = negative | 1 = positive)
            Axis.NetworkNode
                .AKDASCIICommand("HOME.P 0"); // Sets home position; active in opmode 2 (position) only.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.DIST 0"); // Sets homing distance; active in opmode 2 (position) only.
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.MAXDIST 0"); // Sets the maximum distance the motor is allowed to move during the homing routine. (Disabled when value = 0)
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.IPEAK 6"); // Sets the current limit during homing procedure to a mechanical stop; active in opmode 2 (position) only.

            // 4. READY AXIS
            Axis.ErrorLimitActionSet(RSIAction.RSIActionNONE);
            Axis.Abort(); // Disable axis.
            Axis.ClearFaults(); // Clear any faults.
            Axis.AmpEnableSet(true); // Enable the axis.
            Thread.Sleep(100); // Allow time for amp enable


            NewMessage("Homing Started...", null);
            lock (_cancelHomingLock)
            {
                if (_cancelHoming)
                    throw new Exception("Homing Cancelled");
            }

            // 5. START HOMING
            Axis.NetworkNode
                .AKDASCIICommand(
                    "HOME.MOVE"); // Starts a homing procedure; active in opmode 2 (position) only.

            var now = DateTime.UtcNow.ToLocalTime();
            var timeout = now.AddSeconds(10);

            // 6. CHECK IF HOMING IS DONE
            var isHomedvalue = 0;
            var isHomeErrorValue = false;
            while (isHomedvalue != 1 &&
                   DateTime.UtcNow.ToLocalTime() < timeout) // When isHomedValue = 1, homing has finished.
            {
                var statusWordValue = Axis.NetworkNode.StatusWordGet(Settings[0].AxisIndex);
                isHomedvalue =
                    statusWordValue >>
                    12; // Get the 12th bit only. This bit tells us homing is done when it goes HIGH.
                isHomeErrorValue =
                    (statusWordValue >>
                     13) == 1; // Get the 13th bit only. This bit tells us homing is in error when it goes HIGH.

                lock (_cancelHomingLock)
                {
                    if (_cancelHoming)
                    {
                        Axis.Stop();
                        Axis.AmpEnableSet(false);
                        throw new Exception("Homing Cancelled");
                    }
                }

                if (isHomeErrorValue) break;
            }

            Error = DateTime.UtcNow.ToLocalTime() >= timeout || isHomeErrorValue;

            NewMessage($"Homing {(Error ? "Failed" : "Successful")}", null);

            // 7. CLEAN UP
            Axis.OriginPositionSet(0.0);
            Axis.Abort(); // Disable the axis.
            Axis.OperationModeSet(RSIOperationMode
                .RSIOperationModeINTERPOLATED_POSITION_MODE); // Mode of Operation Restore
            Axis.ErrorLimitActionSet(RSIAction
                .RSIActionNONE); // Restore the position error action to whatever you want it to be.
            Axis.ClearFaults();
            Thread.Sleep(100);
            HelperFunctions
                .CheckErrors(Axis); // [Helper Function] Check that the axis has been initialize correctly.
            Axis.ClearFaults();
            lock (_cancelHomingLock)
            {
                Axis.AmpEnableSet(!_cancelHoming);
                if (_cancelHoming)
                    throw new Exception("Homing Cancelled");
            }

            Axis.MoveRelative(Settings[0].HomingOffset, 1.0, 1.0, 1.0, Settings[0].JerkPct);
            Axis.MotionDoneWait(10000);
            var homed = Axis.StateGet() == RSIState.RSIStateIDLE;

            lock (_isHomedLock)
                _isHomed = homed;

            NewMessage($"Homing {(homed ? "Complete" : "Fault")}. Axis State: {Axis.StateGet()}", null);
        }
        catch (Exception e)
        {
            Error = true;
            NewMessage(
                $"{MethodBase.GetCurrentMethod().Name} AxisIndex: {Settings[0].AxisIndex} Error: {e.Message}",
                new HomingSequenceError($"Homing Exception for {Settings[0].Name}", e.Message));
        }

        lock (_cancelHomingLock)
        {
            _cancelHoming = false;
        }
    }

I also see the error happen in this simpler method used by some of the other axis in the system:

    private void HomeMethod()
    {
        try
        {
            lock (_isHomedLock)
                _isHomed = false;
            Error = false;
            NewMessage("Homing Initializing...", null);
            Axis.PositionSet(0); // Sets the current position as 0 effectively 'homing' it. 
            Axis.Abort(); // Disable the axis.
            Axis.ClearFaults();
            Axis.NetworkNode.ServiceChannelWrite(
                Settings.ModeOfOpIndex,
                Settings.ModeOfOpSubindex,
                Settings.ModeOfOpByteSize,
                Settings.ModeOfOpValueToDefault); // Mode of Operation (Homing Mode = 6)
            Thread.Sleep(1000);
            HelperFunctions
                .CheckErrors(Axis); // [Helper Function] Check that the axis has been initialize correctly.
            Axis.ClearFaults();
            lock (_cancelHomingLock)
            {
                Axis.AmpEnableSet(!_cancelHoming);
                if (_cancelHoming)
                {
                    throw new Exception("Homing Cancelled");
                }
            }

            lock (_isHomedLock)
                _isHomed = true;

            NewMessage($"Homing Complete. Axis State: {Axis.StateGet()}", null);
        }
        catch (Exception e)
        {
            Error = true;
            NewMessage($"{MethodBase.GetCurrentMethod().Name} AxisIndex: {Settings.AxisIndex} Error: {e.Message}",
                new HomingSequenceError($"Homing Exception on {Settings.Name}", e.Message));
        }

        lock (_cancelHomingLock)
        {
            _cancelHoming = false;
        }
    }

Hey,

I believe the problem is occurring when you call Axis.OperationModeSet in the first case and Axis.NetworkNode.ServiceChannelWrite to do the same thing in the second.

It sounds like there are some cases where your drive is slow to transition or somehow fails to transition modes. I see three different patterns.

(1) 1. READY DRIVE.
Here you don’t seem to be doing anything to interrupt other possible motion. I’d Abort(); ClearFaults(); first something you do in stage 4. You can move those lines up to the start of 1.

(2) 7. CLEAN UP
Here you Abort(); Switch Modes. ClearFaults();

(3) 2nd example
Here you Abort(); ClearFaults(); Switch Modes.


Can you tell when you get the failure when using your Public HomeMethod does Homing actually take place? This would determine if the failure was (1) or (2) or both?

When in the failure state if you check the Mode of Operation does it ultimately succeed or fail? Compare the desired/actual (0x6061) If it does slowly get there, we can use overloads for extra time if needed.

Jacob,
I am not sure exactly where the error was happening at.
This code has been running unchanged for a couple of months while running testing, but after some changes in the higher level control system last week, we began to see this error pop up.

I cannot confirm whether the Axis was able to finish homing after the Exception was raised. The operator has been restarting the system whenever they saw the error.

As soon as I can take the system down, then I will try to run some tests to see if we can pinpoint a problem.

You may be able to prevent it by switching to Axis.OperationModeSet to Axis.NetworkNode.ServiceChannelWrite while using a longer timeout overload. You could try it with a long timeout to see if that prevents the problem from occurring completely.

Hopefully I can try this tomorrow sometime.
Thank you!

Today I updated and ran the application using the Axis.NetworkNode.ServiceChannelWrite() method in both homing routines.
I set the timeout to 1000msec.
I did not see any more homing errors after testing it through about 5 system restarts.
It looks like this has resolved this issue.
If not, then I will update this thread.
Thanks!