سابعا: تصميم Incremental Encoder


0048

0049 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 0060

سابعا: تصميم Incremental Encoder

يعمل هذا المشفر بثلاثة إشارات ضوئية تمر عبر مسننات مشفرة بطريقة خاصة، بحيث يكون خرج إحدى الإشارات هو قطار من النبضات المربعة يمكن استخدامها في التعرف على موضع المحرك وسرعته، كما يتم إضافة قطار آخر من النبضات المماثلة بإزاحة 90 درجة لكي نتمكن من معرفة جهة دوران المحرك. ثم تتم إضافة إشارة ثالثة تقوم بإعطاء نبضة مربعة كلما دار المحرك دورة كاملة. هذه الإشارات هي A, B, Z على الترتيب.

نصمم الدارة التالية:

حيث أن برمجة المحرك هي البرمجة الكلاسيكية الأولى:

/*

 * DC-Servo Motor Modelling

 * Copyright (c) 2006 by University of Aleppo

 *  All Rights Reserved

 */

#define S_FUNCTION_NAME DC_Motor

#include <stddef.h>

#include <stdlib.h>

#include <math.h>

#include “simstruc.h”

#ifdef MATLAB_MEX_FILE

#include “mex.h”

#endif

#define SAMPLE_TIME_ARG         ssGetArg(S,0)

#define Ra_Arg                  ssGetArg(S,1)

#define La_Arg                  ssGetArg(S,2)

#define J_Arg                   ssGetArg(S,3)

#define B_Arg                   ssGetArg(S,4)

#define Cpsi_Arg                ssGetArg(S,5)

#define NUMBER_OF_ARGS          (6)

#define NSAMPLE_TIMES           (1)

#define NUMBER_OF_INPUTS        (2)  //U=[Ua,T_L]

#define NUMBER_OF_OUTPUTS       (3) // x=[ia wr theta_r] state vector

float tsam,Ra,La,J,B,Cpsi;

float ia_k_1,ia_k,wr_k,wr_k_1,theta_k_1,theta_k,u_k,Tl_k;

static void mdlInitializeSizes(SimStruct *S)

{

    if (ssGetNumArgs(S) != NUMBER_OF_ARGS) {

#ifdef MATLAB_MEX_FILE

    mexErrMsgTxt(“Wrong number of input arguments passed.\nThree arguments are expected\n”);

#endif

    }

    /* Set up size information */

    ssSetNumContStates(    S, 0);      /* number of continuous states */

    ssSetNumDiscStates(    S, 5);      /* number of discrete states */

    ssSetNumInputs(        S, NUMBER_OF_INPUTS);      /* number of inputs */

    ssSetNumOutputs(       S, NUMBER_OF_OUTPUTS);      /* number of outputs */

    ssSetDirectFeedThrough(S, 0);      /* direct feedthrough flag */

    ssSetNumSampleTimes(   S, NSAMPLE_TIMES);      /* number of sample times */

    ssSetNumInputArgs(     S, NUMBER_OF_ARGS);      /* number of input arguments */

    ssSetNumRWork(         S, 0);      /* number of real work vector elements */

    ssSetNumIWork(         S, 0);      /* NUMBER_OF_IWORKS);      /* number of integer work vector elements */

    ssSetNumPWork(         S, 0);      /* number of pointer work vector elements */

}

static void mdlInitializeSampleTimes(SimStruct *S)

{

    ssSetSampleTimeEvent(S, 0, mxGetPr(SAMPLE_TIME_ARG)[0]);

    ssSetOffsetTimeEvent(S, 0, 0.0);

}

static void mdlInitializeConditions(double *x0, SimStruct *S)

{

    /*Sampling Time*/

    tsam = mxGetPr(SAMPLE_TIME_ARG)[0];

    Ra = mxGetPr(Ra_Arg)[0];

    La = mxGetPr(La_Arg)[0];

    J  = mxGetPr(J_Arg)[0];

    B = mxGetPr(B_Arg)[0];

    Cpsi = mxGetPr(Cpsi_Arg)[0];

    /* States initialization*/

    ia_k_1=0;

    wr_k_1=0;

    theta_k_1=0;

//     Ra=11.8;    //armuture resistance ohm

//     La=0.2;     //armuture induction

//     Cpsi=0.945; //back emf constant vs/rad

//     J=0.009;   //moment of inertia kg

//     B=0.0006;  //friction constant

}

static void mdlOutputs(double *y, double *x, double *u, SimStruct *S, int tid)

{

    y[0]=ia_k_1;    /*Vo*/

    y[1]=wr_k_1;

    y[2]=theta_k_1;

}

