mbed controller for openroach

Dependencies:   MPU6050IMU QEI RPCInterface TSL1401CL mbed

Fork of controller_with_imu by Yuxiang Yang

main.cpp

Committer:
yxyang
Date:
2017-05-30
Revision:
0:4856445a8db9
Child:
1:150bafe1bd61

File content as of revision 0:4856445a8db9:

/*
 * A sample path following program for the Zumy board.
 * Author: Galen Savidge
 *
 * Behavior:
 * Zumy follows the edge of the line until no line is found for LINE_END_TIME
 * cycles. Line position is recorded every frame as an 8 bit unsigned int. The
 * general area of the line is shown on the 4 LEDs on the mbed board. If a line
 * is not found all 4 LEDs are turned on. The Zumy stops and ine position data
 * is output to serial once the end of the track is reached.
 */

#include "MPU6050.h"
#include "TSL1401CL.h"
#include "mbed.h"

/***** Constants ******/

MPU6050 mpu6050;

#define CAM_INTEGRATION_TIME 80

// Higher line threshold -> the sensor will only recognize larger changes in
// brightness as a line edge
#define LINE_THRESHOLD 3000
#define LINE_PRECISION 2
#define LINE_CROP_AMOUNT 4

// These constants define the base pwm across the motors and how much the
// controller
// adjusts based on position of the line relative to the sensor
#define SPEED_PWM 0.23
#define TURN_SENS_INNER 1.5F
#define TURN_SENS_OUTER 0.5F

// Defines data
#define LINE_HIST_SIZE 1000
#define LINE_END_TIME 2500

// Sensor pins
#define clk p16
#define si p17
#define adc p18

// Motors -- As labelled on the Zumy mbed board
PwmOut m1_fwd (p21);
PwmOut m1_back (p22);

PwmOut m2_fwd (p23);
PwmOut m2_back (p24);

// LEDs
DigitalOut led1 (LED1);
DigitalOut led2 (LED2);
DigitalOut led3 (LED3);
DigitalOut led4 (LED4);

// USB serial
Serial pc (USBTX, USBRX);

// Data storage
uint8_t line_hist[LINE_HIST_SIZE];
int16_t accel_x[LINE_HIST_SIZE];
int16_t accel_y[LINE_HIST_SIZE];
int16_t accel_z[LINE_HIST_SIZE];
int16_t gyro_x[LINE_HIST_SIZE];
int16_t gyro_y[LINE_HIST_SIZE];
int16_t gyro_z[LINE_HIST_SIZE];

uint16_t hist_index;

/***** Helper functions *****/
float max (float a, float b);

// Sets the 4 LEDS on the mbed board to the four given binary values
void setLEDs (uint8_t a, uint8_t b, uint8_t c, uint8_t d);

// Steers by linearly decreasing the inner wheel speed as the line moves from
// the center (unused in this program)
void steerStupid (int8_t line_pos);

// Based on steerStupid; adds the ability for the inner wheel to rotate in
// reverse (unused in this program)
void steerPointTurns (int8_t line_pos);

// Based on steerPointTurns; the outer wheel moves faster the farther the line
// is from center
void steerImprovedPointTurns (int8_t line_pos);

