BUG? CoDeSys AXIS_REF 32bit position rollover

  • Anonymous - 2008-02-19

    Originally created by: Nicolai_Hanssing

    System: CoDeSys with Infranor CD1k CanOpen drives

    Target: WinCE Cybelec

    When using an axis with linear configuration I get some wrong behaviour when the feedback-position (DINT) rolls over at 2^31:

    The raw 32bit feedback-position from the drive is available in:

    AXIS_REF.dwActPosition (OBS: this is unsigned version, but it matches the binary transmission from the drive)

    AXIS_REF.fActPosition - Current actual positon, scaled.

    AXIS_REF.fSetPosition - Current setpoint from Position-profiler, scaled.

    Now all these values are fine until the drive roll-over of the 32bit SIGNED position: 16#80000000 (2^31)

    The setpoint for the drive is continous, when the roll-over hapens (ie. no following error), but is this is by luck i dont know....

    'AXIS_REF.fActPosition' changes sign, and follows the dwActPosition, if that is typecasted into a DINT.

    But 'AXIS_REF.fSetPosition' does not, it continous to grow.

    So you get a large difference (2^32) between fActPosition and fSetPosition. This does not make sense, and is a bug....

    Exspected behaviour would be one of the two below:

    a) Act/Set-Position would both change sign.

    b) Act/Set-Position would both be continous.

    So we have this bug, but is it CoDeSys or is there something wrong with the Drive-libs?

    I have some question I hope some will be able to answer:

    What is the largest linear position, for a linear axis in the profiler?

    How is the relation-ship between fSetPos (From profiler) and Actual command defined, when a roll-over has occured on either feedback or command-setpoint?

    Please feel free to only answer part of the questions in seperate posts.

    I'll try to see if I can provoke more strange behavior.


    Nicolai Hanssing

  • Anonymous - 2008-02-19

    Originally created by: Nicolai_Hanssing

    Changing the axis to a modolu-axis, causes the discrepency to not appear when position-rollover from drive occurs.

    However if I run the axis with modulo, how can I correctly transform the 32bit DINT feedback-value to an actual positionvalue?

    My investigations so far has led me to the follwoing construct:

    (* pAx is a pointer to AXIS_REF. *)
    (* Lets calculate actual position from dwActpos (modulo axis) *)
    Β dwOffset := LREAL_TO_DWORD(pAx^.fOffsetPosition*pAx^.fScalefactor);
    Β ActPosition := 
    Β  ((pAx^.dwActPosition-dwOffset) MOD pAx^.dwOneTurn) / pAx^.fScalefactor;

    Firstoff I need to treat the feedback-value as DW instad of DI?

    Then get the current offset and convert to DW by scalefactor (not precise, anyone know where to get the DW-offsetvalue to avoid rounding-errors?).

    Apply axis modulo as found in AXIS_REF.dwOneTurn.

    However this is not precise!

    I think it is due to rounding-errors in the calculation of dwOffset.

    So anyone have a sure, fast and precise way of transforming a 32bit DINT value to a corresponding AXIS_REF.fActPosition-domain?

    Notes on application: We're reading a 32bit capture-positon in the drive, wich is currently not supported by MC_TouchProbe(), and therefor need to do this conversion.

  • Anonymous - 2008-02-20

    Originally created by: Nicolai_Hanssing

    The lack of precision in previous post, is due to a bug wich I have posted in a new thread.

    I have now found a way(?) to convert an actual 32bit position, and transform it into the TechUnits-domain for a rotary axis (modulo):

    (* Lets try to calculate actual position from dwActpos *)
    (* OBS: pAx : POINTER TO AXIS_REF *)
    ActPosition := ((pAx^.dwActPosition-pAx^.dwPosOffsetForResiduals) MOD pAx^.dwOneTurn)/pAx^.fScalefactor;
    TmpLReal := pAx^.fOffsetPosition-TRUNC(pAx^.fOffsetPosition / pAx^.fPositionPeriod)*pAx^.fPositionPeriod;
    ActPosition := ActPosition - TmpLReal;
    WHILE ActPosition>=pAx^.fPositionPeriod DO
    Β  ActPosition:=ActPosition-pAx^.fPositionPeriod;
    WHILE ActPosition<0 DO
    Β  ActPosition:=ActPosition+pAx^.fPositionPeriod;

    I however dont understand why the value in AXIS_REF.fOffsetPosition is not kept within .fPositionPeriod?

    When perofrming multiple MC_SetPos() calls the value can become extremely large, causing many iterations in the while-loops, wich is inefficient, so I had to add the TRUNC() calculation to keep it O(1) effecient.

    It will also lead to loss of precision eventually when the LREAL value gets big enough!

    I realise that increment-precision is kept until 2^51 for double precision LREAL, but it still seems wrong?

    Is this intended by 3S?




Log in to post a comment.