/***************************************************************************/
/* balanceREAD.c                                                           */
/* Balancing robot algorithm with PID control for driving straight         */
/* Collectind Data for analysis                                            */
/* Author: Rich Chi Ooi                                                    */
/* Version: 1.0                                                            */
/* Date:14.08.2003                                                         */ 
/* -------------------------------                                         */
/* Compilation  procedure:                                                 */
/*       Linux                                                             */
/*      gcc68 -c  XXXXXX.c (to create object file)                         */
/*      gcc68 -o  XXXXXX.hex XXXXXX.o ppwa.o                               */
/***************************************************************************/
/* In this version:                                                        */
/***************************************************************************/

#include <math.h>
#include <stdlib.h>
#include "stdio.h"
#include "eyebot.h"
#include "ppwa.h"
#include "sensors.h"
#include "kalman.h"

#define MAX 5000

int counter = 0;
float XDIST[MAX];
float XRATE[MAX];
float PHIANGLE[MAX];
float PHIRATE[MAX];
float ANGLE[MAX];
int MOTORCOMMAND[MAX];

/*metre per tick*/
static const float MPT = (M_PI*0.051)/3495;

/*Gyro Scaling to rad/s */
static const float  GY_SCALE = 0.002798;

/*Time step for encoder reading*/
static const float DT = 0.02;

MotorHandle motorLeft;
MotorHandle motorRight;
QuadHandle quadLeft;
QuadHandle quadRight;

/*Gain values for state control*/
static const float X_K = -31.6;
static const float Xdot_K = -34.3;
static const float PHI_K = 1467.6;
static const float PHIdot_K = 113.8; 

/*PID Gains*/

static const float KP = 0.35;
static const float KI = 0.025;
static const float KD = 0.75;

static float distance_old = 0;
static int r_old = 0;
static int e_old = 0;
static int e_old2 = 0;
static int enc_left_new = 0;
static int enc_right_new = 0;
static int e_func = 0;
static int r_motor = 0;

static float X = 0;
static float Xdot = 0;
static float PHI = 0;
static float PHIdot = 0;
static float command = 0;

static float gy_angle = 0;
static float in_angle = 0;
static  int motor_command = 0;

/*
 *Initialize the filter
 */
void stateInit(){

  int gyRaw = 0;
  
  gyRaw = gyroRaw();
  q_bias =gyRaw*GY_SCALE;
  angle = incAngle(); 
}

void balance(){
  
  gy_angle = gyroRaw()*GY_SCALE;
  in_angle = incAngle();
  
  stateUpdate(gy_angle);
  kalmanUpdate(in_angle);

  enc_left_new = QUADRead(quadLeft);
  enc_right_new = QUADRead(quadRight);
  
  PHI = in_angle;
  PHIdot = rate;

  X = ((enc_left_new+enc_right_new)/2)*MPT;
  Xdot = (X - distance_old)/DT;

  e_func = enc_left_new-enc_right_new;
  r_motor =(int)( r_old+KP*(e_func-e_old)+KI*(e_func+e_old)/2
                 +KD*(e_func-2*e_old+e_old2));
  e_old2 = e_old;
  e_old = e_func;
  r_old = r_motor;
  distance_old = X;

  motor_command =(int) (-1*((X*X_K)+(Xdot*Xdot_K)+(PHI*PHI_K)+(PHIdot*PHIdot_K)));

  if(motor_command>95){
    motor_command = 95;
  }
  if(motor_command<-95){
    motor_command = -95;
  }
 
  MOTORDrive(motorLeft,motor_command-r_motor);
  MOTORDrive(motorRight,motor_command+r_motor);
 
  XDIST[counter]= X;
  XRATE[counter] = Xdot;
  PHIANGLE[counter] = PHI;
  PHIRATE[counter] = PHIdot;
  ANGLE[counter] = angle;
  MOTORCOMMAND[counter] = motor_command;
  counter++;

 /*  LCDSetPos(1,0); */
/*   LCDPrintf(" X:%.4f\n XD:%.4f\n",X,Xdot); */
/*   LCDSetPos(3,0); */
/*   LCDPrintf(" P:%.4f\n PD:%.4f\n",PHI,PHIdot); */
/*   LCDSetPos(5,0); */
/*   LCDPrintf("CMD:%d\n",motor_command); */
}

/*
 *Uploading data to PC
 */
static void uploadData(){
  FILE *ser;
  int iKey;
  int i;

  LCDPrintf("Upload Data?\n");
  OSWait(50);
  LCDMenu(" "," ","YES","END");
  iKey=KEYGet();

  if(iKey==KEY3){
    OSInitRS232(SER115200,NONE,SERIAL1);
    ser = fdopen(SERIAL1, "w");
    if (ser==NULL){
      LCDPrintf("serial init error\n"); 
    }else{
      LCDPrintf("init OK >%d<\n", (int) ser);
    }
    fprintf(ser,"X,Xdot,PHI,PHIdot,ANGLE,motor_command\n");
    for(i=0;i<MAX;i++){
      fprintf(ser,"%.4f,",XDIST[i]);
      fprintf(ser,"%.4f,",XRATE[i]);
      fprintf(ser,"%.4f,",PHIANGLE[i]);
      fprintf(ser,"%.4f,",PHIRATE[i]);
      fprintf(ser,"%.4f,",ANGLE[i]);
      fprintf(ser,"%d",MOTORCOMMAND[i]);
      fprintf(ser,"\n");
    }
    fclose(ser);
    LCDPrintf("data sent");
    AUBeep();
  }
}
int main(void)
{
  int i;
  ServoHandle gyro;
  TimerHandle balanceTimer;

  /*initialize ports and sensors*/
  tpuInit();
  gyroInit(gyro);
  inclinoInit();
  motorLeft = MOTORInit(MOTOR_LEFT);
  motorRight = MOTORInit(MOTOR_RIGHT);
  quadLeft = QUADInit(QUAD_LEFT);
  quadRight = QUADInit(QUAD_RIGHT);
 
  QUADReset(quadRight);
  QUADReset(quadLeft);

  stateInit();
  OSWait(200);
  LCDPrintf("ROBOT INITIALIZED \n");
  LCDClear();

  balanceTimer = OSAttachTimer(2,(TimerFnc)balance);
   while(KEYRead()!=KEY4){
   }

  /*release all handles*/
  OSDetachTimer(balanceTimer);
  SERVORelease(gyro);
  MOTORRelease(motorLeft);
  MOTORRelease(motorRight);
  QUADRelease(quadLeft);
  QUADRelease(quadRight);

  LCDPrintf("reading ends !\n");
  OSWait(100);

  /*upload data*/
  uploadData();
  
}