static void mdlUpdate(double *x, double *u, SimStruct *S, int tid)

{

    //Model Update

    u_k = u[0];

    Tl_k = u[1];

    ia_k = (-((Ra/La)*ia_k_1)-((Cpsi/La)*wr_k_1)+(u_k/La))*tsam+ia_k_1;

    wr_k = (((Cpsi/J)*ia_k_1)-((B/J)*wr_k_1)-(Tl_k/J))*tsam+wr_k_1;

    theta_k = (wr_k_1*tsam)+theta_k_1;

    ia_k_1 = ia_k;       //update value

    wr_k_1 = wr_k;       //update value

    theta_k_1 = theta_k; //update value

    if (theta_k_1 >= 6.283185307179586)

    {

        theta_k_1 = theta_k_1 – 6.283185307179586;

        theta_k = theta_k – 6.283185307179586;

    }

    else if (theta_k_1 < 0)

    {

        theta_k_1 =theta_k_1 + 6.283185307179586;

        theta_k = theta_k + 6.283185307179586;

    }

}

/*

 * mdlDerivatives – compute the derivatives

 *

 * In this function, you compute the S-function block’s derivatives.

 * The derivatives are placed in the dx variable.

 */

static void mdlDerivatives(double *dx, double *x, double *u, SimStruct *S, int tid)

{

}

/*

 * mdlTerminate – called when the simulation is terminated.

 *

 * In this function, you should perform any actions that are necessary

 * at the termination of a simulation.  For example, if memory was allocated

 * in mdlInitializeConditions, this is the place to free it.

 */

static void mdlTerminate(SimStruct *S)

{

}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */

#include “simulink.c”      /* MEX-file interface mechanism */

#else

#include “cg_sfun.h”       /* Code generation registration function */

#endif

أما برمجة الـ Incremental Encoder فهي كالتالي:

/*

 * DC-Servo Motor Modelling

 * Copyright (c) 2006 by University of Aleppo

 *  All Rights Reserved

 */

#define S_FUNCTION_NAME Incremental_Enc

#include <stddef.h>

#include <stdlib.h>

#include <math.h>

#include “simstruc.h”

#ifdef MATLAB_MEX_FILE

#include “mex.h”

#endif

#define SAMPLE_TIME_ARG         ssGetArg(S,0)

#define PulsePerRotate_ARG      ssGetArg(S,1)

#define NUMBER_OF_ARGS          (2)

#define NSAMPLE_TIMES           (1)

#define NUMBER_OF_INPUTS        (1) //wr

#define NUMBER_OF_OUTPUTS       (6) // A,B,Z

float M_2PI = 6.283185307179586;

float Ts, PulsePerRotate, Resolution, Resolution_Rev;

int A, B, Z;

float wr_k, theta_r, theta_r_1, theta_1, theta_1_1, theta_N;

static void mdlInitializeSizes(SimStruct *S)

{

    if (ssGetNumArgs(S) != NUMBER_OF_ARGS) {

#ifdef MATLAB_MEX_FILE

    mexErrMsgTxt(“Wrong number of input arguments passed.\nThree arguments are expected\n”);

#endif

    }

    /* Set up size information */

    ssSetNumContStates(    S, 0);      /* number of continuous states */

    ssSetNumDiscStates(    S, 1);      /* number of discrete states */

    ssSetNumInputs(        S, NUMBER_OF_INPUTS);      /* number of inputs */

    ssSetNumOutputs(       S, NUMBER_OF_OUTPUTS);      /* number of outputs */

    ssSetDirectFeedThrough(S, 0);      /* direct feedthrough flag */

    ssSetNumSampleTimes(   S, NSAMPLE_TIMES);      /* number of sample times */

    ssSetNumInputArgs(     S, NUMBER_OF_ARGS);      /* number of input arguments */

    ssSetNumRWork(         S, 0);      /* number of real work vector elements */

    ssSetNumIWork(         S, 0);      /* NUMBER_OF_IWORKS);      /* number of integer work vector elements */

    ssSetNumPWork(         S, 0);      /* number of pointer work vector elements */

}

static void mdlInitializeSampleTimes(SimStruct *S)

{

    ssSetSampleTimeEvent(S, 0, mxGetPr(SAMPLE_TIME_ARG)[0]);

    ssSetOffsetTimeEvent(S, 0, 0.0);

}

static void mdlInitializeConditions(double *x0, SimStruct *S)