int
main ()
{
  /********** SENSOR SETUP **********/
  TSL1401CL cam (clk, si, adc);
  cam.setIntegrationTime (CAM_INTEGRATION_TIME);

  int8_t line_pos = -1;
  int8_t line_pos_previous = -1;
  uint8_t line_lost_time = 0;

  hist_index = 0;

  i2c.frequency (400000);

  volatile bool imu_ready = false;

  wait_ms (100);
  uint8_t whoami = mpu6050.readByte (MPU6050_ADDRESS, WHO_AM_I_MPU6050);

  if (whoami == 0x68) // WHO_AM_I should always be 0x68
    {
      mpu6050.MPU6050SelfTest (SelfTest);
      if (SelfTest[0] < 1.0f && SelfTest[1] < 1.0f && SelfTest[2] < 1.0f
          && SelfTest[3] < 1.0f && SelfTest[4] < 1.0f && SelfTest[5] < 1.0f)
        {
          mpu6050.resetMPU6050 ();
          mpu6050.calibrateMPU6050 (gyroBias, accelBias);
          mpu6050.initMPU6050 ();
          mpu6050.getAres ();
          mpu6050.getGres ();
          imu_ready = true;
        }
    }
  else
    {
      setLEDs (1, 0, 1, 0);
      wait_ms (1000);
    }
  // Read garbage data
  while (!cam.integrationReady ())
    ;
  cam.read ();

  while (1)
    {
      /***** Read line sensor *****/
      while (!cam.integrationReady ())
        ; // Wait for integration
      cam.read ();
      /***** Line following loop *****/

      line_pos = cam.findLineEdge (LINE_THRESHOLD, LINE_PRECISION,
                                   LINE_CROP_AMOUNT);

      if (line_pos != -1)
        { // On the line
          // Set LEDs based on the position of the line
          if (line_pos < (TSL1401CL_PIXEL_COUNT - 2 * LINE_CROP_AMOUNT) / 4)
            {
              setLEDs (1, 0, 0, 0);
            }
          else if (line_pos
                   < (TSL1401CL_PIXEL_COUNT - 2 * LINE_CROP_AMOUNT) / 2)
            {
              setLEDs (0, 1, 0, 0);
            }
          else if (line_pos
                   < (TSL1401CL_PIXEL_COUNT - 2 * LINE_CROP_AMOUNT) * 3 / 4)
            {
              setLEDs (0, 0, 1, 0);
            }
          else
            {
              setLEDs (0, 0, 0, 1);
            }

          // Record the line position
          line_hist[hist_index] = line_pos;
          line_lost_time = 0;
          if (imu_ready)
            {

              if (mpu6050.readByte (MPU6050_ADDRESS, INT_STATUS) & 0x01)
                { // check if data ready interrupt
                  mpu6050.readAccelData (accelCount);
                  // Read the x/y/z adc values

                  accel_x[hist_index] = accelCount[0];
                  accel_y[hist_index] = accelCount[1];
                  accel_z[hist_index] = accelCount[2];

                  // Calculate the gyro value into actual degrees per
                  // second

                  mpu6050.readGyroData (gyroCount);

                  gyro_x[hist_index] = gyroCount[0];
                  gyro_y[hist_index] = gyroCount[1];
                  gyro_z[hist_index] = gyroCount[2];
                  // Read the x/y/z ad values
                  // gyro_x = (float)gyroCount[0] * gRes
                  //          - gyroBias[0]; // get actual gyro value, this
                  //                         // depends on scale being set
                  // gyro_y = (float)gyroCount[1] * gRes - gyroBias[1];
                  // gyro_z = (float)gyroCount[2] * gRes - gyroBias[2];
                  //   pc.printf ("Gyro,%d,%d,%d\n", gyroCount[0],
                  //   gyroCount[1],
                  //              gyroCount[2]);
                  //
                }
            }
          hist_index++;

          // Steer the vehicle
          steerImprovedPointTurns (line_pos);

          line_pos_previous = line_pos;
        }
      else
        { // Lost the line
          // setLEDs (1, 1, 1, 1);
          if (abs (line_pos_previous - TSL1401CL_PIXEL_COUNT / 2)
              > TSL1401CL_PIXEL_COUNT / 4)
            {
              // Steer at maximum turn angle towards the last known line
              // direction
              if (line_pos_previous >= TSL1401CL_PIXEL_COUNT / 2)
                {
                  steerImprovedPointTurns (TSL1401CL_PIXEL_COUNT - 1
                                           - LINE_CROP_AMOUNT);
                  // line_hist[hist_index] = TSL1401CL_PIXEL_COUNT - 1 -
                  // LINE_CROP_AMOUNT;
                }
              else
                {
                  steerImprovedPointTurns (LINE_CROP_AMOUNT);
                  // line_hist[hist_index] = LINE_CROP_AMOUNT;
                }
            }
          else
            {
              line_lost_time++;
              if (line_lost_time >= LINE_END_TIME)
                {
                  setLEDs (1, 0, 1, 0);
                  // Line end; transmit data to PC
                  m1_fwd.write (0);
                  m2_fwd.write (0);
                  // while (!pc.readable ())
                  //   ;
                  pc.printf ("----- Start line data -----\n");
                  for (int i = 0; i <= hist_index; i++)
                    {
                      pc.printf ("Pos: %d\n", line_hist[i]);
                      float x, y, z;
                      x = (float)accel_x[i] * aRes - accelBias[0];
                      y = (float)accel_y[i] * aRes - accelBias[1];
                      z = (float)accel_z[i] * aRes - accelBias[2];
                      pc.printf ("Acceleration,%f,%f,%f\n", x, y, z);
                      x = (float)gyro_x[i] * gRes - gyroBias[0];
                      y = (float)gyro_y[i] * gRes - gyroBias[1];
                      z = (float)gyro_z[i] * gRes - gyroBias[2];
                      pc.printf ("Gyroscope,%f,%f,%f\n", x, y, z);
                    }
                  while (1)
                    ;
                }
            }
        }
      if (hist_index > LINE_HIST_SIZE)
        {
          setLEDs (1, 0, 0, 1);

          // Line end; transmit data to PC
          m1_fwd.write (0);
          m2_fwd.write (0);
          // while (!pc.readable ())
          //   ;
          pc.printf ("----- Start line data -----\n");
          for (int i = 0; i <= hist_index; i++)
            {
              pc.printf ("Pos: %d\n", line_hist[i]);
              float x, y, z;
              x = (float)accel_x[i] * aRes - accelBias[0];
              y = (float)accel_y[i] * aRes - accelBias[1];
              z = (float)accel_z[i] * aRes - accelBias[2];
              pc.printf ("Acceleration,%f,%f,%f\n", x, y, z);
              x = (float)gyro_x[i] * gRes - gyroBias[0];
              y = (float)gyro_y[i] * gRes - gyroBias[1];
              z = (float)gyro_z[i] * gRes - gyroBias[2];
              pc.printf ("Gyroscope,%f,%f,%f\n", x, y, z);
            }
          while (1)
            ;
        }
    }
}

