Publishing for Biomimetics.

Dependencies:   CRC MODDMA MODSERIAL MPU6050IMU PID QEI mbed-rtos mbed-src

control.cpp

Committer:
abuchan
Date:
2016-05-31
Revision:
0:8cfa73bb68e4

File content as of revision 0:8cfa73bb68e4:

#include "control.h"

Control::Control(
    PinName left_mot_0_pin, PinName left_mot_1_pin, 
    PinName right_mot_0_pin, PinName right_mot_1_pin, 
    Sensors *sensors, uint32_t tick_per_rev,
    float kP, float kI, float kD, float period, float velocity_max,
    float pid_dead_band
  ) :
    sensors_(sensors),
    control_timer_(&Control::control_helper,osTimerPeriodic,this),
    pid_dead_band_(pid_dead_band)
  {

  motors_[MOTOR_LEFT][0] = new PwmOut(left_mot_0_pin);
  motors_[MOTOR_LEFT][1] = new PwmOut(left_mot_1_pin);
  motors_[MOTOR_RIGHT][0] = new PwmOut(right_mot_0_pin);
  motors_[MOTOR_RIGHT][1] = new PwmOut(right_mot_1_pin);
  
  // For the LPC1768, all PWM channels are on the same timer, so setting one
  // period sets them all
  motors_[MOTOR_LEFT][0]->period_us(50);

  tick_to_angular_velocity_ = 2.0 * 3.14159265358979323846 / (float)(tick_per_rev * period);
  
  pid_init(MOTOR_LEFT,kP,kI,kD,period,velocity_max);
  pid_init(MOTOR_RIGHT,kP,kI,kD,period,velocity_max);

  control_timer_.start(period*1000);

  last_positions_[MOTOR_LEFT] = 0;
  last_positions_[MOTOR_RIGHT] = 0;
}

void Control::set_setpoints(float left, float right) {
  pids_[MOTOR_LEFT]->setSetPoint(left);
  pids_[MOTOR_RIGHT]->setSetPoint(right);
}

void Control::fill_pid_packet(packet_t* pkt) {
  pkt->header.type = PKT_TYPE_PID;
  pkt->header.length = sizeof(header_t) + sizeof(pid_data_t) + 1;
  pid_data_t* pid_data = (pid_data_t*)pkt->data_crc;
  pid_data->vel[MOTOR_LEFT] = velocities_[MOTOR_LEFT];
  pid_data->vel[MOTOR_RIGHT] = velocities_[MOTOR_RIGHT];
  pid_data->pwm[MOTOR_LEFT] = pwms_[MOTOR_LEFT];
  pid_data->pwm[MOTOR_RIGHT] = pwms_[MOTOR_RIGHT];
}

void Control::fill_sensor_packet(packet_t* pkt) {
  pkt->header.type = PKT_TYPE_SENSOR;
  pkt->header.length = sizeof(header_t) + sizeof(sensor_data_t) + 1;
  sensor_data_t* sensor_data = (sensor_data_t*)pkt->data_crc;
  sensor_data->velocity[MOTOR_LEFT] = velocities_[MOTOR_LEFT];
  sensor_data->velocity[MOTOR_RIGHT] = velocities_[MOTOR_RIGHT];
}

void Control::set_motor_pwm(int motor, float value) {
  if (value >= 0.0) {
    motors_[motor][0]->write(value);
    motors_[motor][1]->write(0.0);
  } else {
    motors_[motor][0]->write(0.0);
    motors_[motor][1]->write(-value);
  }
}

void Control::pid_init(int motor, float kP, float kI, float kD, float period, float velocity_max) {
  pids_[motor] = new PID(kP,kI,kD,period);
  pids_[motor]->setInputLimits(-velocity_max, velocity_max);
  pids_[motor]->setOutputLimits(-1.0,1.0);
  pids_[motor]->setBias(0.0);
  pids_[motor]->setSetPoint(0.0);
}

void Control::control_helper(const void* p) {
  Control* instance = (Control*)p;
  instance->control_update();
}

void Control::control_update(void) {
  float positions[2];
  
  sensors_->get_angles(positions);

  for (uint32_t i=0; i<2; i++) {
    velocities_[i] = tick_to_angular_velocity_ * (positions[i] - last_positions_[i]);
    last_positions_[i] = positions[i];
    pids_[i]->setProcessValue(velocities_[i]);
    pwms_[i] = pids_[i]->compute();
    if (fabs(pwms_[i]) < pid_dead_band_)
      pwms_[i] = 0.0;
  }

  set_motor_pwm(MOTOR_LEFT, pwms_[MOTOR_LEFT]);
  set_motor_pwm(MOTOR_RIGHT, pwms_[MOTOR_RIGHT]);
}