{

    Ts = mxGetPr(SAMPLE_TIME_ARG)[0];        /*Sampling Time*/

    PulsePerRotate = mxGetPr(PulsePerRotate_ARG)[0];

    /* States initialization*/

    theta_r_1=0;

    theta_1_1=0;

    Resolution = M_2PI / PulsePerRotate;    //(2*pi)/256

    Resolution_Rev = PulsePerRotate / M_2PI;    //256/(2*pi)

}

static void mdlOutputs(double *y, double *x, double *u, SimStruct *S, int tid)

{

    y[0] = A;

    y[1] = B;

    y[2] = Z;

    y[3] = theta_r;

    y[4] = theta_1;

    y[5] = theta_N;

}

static void mdlUpdate(double *x, double *u, SimStruct *S, int tid)

{

    wr_k = u[0];

    theta_r = wr_k * Ts + theta_r_1;

    if (theta_r >= M_2PI)

        theta_r = theta_r – M_2PI;

    else if(theta_r < 0)

        theta_r = theta_r + M_2PI;

    theta_1 = wr_k * Ts + theta_1_1;

    if(theta_1 >= Resolution)

       theta_1 = theta_1 – Resolution;

    else if (theta_1 < 0)

       theta_1 = theta_1 + Resolution;

    theta_N = theta_1 * Resolution_Rev;

    if (theta_N > 0.25 && theta_N <= 0.75)

        A = 1;

    else

        A = 0;

    if (theta_N > 0.5)

        B = 1;

    else

        B = 0;

    if (theta_r < M_2PI && theta_r > (M_2PI – Resolution / 2))    //6.270913460876502=2*pi-encoder_resolution/2

        Z = 1;

    else

        Z = 0;

    theta_r_1 = theta_r;

    theta_1_1 = theta_1;

}

/*

 * mdlDerivatives – compute the derivatives

 *

 * In this function, you compute the S-function block’s derivatives.

 * The derivatives are placed in the dx variable.

 */

static void mdlDerivatives(double *dx, double *x, double *u, SimStruct *S, int tid)

{

}

/*

 * mdlTerminate – called when the simulation is terminated.

 *

 * In this function, you should perform any actions that are necessary

 * at the termination of a simulation.  For example, if memory was allocated

 * in mdlInitializeConditions, this is the place to free it.

 */

static void mdlTerminate(SimStruct *S)

{

}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */

#include “simulink.c”      /* MEX-file interface mechanism */

#else

#include “cg_sfun.h”       /* Code generation registration function */

#endif

وإذا اخترنا عرض الإشارات A, B, Z فنحصل على الأشكال التالية عند لحظة تغير جهة دوران المحرك، ونلاحظ كيف أن الفرق بين الإشارتين A و B تحول من تقدم الإشارة A بـ 90 درجة إلى تقدم الإشارة B بذلك المقدار وبذلك نعرف أن المحرك قد غير جهة دورانه فقط بالاعتماد على A و B، أما الإشارة Z فهي تتكرر عند بداية كل دورة، وفي الرسم تظهر بداية دورة واحدة فقط:

ومن أجل قراءة إشارة المشفر وبالتالي معرفة سرعة وموضع وجهة دوران المحرك، يجب أن نستخدم فاك شيفرة، وذلك عن طريق تنفيذ البرمجة التالية للصندوق IncEnc_Estimation:

/*

 * Copyright (c) 2006 by University of Aleppo

 *  All Rights Reserved

 */

#define S_FUNCTION_NAME IncEnc_Estimation

#include <stddef.h>

#include <stdlib.h>

#include <math.h>

#include “simstruc.h”

#ifdef MATLAB_MEX_FILE

#include “mex.h”

#endif

#define SAMPLE_TIME_ARG         ssGetArg(S,0)

#define PulsePerRotate_ARG      ssGetArg(S,1)

#define NUMBER_OF_ARGS          (2)

#define NSAMPLE_TIMES           (1)

#define NUMBER_OF_INPUTS        (3) // A,B,Z

#define NUMBER_OF_OUTPUTS       (2) //Theta_out, wr

float M_2PI = 6.283185307179586;

float Ts, PulsePerRotate, Resolution;

int A_k, B_k, Z_k, A_k_1, B_k_1, Z_k_1;

int Change_A, Change_B, Change_Z;

float Direction, theta_Out, theta_Out_1, wr, counter;

static void mdlInitializeSizes(SimStruct *S)