float
max (float a, float b)
{
  if (a >= b)
    return a;
  return b;
}

void
setLEDs (uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
  led1 = a;
  led2 = b;
  led3 = c;
  led4 = d;
}

void
steerStupid (int8_t line_pos)
{
  line_pos -= TSL1401CL_PIXEL_COUNT / 2; // Find offset from center

  if (line_pos < 0)
    {
      m1_fwd.write (SPEED_PWM);
      m1_back.write (0);
      m2_fwd.write (max (SPEED_PWM * (1.0F
                                      + TURN_SENS_INNER * line_pos * 2.0F
                                            / (float)TSL1401CL_PIXEL_COUNT),
                         0));
      m2_back.write (0);
    }

  if (line_pos >= 0)
    {
      m2_fwd.write (SPEED_PWM);
      m2_back.write (0);
      m1_fwd.write (max (SPEED_PWM * (1.0F
                                      - TURN_SENS_INNER * line_pos * 2.0F
                                            / (float)TSL1401CL_PIXEL_COUNT),
                         0));
      m1_back.write (0);
    }
}

void
steerPointTurns (int8_t line_pos)
{
  line_pos -= TSL1401CL_PIXEL_COUNT / 2; // Find offset from center

  float pwm_outer = SPEED_PWM;
  float pwm_inner = SPEED_PWM * (1.0F
                                 - TURN_SENS_INNER * abs (line_pos) * 2.0F
                                       / (float)TSL1401CL_PIXEL_COUNT);

  if (line_pos < 0)
    {
      m1_fwd.write (pwm_outer);
      m1_back.write (0);
      if (pwm_inner >= 0)
        {
          m2_fwd.write (pwm_inner);
          m2_back.write (0);
        }
      else
        {
          m2_fwd.write (0);
          m2_back.write (pwm_inner * -1.0F);
        }
    }

  if (line_pos >= 0)
    {
      m2_fwd.write (pwm_outer);
      m2_back.write (0);
      if (pwm_inner >= 0)
        {
          m1_fwd.write (pwm_inner);
          m1_back.write (0);
        }
      else
        {
          m1_fwd.write (0);
          m1_back.write (pwm_inner * -1.0F);
        }
    }
}

void
steerImprovedPointTurns (int8_t line_pos)
{
  line_pos -= TSL1401CL_PIXEL_COUNT / 2; // Find offset from center

  // Find desired motor voltages based on the controller
  float pwm_outer = SPEED_PWM * (1.0F
                                 + TURN_SENS_OUTER * abs (line_pos) * 2.0F
                                       / (float)TSL1401CL_PIXEL_COUNT);
  float pwm_inner = SPEED_PWM * (1.0F
                                 - TURN_SENS_INNER * abs (line_pos) * 2.0F
                                       / (float)TSL1401CL_PIXEL_COUNT);

  // Write to the appropriate PWM pins
  if (line_pos < 0)
    {
      m1_fwd.write (pwm_outer);
      m1_back.write (0);
      if (pwm_inner >= 0)
        {
          m2_fwd.write (pwm_inner);
          m2_back.write (0);
        }
      else
        {
          m2_fwd.write (0);
          m2_back.write (pwm_inner * -1.0F);
        }
    }

  if (line_pos >= 0)
    {
      m2_fwd.write (pwm_outer);
      m2_back.write (0);
      if (pwm_inner >= 0)
        {
          m1_fwd.write (pwm_inner);
          m1_back.write (0);
        }
      else
        {
          m1_fwd.write (0);
          m1_back.write (pwm_inner * -1.0F);
        }
    }
}