dc_motor.c

Go to the documentation of this file.
00001 
00043 #include "dc_motor.h"
00044 #include "hw/hw_dc_motor.h"
00045 
00046 // Define logging setting (for cfg/log.h module).
00047 #define LOG_LEVEL         DC_MOTOR_LOG_LEVEL
00048 #define LOG_VERBOSITY     DC_MOTOR_LOG_FORMAT
00049 
00050 #include <cfg/log.h>
00051 #include <cfg/debug.h>
00052 
00053 #include <algo/pid_control.h>
00054 
00055 #include <drv/timer.h>
00056 #include <drv/adc.h>
00057 
00058 #include <kern/proc.h>
00059 
00060 #include <string.h>
00061 
00065 static DCMotor dcm_all[CONFIG_NUM_DC_MOTOR];
00066 
00068 static cpu_stack_t dc_motor_poll_stack[1024];
00069 
00071 static mtime_t sample_period;
00072 
00073 // Only for Debug
00074 LOG_INFOB(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 }
00126 
00127 /*
00128  * Sampling a signal on DC motor and compute
00129  * a new value of speed according with PID control.
00130  */
00131 static void dc_motor_do(int index)
00132 {
00133     DCMotor *dcm = &dcm_all[index];
00134 
00135     dc_speed_t curr_pos;
00136     pwm_duty_t new_pid;
00137 
00138     //If select DC motor is not active we return
00139     if (!(dcm->status & DC_MOTOR_ACTIVE))
00140         return;
00141 
00142     //Acquire the output signal
00143     curr_pos = ADC_RANGECONV(adc_read(dcm->cfg->adc_ch), dcm->cfg->adc_min, dcm->cfg->adc_max);
00144 
00145     //Compute next value for reaching target speed from current position
00146     new_pid = pid_control_update(&dcm->pid_ctx, dcm->tgt_speed, curr_pos);
00147 
00148 
00149     LOG_INFOB(if (debug_msg_delay == 20)
00150     {
00151         LOG_INFO("DCmt[%d]>curr_speed[%d],tgt[%d]\n", dcm->index, curr_pos, dcm->tgt_speed);
00152         LOG_INFO("%d,", curr_pos);
00153         debug_msg_delay = 0;
00154     }
00155     debug_msg_delay++;
00156     kputs("\n"););
00157 
00158     LOG_WARN("tg[%d], new_pid[%d], pos[%d]\n", dcm->tgt_speed, new_pid, curr_pos);
00159 
00160     //Apply the compute duty value
00161     pwm_setDuty(dcm->cfg->pwm_dev, new_pid);
00162 
00163     //Restart dc motor
00164     pwm_enable(dcm->cfg->pwm_dev, true);
00165 
00166     DC_MOTOR_ENABLE(dcm->index);
00167 }
00168 
00175 void dc_motor_setDir(int index, bool dir)
00176 {
00177     DCMotor *dcm = &dcm_all[index];
00178 
00179     if (dir != (dcm->status & DC_MOTOR_DIR))
00180     {
00181         //Reset previous direction flag, and set new
00182         dcm->status &= ~DC_MOTOR_DIR;
00183         dcm->status |= DC_MOTOR_DIR;
00184 
00185         /*
00186          * To set dc motor direction we must also set the
00187          * PWM polarity according with dc motor driver chip
00188          */
00189         pwm_setPolarity(dcm->cfg->pwm_dev, dir);
00190         DC_MOTOR_SET_DIR(index, dir);
00191     }
00192 }
00193 
00194 
00198 void dc_motor_setSpeed(int index, dc_speed_t speed)
00199 {
00200     dcm_all[index].tgt_speed = speed;
00201 }
00202 
00206 void dc_motor_enable(int index, bool state)
00207 {
00208     DCMotor *dcm = &dcm_all[index];
00209 
00210     /*
00211      * Clean all PID stutus variable, becouse
00212      * we start with new one.
00213      */
00214     pid_control_reset(&dcm->pid_ctx);
00215 
00216     if (state)
00217     {
00218         dcm->status |= DC_MOTOR_ACTIVE;
00219     }
00220     else
00221     {
00222         pwm_enable(dcm->cfg->pwm_dev, false);
00223         DC_MOTOR_DISABLE(dcm->index);
00224 
00225         dcm->status &= ~DC_MOTOR_ACTIVE;
00226     }
00227 }
00228 
00232 void dc_motor_setup(int index, DCMotorConfig *dcm_conf)
00233 {
00234     DCMotor *dcm = &dcm_all[index];
00235 
00236     dcm->cfg = dcm_conf;
00237 
00238     /*
00239      * Apply config value.
00240      */
00241     dcm->index = index;
00242 
00243     pwm_setFrequency(dcm->cfg->pwm_dev, dcm->cfg->freq);
00244     pwm_setPolarity(dcm->cfg->pwm_dev, dcm->cfg->pol);
00245     pwm_enable(dcm->cfg->pwm_dev, false);
00246 
00247     //Init pid control
00248     pid_control_init(&dcm->pid_ctx, &dcm->cfg->pid_cfg);
00249 
00250     /*
00251      * We are using the same sample period for each
00252      * motor, and so we check if this value is the same
00253      * for all. The sample period time is defined in pid
00254      * configuration.
00255      *
00256      * TODO: Use a different sample period for each motor
00257      * and refactor a module to allow to use a timer interrupt,
00258      * in this way we can controll a DC motor also without a
00259      * kernel, increasing a portability on other target.
00260      */
00261     if (!sample_period)
00262         sample_period = dcm->cfg->pid_cfg.sample_period;
00263 
00264     ASSERT(sample_period == dcm->cfg->pid_cfg.sample_period);
00265 
00266     //Set default direction for DC motor
00267     DC_MOTOR_SET_DIR(dcm->index, dcm->cfg->dir);
00268 
00269     LOG_INFO("DC motort[%d]:\n", dcm->index);
00270     LOG_INFO("> PID: kp[%lf],ki[%lf],kd[%lf]\n", dcm->cfg->pid_cfg.kd, dcm->cfg->pid_cfg.ki, dcm->cfg->pid_cfg.kd);
00271     LOG_INFO("> PWM: pwm_dev[%d], freq[%ld], sample[%ld]\n", dcm->cfg->pwm_dev, dcm->cfg->freq, dcm->cfg->sample_delay);
00272     LOG_INFO("> ADC: adc_ch[%d], adc_max[%d], adc_min[%d]\n", dcm->cfg->adc_ch, dcm->cfg->adc_max, dcm->cfg->adc_min);
00273     LOG_INFO("> DC: dir[%d], speed[%d]\n", dcm->cfg->dir, dcm->cfg->speed);
00274 
00275 }
00276 
00277 
00281 void dc_motor_init(void)
00282 {
00283     memset(dcm_all, 0, sizeof(dcm_all));
00284 
00285     //Init a sample period
00286     sample_period = 0;
00287 
00288     MOTOR_DC_INIT();
00289 
00290     //Create a dc motor poll process
00291     proc_new(dc_motor_poll, NULL, sizeof(dc_motor_poll_stack), dc_motor_poll_stack);
00292 
00293 }
00294