{

    if (ssGetNumArgs(S) != NUMBER_OF_ARGS) {

#ifdef MATLAB_MEX_FILE

    mexErrMsgTxt(“Wrong number of input arguments passed.\nThree arguments are expected\n”);

#endif

    }

    /* Set up size information */

    ssSetNumContStates(    S, 0);      /* number of continuous states */

    ssSetNumDiscStates(    S, 1);      /* number of discrete states */

    ssSetNumInputs(        S, NUMBER_OF_INPUTS);      /* number of inputs */

    ssSetNumOutputs(       S, NUMBER_OF_OUTPUTS);      /* number of outputs */

    ssSetDirectFeedThrough(S, 0);      /* direct feedthrough flag */

    ssSetNumSampleTimes(   S, NSAMPLE_TIMES);      /* number of sample times */

    ssSetNumInputArgs(     S, NUMBER_OF_ARGS);      /* number of input arguments */

    ssSetNumRWork(         S, 0);      /* number of real work vector elements */

    ssSetNumIWork(         S, 0);      /* NUMBER_OF_IWORKS);      /* number of integer work vector elements */

    ssSetNumPWork(         S, 0);      /* number of pointer work vector elements */

}

static void mdlInitializeSampleTimes(SimStruct *S)

{

    ssSetSampleTimeEvent(S, 0, mxGetPr(SAMPLE_TIME_ARG)[0]);

    ssSetOffsetTimeEvent(S, 0, 0.0);

}

static void mdlInitializeConditions(double *x0, SimStruct *S)

{

    Ts = mxGetPr(SAMPLE_TIME_ARG)[0];        /*Sampling Time*/

    PulsePerRotate = mxGetPr(PulsePerRotate_ARG)[0];

    /* States initialization*/

    A_k_1 = 0;

    B_k_1 = 0;

    Z_k_1 = 0;

    theta_Out = 0;

    theta_Out_1 = 0;

    wr = 0;

    Resolution = M_2PI / PulsePerRotate;    //(2*pi)/256

}

static void mdlOutputs(double *y, double *x, double *u, SimStruct *S, int tid)

{

    y[0] = theta_Out;

    y[1] = wr;

}

static void mdlUpdate(double *x, double *u, SimStruct *S, int tid)

{

    A_k = u[0];

    B_k = u[1];

    Z_k = u[2];

    counter++;

    Change_A = A_k – A_k_1;

    Change_B = B_k – B_k_1;

    Change_Z = Z_k – Z_k_1;

    if(Change_A < 0 && B_k == 1) // Direction is Forward

    {

        theta_Out += Resolution;

        Direction = 1;

        wr = (theta_Out – theta_Out_1) / (counter * Ts);

        counter = 0;

    }

    if(Change_A < 0 && B_k == 0) // Direction is Backward

    {

        theta_Out -= Resolution;

        Direction = -1;

        wr = (theta_Out – theta_Out_1) / (counter * Ts);

        counter = 0;

    }

    if(Change_Z < 0)

    {

        if(Direction == 1)

        {

            theta_Out -= M_2PI;

            theta_Out_1 -= M_2PI;

        }

        else

        {

            theta_Out += M_2PI;

            theta_Out_1 += M_2PI;

        }

    }

    A_k_1 = A_k;

    B_k_1 = B_k;

    Z_k_1 = Z_k;

    theta_Out_1 = theta_Out;

}

/*

 * mdlDerivatives – compute the derivatives

 *

 * In this function, you compute the S-function block’s derivatives.

 * The derivatives are placed in the dx variable.

 */

static void mdlDerivatives(double *dx, double *x, double *u, SimStruct *S, int tid)

{

}

/*

 * mdlTerminate – called when the simulation is terminated.

 *

 * In this function, you should perform any actions that are necessary

 * at the termination of a simulation.  For example, if memory was allocated

 * in mdlInitializeConditions, this is the place to free it.

 */

static void mdlTerminate(SimStruct *S)

{

}

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */

#include “simulink.c”      /* MEX-file interface mechanism */

#else

#include “cg_sfun.h”       /* Code generation registration function */

#endif

وبمقارنة الموضع الحقيقي مع الموضع المخمن نحصل على الشكل التالي:

أما بالنسبة للسرعة، فنحصل على إشارة مشوشة بعض الشيء وتحتاج إلى مرشح تمرير منخفض لتحسين شكلها، والمخطط التالي يظهر السرعة الحقيقية، والسرعة المخمنة مع ترشيح، والسرعة المخمنة دون ترشيح؛ باللون الأزرق والقرمزي والأزرق الفاتح على الترتيب:

وفي شكل أكثر وضوحا:

  • وعند هذه المرحلة نكون قد أنهينا دراسة نمذجة محرك التيار المستمر مع أبرز الحساسات المستخدمة معه.

أضف تعليق