dc_motor.c

Go to the documentation of this file.
00001 
00043 #include "dc_motor.h"
00044 #include "hw_dc_motor.h"
00045 
00046 #include <algo/pid_control.h>
00047 
00048 #include <drv/timer.h>
00049 #include <drv/adc.h>
00050 
00051 #include <cfg/debug.h>
00052 
00053 #include <kern/proc.h>
00054 
00055 #define DC_MOTOR_TARGET_TRIM 0
00056 
00057 #if DC_MOTOR_TARGET_TRIM
00058     #define DC_MOTOR_TARGET_TRIM_SAMPLE_PER 50
00059     static int tgt_sample_period = 0;
00060 #endif
00061 
00065 static DCMotor dcm_all[CONFIG_NUM_DC_MOTOR];
00066 
00068 static cpustack_t dc_motor_poll_stack[200];
00069 
00071 static mtime_t sample_period;
00072 
00073 // Only for Debug
00074 // static int debug_msg_delay = 0;
00075 
00076 //Forward declaration
00077 static void dc_motor_do(int index);
00078 
00093 static void NORETURN dc_motor_poll(void)
00094 {
00095     for (;;)
00096     {
00097         mtime_t max_sample_delay = 0;
00098         int i;
00099 
00100         /*
00101          * For all DC motor we read and process output singal,
00102          * and choose the max value to off time
00103          */
00104         for (i = 0; i < CONFIG_NUM_DC_MOTOR; i++)
00105         {
00106             dc_motor_do(i);
00107             max_sample_delay = MAX(max_sample_delay, dcm_all[i].cfg->sample_delay);
00108         }
00109 
00110         //Wait for next sampling
00111         timer_delay(sample_period - max_sample_delay);
00112 
00113         for (i = 0; i < CONFIG_NUM_DC_MOTOR; i++)
00114         {
00115             if (dcm_all[i].status & DC_MOTOR_ACTIVE)
00116             {
00117                 DC_MOTOR_DISABLE(dcm_all[i].index);
00118                 pwm_enable(dcm_all[i].cfg->pwm_dev, false);
00119             }
00120         }
00121 
00122         //Wait some time to allow signal to stabilize before sampling
00123         timer_delay(max_sample_delay);
00124 
00125 #if DC_MOTOR_TARGET_TRIM
00126         if (tgt_sample_period == DC_MOTOR_TARGET_TRIM_SAMPLE_PER)
00127         {
00128             dc_speed_t tgt_speed = ADC_RANGECONV(adc_read(6), 0, 65535);
00129 
00130             for (i = 0; i < CONFIG_NUM_DC_MOTOR; i++)
00131             {
00132                 if ((dcm_all[i].tgt_speed >= tgt_speed - 100) && (dcm_all[i].tgt_speed <= tgt_speed + 100))
00133                     TRACEMSG("DCmt[%d]> tgt[%d]", i, tgt_speed);
00134 
00135                 dc_motor_setSpeed(i, tgt_speed);
00136             }
00137             tgt_sample_period = 0;
00138         }
00139         tgt_sample_period++;
00140 #endif
00141     }
00142 }
00143 
00144 /*
00145  * Sampling a signal on DC motor and compute
00146  * a new value of speed according with PID control.
00147  */
00148 static void dc_motor_do(int index)
00149 {
00150     DCMotor *dcm = &dcm_all[index];
00151 
00152     dc_speed_t curr_pos;
00153     pwm_duty_t new_pid;
00154 
00155     //If select DC motor is not active we return
00156     if (!(dcm->status & DC_MOTOR_ACTIVE))
00157         return;
00158 
00159     //Acquire the output signal
00160     curr_pos = ADC_RANGECONV(adc_read(dcm->cfg->adc_ch), dcm->cfg->adc_min, dcm->cfg->adc_max);
00161 
00162     //Compute next value for reaching target speed from current position
00163     new_pid = pid_control_update(&dcm->pid_ctx, dcm->tgt_speed, curr_pos);
00164 
00165 //TODO: Add a multilevel debug..
00166 //  if (debug_msg_delay == 20)
00167 //  {
00168 //      TRACEMSG("DCmt[%d]>curr_speed[%d],tgt[%d],err[%f],P[%f],I[%f],D[%f]", dcm->index, curr_pos, dcm->tgt_speed);
00169 //      kprintf("%d,", curr_pos);
00170 //      debug_msg_delay = 0;
00171 //  }
00172 //  debug_msg_delay++;
00173 
00174 //  TRACEMSG("tg[%d], new_pid[%d], pos[%d]", dcm->tgt_speed, new_pid, curr_pos);
00175 
00176     //Apply the compute duty value
00177     pwm_setDuty(dcm->cfg->pwm_dev, new_pid);
00178 
00179     //Restart dc motor
00180     pwm_enable(dcm->cfg->pwm_dev, true);
00181 
00182     DC_MOTOR_ENABLE(dcm->index);
00183 }
00184 
00191 void dc_motor_setDir(int index, bool dir)
00192 {
00193     DCMotor *dcm = &dcm_all[index];
00194 
00195     if (dir != (dcm->status & DC_MOTOR_DIR))
00196     {
00197         //Reset previous direction flag, and set new
00198         dcm->status &= ~DC_MOTOR_DIR;
00199         dcm->status |= DC_MOTOR_DIR;
00200         DC_MOTOR_SET_DIR(index, dir);
00201     }
00202 
00203 }
00204 
00205 
00209 void dc_motor_setSpeed(int index, dc_speed_t speed)
00210 {
00211     dcm_all[index].tgt_speed = speed;
00212 }
00213 
00217 void dc_motor_enable(int index, bool state)
00218 {
00219     DCMotor *dcm = &dcm_all[index];
00220 
00221     /*
00222      * Clean all PID stutus variable, becouse 
00223      * we start with new one.
00224      */
00225     pid_control_reset(&dcm->pid_ctx);
00226 
00227     if (state)
00228     {
00229         dcm->status |= DC_MOTOR_ACTIVE;
00230     }
00231     else
00232     {
00233         pwm_enable(dcm->cfg->pwm_dev, false);
00234         DC_MOTOR_DISABLE(dcm->index);
00235 
00236         dcm->status &= ~DC_MOTOR_ACTIVE;
00237     }
00238 }
00239 
00243 void dc_motor_setup(int index, DCMotorConfig *dcm_conf)
00244 {
00245     DCMotor *dcm = &dcm_all[index];
00246 
00247     dcm->cfg = dcm_conf;
00248 
00249     /*
00250      * Apply config value.
00251      */
00252     dcm->index = index;
00253 
00254     DC_MOTOR_INIT(dcm->index);
00255 
00256     pwm_setFrequency(dcm->cfg->pwm_dev, dcm->cfg->freq);
00257     pwm_enable(dcm->cfg->pwm_dev, false);
00258 
00259     //Init pid control
00260     pid_control_init(&dcm->pid_ctx, &dcm->cfg->pid_cfg);
00261 
00262     /*
00263      * We are using the same sample period for each
00264      * motor, and so we check if this value is the same
00265      * for all. The sample period time is defined in pid
00266      * configuration.
00267      *
00268      * TODO: Use a different sample period for each motor
00269      * and refactor a module to allow to use a timer interrupt,
00270      * in this way we can controll a DC motor also without a
00271      * kernel, increasing a portability on other target.
00272      */
00273     if (!sample_period)
00274         sample_period = dcm->cfg->pid_cfg.sample_period;
00275 
00276     ASSERT(sample_period == dcm->cfg->pid_cfg.sample_period);
00277 
00278     //Set default direction for DC motor
00279     DC_MOTOR_SET_DIR(dcm->index, dcm->cfg->dir);
00280 
00281     TRACEMSG("DC motort[%d]> kp[%f],ki[%f],kd[%f]", dcm->index, dcm_conf->pid_cfg.kp, dcm_conf->pid_cfg.ki, dcm_conf->pid_cfg.kd);
00282     TRACEMSG("               > pwm_dev[%d], freq[%ld], sample[%ld]", dcm_conf->pwm_dev, dcm_conf->freq, dcm_conf->sample_delay);
00283     TRACEMSG("               > adc_ch[%d], adc_max[%d], adc_min[%d]", dcm_conf->adc_ch, dcm_conf->adc_max, dcm_conf->adc_min);
00284     TRACEMSG("               > dir[%d]", dcm->cfg->dir);
00285 
00286 }
00287 
00288 
00292 void dc_motor_init(void)
00293 {
00294     for (int i = 0; i < CONFIG_NUM_DC_MOTOR; i++)
00295         dcm_all[i].status &= ~DC_MOTOR_ACTIVE;
00296 
00297     //Init a sample period
00298     sample_period = 0;
00299 
00300     //Create a dc motor poll process
00301     proc_new(dc_motor_poll, NULL, sizeof(dc_motor_poll_stack), dc_motor_poll_stack);
00302 
00303 }
00304