Madison YangMatthew LimWeihao ChengAlex Stevens
Published

ME 461 UIUC Drawing Robot

Sending a 2D line drawing to a robot to draw the line

IntermediateShowcase (no instructions)78
ME 461 UIUC Drawing Robot

Things used in this project

Hardware components

LAUNCHXL-F28379D C2000 Delfino LaunchPad
Texas Instruments LAUNCHXL-F28379D C2000 Delfino LaunchPad
This was the Component that controlled the robots movement. Super Useful Device that was really easy to program.
×1
Raspberry Pi 4 Model B
Raspberry Pi 4 Model B
×1
Camera (generic)
×1
Hitec RC Servo
×1

Software apps and online services

LabVIEW Community Edition
LabVIEW Community Edition
Code Composer Studio
Texas Instruments Code Composer Studio

Story

Read more

Custom parts and enclosures

mount for robot to hold servo motor and camera

Schematics

LabVIEW program

Code

Control.C

C/C++
This is the file that has all of the code needed to control the robots position
// hi this is to reduce the problems with version control with several people 
// I am going to put my files in this so that it will reduce the chances of git conflicts - Alex

//------------------------alex functions--------------------
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include "F28x_Project.h"
#include "driverlib.h"
#include "device.h"
#include "F28379dSerial.h"
#include "LEDPatterns.h"
//#include "song.h"
#include "dsp.h"
#include "fpu32/fpu_rfft.h"
#include <control.h>
/*

// here are the variables
extern float cur_x_e;
extern float cur_y_e;
extern float cur_bearing_e;
extern float cur_vel_x_e;
extern float cur_vel_y_e;
extern float cur_omega_in_e;
extern float xarray[];
extern float yarray[];

float eturn;
float turn;
float eturn_I;
float vel_right;
float vel_left;
float eturn_I_1;
float zero_x;
float zero_y;
float shift_pos_x;
float shift_pos_y;
float shift_line_x2;
float shift_line_y2;
float ux;
float uy;
float top;
float bottom;
float proj_x;
float proj_y;
float comp_x;
float comp_y;
float slope_line;
float slope;
float slope_robot_line;
float eturn_d;
float omega;
float eturn_1;
float k_turn_I = .8;// this will need to be tuned to damp the system
float k_turn_p = .7; // tune for pid;
float eturn_p;
float k_turn_d = .05; // tune for the d
int satR;
int satL;



struct position {
    float x;
    float y;
    float bearing;
    float omega;
    float velx;
    float vely;
    float dist_to_line;
    int direction_to_line;// boolean left of the robot is positive
    float distance_along_line;

};

struct line {
    float line_global_heading;
    float x1;
    float y1;
    float x2;
    float y2;
    float length;
    int index_line;
    int pen_down_bool;

};

float aim(struct position pos, struct line prev_line);// this function will generate the angle that the wheels should be
void gen_line(float x_2, float y_2);// this function will generate the line that I want to follow
//void set_wheel_speeds(float turn_angle);
void set_pen_down(int pen_down);
void update_pos(float cur_x, float cur_y, float cur_bearing, float cur_vel_x, float cur_vel_y, float omega_in);
float set_velocity = 3.0; // this is the baseline velocity that the wheels will be trying to get too
int go();// this position will make the wheels run, it will return 1 when it is "close enough" to the point 0 is running.
struct position cur_pos;
struct line cur_line;
struct line prev_line;
void setEPWM2A(float controleffort);
void setEPWM2B(float controleffort);
//float turn_angle(struct position pos, float turn_current, float[] turn_error, struct line cur_line) {
    // here will be a pid loop to get back on track
    // there will be a constant set velocity and then turn will increase or decrease the velocities of the wheels to turn

//} */


float set_velocity = .7; // this is the baseline velocity that the wheels will be trying to get too
float cur_x_e = 0;
float cur_y_e = 0;
float cur_bearing_e = 0;
float cur_vel_x_e = 0;
float cur_vel_y_e = 0;
float cur_omega_in_e = 0;
int last_line_index = 25;
int ready = 0;


extern float eturn;
extern float turn;
extern float eturn_I;
extern float vel_right;
extern float vel_left;
extern float eturn_I_1;
extern float zero_x;
extern float zero_y;
extern float shift_pos_x;
extern float shift_pos_y;
extern float shift_line_x2;
extern float shift_line_y2;
extern float ux;
extern float uy;
extern float top;
extern float bottom;
extern float proj_x;
extern float proj_y;
extern float comp_x;
extern float comp_y;
extern float slope_line;
extern float slope;
extern float slope_robot_line;
extern float eturn_d;
extern float omega;
extern float eturn_1;
//extern float k_turn_I;// this will need to be tuned to damp the system
//extern float k_turn_p; // tune for pid;
extern float eturn_p;
extern float k_turn_d; // tune for the d
extern float Kp;
extern float Ki;
extern int satR;
extern int satL;
extern float xarray_i[100];
extern float yarray_i[100];
extern float VLeftK;
extern float VRightK;

float evel_left = 0.0;
float evel_right = 0.0;
float IrightK = 0.0;
float IrightK_1 = 0.0;
float evel_right_1 = 0.0;
float IleftK = 0.0;
float IleftK_1 = 0.0;
float evel_left_1 = 0.0;
float distance_to_point = 0.0;

float k_turn_I = 2;
float k_turn_p = 1.0;
float kp_vel = 2;
float ki_vel = 10;
float k_overall_turn = 2.0;


struct position cur_pos;
struct line cur_line;
struct line prev_line;


int turn_left = 0;
int turn_right = 0;
float hard_vell = 0.0;
float hard_velr = 0.0;
int time_out_count = 0;



int go(void) {
    update_pos(cur_x_e, cur_y_e, cur_bearing_e, cur_vel_x_e, cur_vel_y_e, cur_omega_in_e); // figure out where we are
    //set_pen_down(cur_line.pen_down_bool);
    if(!ready) {// wait for the lines to be sent over

        set_pen_down(0); // keep pen up
        return 0;
    }

    set_pen_down(1); // puts the pen down
    if(cur_line.index_line > 25) { // this statment should be catching us at the end
                   setEPWM2B(0.0);// stopping the robot
                   setEPWM2A(0.0);
                   set_pen_down(0); // putting the pen up
                   return 0;
    }

    if(cur_pos.distance_to_pos < .05) { // if we are close to the point we are trying to get to we should make another point
            // if we are in this statment we are at the end of the line
            setEPWM2B(0.0);
            setEPWM2A(0.0);
            //DELAY_US(3000000); //delay in microseconds so 3 seconds is 3 000 000
            gen_line(xarray_i[cur_line.index_line + 1], yarray_i[cur_line.index_line + 1]);//make another point
            //aim(cur_pos, cur_line);
            //set_pen_down(1);
            return 1;
    }

    if((cur_pos.bearing_wanted - cur_pos.bearing) < .02 & ((cur_pos.bearing_wanted - cur_pos.bearing) > -.02)) { // if we are close to the right direction
        turn_left = 0;// dont turn left or right
        turn_right = 0;
    } else if ((cur_pos.bearing_wanted - cur_pos.bearing) > 0) { // if our bearing wanted is greater than the bearing we have turn right
        turn_right = 1;// turn right
        turn_left = 0;
    } else {
        turn_right = 0;
        turn_left = 1; // we turn left
    }

    time_out_count = time_out_count + 1; // time out counter so that every 3 seconds we change targets in case we get stuck
    if(time_out_count == 750) {
        time_out_count = 0;
        gen_line(xarray_i[cur_line.index_line + 1], yarray_i[cur_line.index_line + 1]); // changes the target
    }

    if (turn_left == 1) { // if turn left turn left
        //setEPWM2B(-2.0);
        hard_vell = -4;
        //setEPWM2A(-2.0);
        hard_velr = -4;
    } else if (turn_right == 1) { // if turn right turn right
        //setEPWM2B(2.0);
        hard_vell = 4;
        hard_velr = 4;
        //setEPWM2A(2.0);
    } else { // else straight
        //setEPWM2B(-2.0);
        hard_vell = -1.7;
        hard_velr = 1.5;
        //setEPWM2A(2.0);
    }
    setEPWM2B(hard_vell); // left epwm
    setEPWM2A(hard_velr); // right epwm
    return 1;

    /* below is all of the code for the second control algorithm. PID on bearing

    } else if (cur_line.length == 0 ) { // if this statment is true the x2 and x1 and y2 and y1 are the same

        set_pen_down(0);
        gen_line(xarray_i[cur_line.index_line + 1], yarray_i[cur_line.index_line + 1]);
        return 0;
    }
    else if(cur_pos.distance_to_pos < .2) {
        // if we are in this statment we are at the end of the line
        setEPWM2B(0.0);
        setEPWM2A(0.0);
        //DELAY_US(3000000); //delay in microseconds so 3 seconds is 3 000 000
        gen_line(xarray_i[cur_line.index_line + 1], yarray_i[cur_line.index_line + 1]);
        //aim(cur_pos, cur_line);
        //set_pen_down(1);
        return 1;


    }  else { // we are driving I guess
        //setEPWM2B(0.0);
        //setEPWM2A(0.0);
        set_pen_down(cur_line.pen_down_bool);
        aim(cur_pos, cur_line);

        return 1;
    } */
    //aim2(cur_pos.bearing_wanted, cur_pos.distance_to_pos);
    //gen_line(xarray_i[cur_line.index_line + 1], yarray_i[cur_line.index_line + 1]);
}
// to do- make a turn for while the system is at the end of the line
float aim(struct position pos, struct line the_line) {
    // here will be a PID loop and the activation for the motors


        //PosLeft_k_1 = PosLeft_k;// all of the code in this section is setting the previous values of all of the needed values so we can integrate or derive
        //PosRight_k_1 = PosRight_k;
        //eLeft_k_1 = eLeft_k;
        //eRight_k_1 = eRight_k;
        //ILeft_k_1 = ILeft_k;
        //IRight_k_1 = IRight_k;
        //LeftWheel_k_1 = LeftWheel;
        //RightWheel_k_1 = RightWheel;
        //xdot_k_1 = xdot;
        //ydot_k_1 = ydot;

        //LeftWheel = readEncLeft();// sets left wheel distance (technically total amt of angle change)
        //RightWheel = readEncRight(); // sets left wheel distance (technically total amt of angle change)
        //wLeftK = (LeftWheel- LeftWheel_k_1) / 0.004; // calculates velocity based on time difference and previous position
        //wRightK = (RightWheel - RightWheel_k_1) / 0.004; // same here but right

        //PosLeft_k = LeftWheel / 5.128; //converts from rad to ft
        //PosRight_k = RightWheel / 5.128; // doing it again


        //bearing = .1946/.56759*(RightWheel - LeftWheel); // this finds the "compass" direction. but it is really just the angle change since beginning
        //theta_avg_k = .5*(RightWheel + LeftWheel); // finds the average distance of the robot
        //omega_avg_k = .5*(wRightK + wLeftK); // finds the avg velocity of the robot
        //xdot = .19460*omega_avg_k*cos(bearing); // finds the x velocity of the robot
        //ydot = .19460*omega_avg_k*sin(bearing); // finds the yvelocity of the robot

        //globalx = globalx + .004*(xdot+xdot_k_1)/2; // this is global x coordinate with starting pos as 0
        //globaly = globaly + .004*(ydot+ydot_k_1)/2; // global y coordinate with starting pos as 0

        //VLeftK = (PosLeft_k - PosLeft_k_1) / 0.004; // calculates velocity based on time difference and previous position
        //VRightK = (PosRight_k - PosRight_k_1) / 0.004;


        //eturn = (VLeftK - VRightK) + turn; // error but the turn is to help with turning
        //eLeft_k = set_velocity - Kturn*eturn;//- VLeftK ; // error left
        //eRight_k = set_velocity + Kturn*eturn;//- VRightK; // error right (to be used with pid)
        //if (satR) {
            // don't run the else so that we stop summing no more integral windup
        //} else {
            //IRight_k = IRight_k_1 + 0.004 * (eRight_k + eRight_k_1) / 2; // integrate for PID
        //}
        //if (satL) {
            // dont run the else so that we stop summing
        //} else {
          //  ILeft_k = ILeft_k_1 + 0.004 * (eLeft_k + eLeft_k_1) / 2; // integrate for PID
        //}

        //uLeft = Kp * eLeft_k + Ki * ILeft_k; // PI for left wheel
        //uRight = Kp * eRight_k + Ki * IRight_k; // PI for right wheel

        //if ((uRight < 10) & (uRight > -10)) { // this is code to make sure that we don't request too much
          //  satR = 0; // reset the satR
        //}
        //if ((uLeft < 10) & (uLeft > -10)) {
          //  satL = 0; // reset the satL
        //}

    //eturn = cur_pos.dist_to_line * (cur_pos.direction_to_line * (-1.0)); // essentially distance back to line but has direction
    //eturn = cur_pos.bearing_wanted - cur_pos.bearing; // current eturn is going to be the difference between the bearing wanted and what is had
    eturn = (VLeftK - VRightK) + (cur_pos.bearing_wanted - cur_pos.bearing);
    //eturn_d = -omega;
    eturn_I = (eturn+eturn_1)/2*.004 + eturn_I_1; // using trapezoid rule to get integral of error terms
    turn = k_turn_I*eturn_I + k_turn_p*(eturn_p);// + k_turn_d*eturn_d;

    if (distance_to_point < 1) {
        set_velocity = distance_to_point;
    } else {
        set_velocity = 3;
    }

    evel_left = set_velocity - VLeftK - k_overall_turn*turn; // can flip these
    evel_right = set_velocity - VRightK + k_overall_turn*turn;
    IrightK = IrightK_1 + (evel_right + evel_right_1)/2*.004;
    IleftK = IleftK_1 + (evel_left + evel_left_1)/2*.004;

    //eturn = (VLeftK - VRightK) + turn; // error but the turn is to help with turning
    //eLeft_k = set_velocity - Kturn*eturn- VLeftK ; // error left
   //eRight_k = set_velocity + Kturn*eturn- VRightK; // error right (to be used with pid)



    vel_left = kp_vel * evel_left + ki_vel * IleftK; // PI for left wheel
    vel_right = kp_vel * evel_right + ki_vel * IrightK; // PI for right wheel


    if (turn > 5) {
        turn = 5;
    } else if (turn < -5) {
        turn = -5;
    }

    if (eturn_I > 5) {
        eturn_I = 5;
    } else if  (eturn_I < -5) {
        eturn_I = -5;
    }

    if (vel_left >= 7.0) {
        vel_left = 7.0;
    } else if (vel_left <= -7.0) {
        vel_left = -7.0;
    }

    if (vel_right >= 7.0) {
        vel_right = 7.0;
    } else if (vel_right <= -7.0) {
        vel_right = -7.0;
    }

    if (IleftK >= 15) {
        IleftK = 15;
    } else if (IleftK <= -15) {
        IleftK = -15;
    }

    if (IrightK >= 15) {
            IrightK = 15;
    } else if (IrightK <= -15) {
            IrightK = -15;
   }





    // change of plan is being done here
    // need to use a PID on the robots bearing
    // bearing_wanted should be the global bearing towards the target

    setEPWM2B(-vel_left/2); //maddie added a negative
    setEPWM2A(vel_right/2);

    eturn_1 = eturn;
    eturn_I_1 = eturn_I;
    IleftK_1 = IleftK;
    IrightK_1 = IrightK;
    evel_right_1 = evel_right;
    evel_left_1 = evel_left;
    return turn;

}



void gen_line(float x_2, float y_2) {
    cur_line.x1 = prev_line.x2; // set the current line x value equal to the previous line second x val
    cur_line.y1 = prev_line.y2; // set the current line y start to the previous line y end
    cur_line.x2 = x_2; // set the current line x final to the value it wants
    cur_line.y2 = y_2; // set the current line y value equal to what it wants
    // now to get bearing in degrees
    //slope = (cur_line.y2 - cur_line.y1)/(cur_line.x2- cur_line.x1); // this fines the global slope of the current line
    //cur_line.line_global_heading = atan(slope); // this fines the global heading of the line in degrees
    cur_line.length = sqrt(((cur_line.x2-cur_line.x1)*(cur_line.x2-cur_line.x1)) + ((cur_line.y2 - cur_line.y1)*(cur_line.y2 - cur_line.y1)));
    // the above line finds the length from the start to the finish of the line
    cur_line.index_line = prev_line.index_line + 1;// this line adds one to the starting value of the previous line
    if (prev_line.index_line == 0) { // just recall that the index starts at 1 for the first line but the previous
        // line will be initialized with all 0's
        // this function should be changed for multiple lines
        cur_line.pen_down_bool = 0; // the pen is up
    } else if(prev_line.index_line == last_line_index) {
        cur_line.pen_down_bool = 0; // the pen is up if it is the last line
    } else {
        cur_line.pen_down_bool = 1; // the pen is down
    }
    prev_line = cur_line; // set the previous line equal to the new line
}

void update_pos(float cur_x, float cur_y, float cur_bearing, float cur_vel_x, float cur_vel_y, float omega_in) {
    //zero_x = cur_line.x1; // this sets where our local 0 is
    //zero_y = cur_line.y1; // this sets where our local 0 is
    // this bout to get mathy
    //https://textbooks.math.gatech.edu/ila/projections.html
    cur_pos.omega = omega_in; // next lines are getting matt code date
    cur_pos.x = cur_x;
    cur_pos.y = cur_y;
    cur_pos.bearing = cur_bearing;
    cur_pos.velx = cur_vel_x;
    cur_pos.vely = cur_vel_y;

    //shift_pos_x = cur_pos.x - zero_x; // this is now the current local position
    //shift_pos_y = cur_pos.y - zero_y; // this is now the current local position

    //shift_line_x2 = cur_line.x2 - zero_x; // this is the local end value
    //shift_line_y2 = cur_line.x2 - zero_x; // this is the local end value
    //if((shift_line_x2  == 0) & (shift_line_y2 == 0)) {
        //gen_line(xarray_i[cur_line.index_line + 1], yarray_i[cur_line.index_line + 1]);
      //  return ; // if the line value lenght is 0
    //}
    //need to (vec(u).vec(x)/vec(u).vec(u))vec(u)
    // this is to get the projection of the point onto the line
    // will write as top/bottom * ux and top/bottom * uy
    // u is the unit vector along the line
    //ux = shift_line_x2/cur_line.length; // this is the local direction vector
    //uy = shift_line_y2/cur_line.length; // this is the local direction vector

    // theoretically the ux^2 + uy^2 = 1 but thats lin alg

    //top = ux*shift_pos_x + uy*shift_pos_y; // for projection it is the dot product
    //bottom = ux*ux + uy*uy;

   // proj_x = top/bottom*ux;
   // proj_y = top/bottom*uy;

    //cur_pos.distance_along_line = sqrt(proj_x*proj_x + proj_y*proj_y); // this is the length of the projection

    //comp_x = shift_pos_x - proj_x; // this is used for the distance to the line
    //comp_y = shift_pos_y - proj_y; // this is used for the distance to the line

    //cur_pos.dist_to_line = sqrt(comp_x*comp_x + comp_y*comp_y); // this finds the distance to the line
    // this is a little weird to get which side it is on
    // This is also the most likely point for errors
    // we need to find whether the line is on the right side or left side of the robot
    // i will use the direction of the line
    // then I will check whether the line from the robots current pos to the end of the line is more negative
    //slope_line = (cur_line.y2 - cur_line.y1)/(cur_line.x2 - cur_line.x1);
    //slope_robot_line = (cur_line.y2 - cur_pos.y)/(cur_line.x2 - cur_pos.x);
    //cur_pos.direction_to_line = (slope_line <= slope_robot_line);//left is 1 right is 0
    //imagine a vector or a line to both the position and to the final pos of line

    //cur_pos.direction_to_line = -1; // set to get rid of the value
    //cur_pos.distance_to_line = 0.0;
    //cur_pos.distance_along_line = 0.0;

    cur_pos.bearing_wanted = atan2((cur_line.y2-cur_pos.y),(cur_line.x2 - cur_pos.x)) - 3.14159265/2;
    cur_pos.distance_to_pos = sqrt(((cur_pos.x - cur_line.x2)*(cur_pos.x- cur_line.x2)) + ((cur_pos.y-cur_line.y2)*(cur_pos.y - cur_line.y2)));
    //cur_pos.direction_to_l


}


//void set_wheel_speeds(float turn_angle) {


//}


    }
}

F28370dSerial.c

C/C++
Code to communicate between Raspberry Pi and red board
/* SERIAL.C: This code is designed to act as a low-level serial driver for
    higher-level programming.  Ideally, one could simply call init_serial()
    to initialize the serial port, then use serial_send("data", 4) to send
    an array of data (8-bit unsigned character strings).

    WRITTEN BY : Paul Miller <pamiller@uiuc.edu>
    $Id: serial.c,v 1.4 2003/08/08 16:08:56 paul Exp $
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <limits.h>

#include "F28x_Project.h"     // Device Headerfile and Examples Include File
#include <buffer.h>
#include <F28379dSerial.h>
#include <F2837xD_sci.h>

serialSCIA_t SerialA;
serialSCIB_t SerialB; 
serialSCIC_t SerialC;
serialSCID_t SerialD;

char RXAdata = 0;
char RXBdata = 0;
char RXCdata = 0;
char RXDdata = 0;
uint32_t numRXA = 0;
uint32_t numRXB = 0;
uint32_t numRXC = 0;
uint32_t numRXD = 0;

float cx = 0;
float cy = 0;
float cbearing = 0;

//for serial com with pi
typedef union {
    uint16_t parts[2];
    float value;
} float_int;

uint16_t com_state = 0;
char send_sci[40]; //send the float
float_int to_send[10];
uint16_t received_count = 0;
uint16_t opti_count = 0;
float_int received_pi[60];
char temp_MSB = 0;

extern float xarray[25];
extern float yarray[25];
extern float apriltag;

// for SerialA
uint16_t init_serialSCIA(serialSCIA_t *s, uint32_t baud)
{
    volatile struct SCI_REGS *sci;
    uint32_t clk;

    if (s == &SerialA) {
        sci = &SciaRegs;
        s->sci = sci;
        init_bufferSCIA(&s->TX);

        GPIO_SetupPinMux(43, GPIO_MUX_CPU1, 15);
        GPIO_SetupPinOptions(43, GPIO_INPUT, GPIO_PULLUP);
        GPIO_SetupPinMux(42, GPIO_MUX_CPU1, 15);
        GPIO_SetupPinOptions(42, GPIO_OUTPUT, GPIO_PUSHPULL);

    } else {
        return 1;
    }

    /* init for standard baud,8N1 comm */
    sci->SCICTL1.bit.SWRESET = 0;       // init SCI state machines and opt flags
    sci->SCICCR.all = 0x0;
    sci->SCICTL1.all = 0x0;
    sci->SCICTL2.all = 0x0;
    sci->SCIPRI.all = 0x0;
    clk = LSPCLK_HZ;                    // set baud rate
    clk /= baud*8;
    clk--;
    sci->SCILBAUD.all = clk & 0xFF;
    sci->SCIHBAUD.all = (clk >> 8) & 0xFF;

    sci->SCICCR.bit.SCICHAR = 0x7;      // (8) 8 bits per character
    sci->SCICCR.bit.PARITYENA = 0;      // (N) disable party calculation
    sci->SCICCR.bit.STOPBITS = 0;       // (1) transmit 1 stop bit
    sci->SCICCR.bit.LOOPBKENA = 0;      // disable loopback test
    sci->SCICCR.bit.ADDRIDLE_MODE = 0;  // idle-line mode (non-multiprocessor SCI comm)

    sci->SCIFFCT.bit.FFTXDLY = 0;       // TX: zero-delay

    sci->SCIFFTX.bit.SCIFFENA = 1;      // enable SCI fifo enhancements
    sci->SCIFFTX.bit.TXFIFORESET = 0;
    sci->SCIFFTX.bit.TXFFIL = 0x0;// TX: fifo interrupt at all levels   ???? is this correct
    sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    sci->SCIFFTX.bit.TXFIFORESET = 1;

    sci->SCIFFRX.bit.RXFIFORESET = 0;   // RX: fifo reset
    sci->SCIFFRX.bit.RXFFINTCLR = 1;    // RX: clear interrupt flag
    sci->SCIFFRX.bit.RXFFIENA = 1;      // RX: enable fifo interrupt
    sci->SCIFFRX.bit.RXFFIL = 0x1;      // RX: fifo interrupt
    sci->SCIFFRX.bit.RXFIFORESET = 1;   // RX: re-enable fifo

    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.TXWAKE = 0;
    sci->SCICTL1.bit.SLEEP = 0;         // disable sleep mode
    sci->SCICTL1.bit.RXENA = 1;         // enable SCI receiver
    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL1.bit.TXENA = 1;         // enable SCI transmitter
    sci->SCICTL1.bit.SWRESET = 1;       // re-enable SCI

    /* enable PIE interrupts */
    if (s == &SerialA) {
        PieCtrlRegs.PIEIER9.bit.INTx1 = 1;
        PieCtrlRegs.PIEIER9.bit.INTx2 = 1;
        IER |= (M_INT9);
        PieCtrlRegs.PIEACK.all = (PIEACK_GROUP9);

    }

    return 0;
}

void uninit_serialSCIA(serialSCIA_t *s)
{
    volatile struct SCI_REGS *sci = s->sci;

    /* disable PIE interrupts */
    if (s == &SerialA) {
        PieCtrlRegs.PIEIER9.bit.INTx1 = 0;
        PieCtrlRegs.PIEIER9.bit.INTx2 = 0;
        IER &= ~M_INT9;
    }
    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.RXENA = 0;         // disable SCI receiver
    sci->SCICTL1.bit.TXENA = 0;         // disable SCI transmitter
}



/***************************************************************************
 * SERIAL_SEND()
 *
 * "User level" function to send data via serial.  Return value is the
 * length of data successfully copied to the TX buffer.
 ***************************************************************************/
uint16_t serial_sendSCIA(serialSCIA_t *s, char *data, uint16_t len)
{
    uint16_t i = 0;
    if (len && s->TX.size < BUF_SIZESCIA) {
        for (i = 0; i < len; i++) {
            if (buf_writeSCIA_1(&s->TX, data[i] & 0x00FF) != 0) break;
        }
        s->sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
        s->sci->SCIFFTX.bit.TXFFIENA = 1;       // TX: enable fifo interrupt
    }
    return i;
}

// For SerialB
uint16_t init_serialSCIB(serialSCIB_t *s, uint32_t baud)
{
    volatile struct SCI_REGS *sci;
    uint32_t clk;

    if (s == &SerialB) {
        sci = &ScibRegs;
        s->sci = sci;
        init_bufferSCIB(&s->TX);

        GPIO_SetupPinMux(15, GPIO_MUX_CPU1, 2);
        GPIO_SetupPinOptions(15, GPIO_INPUT, GPIO_PULLUP);
        GPIO_SetupPinMux(14, GPIO_MUX_CPU1, 2);
        GPIO_SetupPinOptions(14, GPIO_OUTPUT, GPIO_PUSHPULL);


    } else {
        return 1;
    }

    /* init for standard baud,8N1 comm */
    sci->SCICTL1.bit.SWRESET = 0;       // init SCI state machines and opt flags
    sci->SCICCR.all = 0x0;
    sci->SCICTL1.all = 0x0;
    sci->SCICTL2.all = 0x0;
    sci->SCIPRI.all = 0x0;
    clk = LSPCLK_HZ;                    // set baud rate
    clk /= baud*8;
    clk--;
    sci->SCILBAUD.all = clk & 0xFF;
    sci->SCIHBAUD.all = (clk >> 8) & 0xFF;

    sci->SCICCR.bit.SCICHAR = 0x7;      // (8) 8 bits per character
    sci->SCICCR.bit.PARITYENA = 0;      // (N) disable party calculation
    sci->SCICCR.bit.STOPBITS = 0;       // (1) transmit 1 stop bit
    sci->SCICCR.bit.LOOPBKENA = 0;      // disable loopback test
    sci->SCICCR.bit.ADDRIDLE_MODE = 0;  // idle-line mode (non-multiprocessor SCI comm)

    sci->SCIFFCT.bit.FFTXDLY = 0;       // TX: zero-delay

    sci->SCIFFTX.bit.SCIFFENA = 1;      // enable SCI fifo enhancements
    sci->SCIFFTX.bit.TXFIFORESET = 0;
    sci->SCIFFTX.bit.TXFFIL = 0x0;// TX: fifo interrupt at all levels   ???? is this correct
    sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    sci->SCIFFTX.bit.TXFIFORESET = 1;

    sci->SCIFFRX.bit.RXFIFORESET = 0;   // RX: fifo reset
    sci->SCIFFRX.bit.RXFFINTCLR = 1;    // RX: clear interrupt flag
    sci->SCIFFRX.bit.RXFFIENA = 1;      // RX: enable fifo interrupt
    sci->SCIFFRX.bit.RXFFIL = 0x1;      // RX: fifo interrupt
    sci->SCIFFRX.bit.RXFIFORESET = 1;   // RX: re-enable fifo

    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.TXWAKE = 0;
    sci->SCICTL1.bit.SLEEP = 0;         // disable sleep mode
    sci->SCICTL1.bit.RXENA = 1;         // enable SCI receiver
    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL1.bit.TXENA = 1;         // enable SCI transmitter
    sci->SCICTL1.bit.SWRESET = 1;       // re-enable SCI

    /* enable PIE interrupts */
    if (s == &SerialB) {
        PieCtrlRegs.PIEIER9.bit.INTx3 = 1;
        PieCtrlRegs.PIEIER9.bit.INTx4 = 1;
        IER |= (M_INT9);
        PieCtrlRegs.PIEACK.all = (PIEACK_GROUP9);
    }

    return 0;
}

void uninit_serialSCIB(serialSCIB_t *s)
{
    volatile struct SCI_REGS *sci = s->sci;

    /* disable PIE interrupts */
    if (s == &SerialB) {
        PieCtrlRegs.PIEIER9.bit.INTx3 = 0;
        PieCtrlRegs.PIEIER9.bit.INTx4 = 0;
        IER &= ~M_INT9;
    }

    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.RXENA = 0;         // disable SCI receiver
    sci->SCICTL1.bit.TXENA = 0;         // disable SCI transmitter
}



/***************************************************************************
 * SERIAL_SEND()
 *
 * "User level" function to send data via serial.  Return value is the
 * length of data successfully copied to the TX buffer.
 ***************************************************************************/
uint16_t serial_sendSCIB(serialSCIB_t *s, char *data, uint16_t len)
{
    uint16_t i = 0;
    if (len && s->TX.size < BUF_SIZESCIB) {
        for (i = 0; i < len; i++) {
            if (buf_writeSCIB_1(&s->TX, data[i] & 0x00FF) != 0) break;
        }
        s->sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
        s->sci->SCIFFTX.bit.TXFFIENA = 1;       // TX: enable fifo interrupt
    }
    return i;
}

// for SerialC
uint16_t init_serialSCIC(serialSCIC_t *s, uint32_t baud)
{
    volatile struct SCI_REGS *sci;
    uint32_t clk;

    if (s == &SerialC) {
        sci = &ScicRegs;
        s->sci = sci;
        init_bufferSCIC(&s->TX);
        GPIO_SetupPinMux(139, GPIO_MUX_CPU1, 6);
        GPIO_SetupPinOptions(139, GPIO_INPUT, GPIO_PULLUP);
        GPIO_SetupPinMux(56, GPIO_MUX_CPU1, 6);
        GPIO_SetupPinOptions(56, GPIO_OUTPUT, GPIO_PUSHPULL);

    } else {
        return 1;
    }

    /* init for standard baud,8N1 comm */
    sci->SCICTL1.bit.SWRESET = 0;       // init SCI state machines and opt flags
    sci->SCICCR.all = 0x0;
    sci->SCICTL1.all = 0x0;
    sci->SCICTL2.all = 0x0;
    sci->SCIPRI.all = 0x0;
    clk = LSPCLK_HZ;                    // set baud rate
    clk /= baud*8;
    clk--;
    sci->SCILBAUD.all = clk & 0xFF;
    sci->SCIHBAUD.all = (clk >> 8) & 0xFF;

    sci->SCICCR.bit.SCICHAR = 0x7;      // (8) 8 bits per character
    sci->SCICCR.bit.PARITYENA = 0;      // (N) disable party calculation
    sci->SCICCR.bit.STOPBITS = 0;       // (1) transmit 1 stop bit
    sci->SCICCR.bit.LOOPBKENA = 0;      // disable loopback test
    sci->SCICCR.bit.ADDRIDLE_MODE = 0;  // idle-line mode (non-multiprocessor SCI comm)

    sci->SCIFFCT.bit.FFTXDLY = 0;       // TX: zero-delay

    sci->SCIFFTX.bit.SCIFFENA = 1;      // enable SCI fifo enhancements
    sci->SCIFFTX.bit.TXFIFORESET = 0;
    sci->SCIFFTX.bit.TXFFIL = 0x0;// TX: fifo interrupt at all levels   ???? is this correct
    sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    sci->SCIFFTX.bit.TXFIFORESET = 1;

    sci->SCIFFRX.bit.RXFIFORESET = 0;   // RX: fifo reset
    sci->SCIFFRX.bit.RXFFINTCLR = 1;    // RX: clear interrupt flag
    sci->SCIFFRX.bit.RXFFIENA = 1;      // RX: enable fifo interrupt
    sci->SCIFFRX.bit.RXFFIL = 0x1;      // RX: fifo interrupt
    sci->SCIFFRX.bit.RXFIFORESET = 1;   // RX: re-enable fifo

    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.TXWAKE = 0;
    sci->SCICTL1.bit.SLEEP = 0;         // disable sleep mode
    sci->SCICTL1.bit.RXENA = 1;         // enable SCI receiver
    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL1.bit.TXENA = 1;         // enable SCI transmitter
    sci->SCICTL1.bit.SWRESET = 1;       // re-enable SCI

    /* enable PIE interrupts */
    if (s == &SerialC) {
        PieCtrlRegs.PIEIER8.bit.INTx5 = 1;
        PieCtrlRegs.PIEIER8.bit.INTx6 = 1;
        PieCtrlRegs.PIEACK.all = (PIEACK_GROUP8);
        IER |= (M_INT8);

    } 

    return 0;
}

void uninit_serialSCIC(serialSCIC_t *s)
{
    volatile struct SCI_REGS *sci = s->sci;

    /* disable PIE interrupts */
    if (s == &SerialC) {
        PieCtrlRegs.PIEIER8.bit.INTx5 = 0;
        PieCtrlRegs.PIEIER8.bit.INTx6 = 0;
        IER &= ~M_INT8;
    } 

    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.RXENA = 0;         // disable SCI receiver
    sci->SCICTL1.bit.TXENA = 0;         // disable SCI transmitter
}



/***************************************************************************
 * SERIAL_SEND()
 *
 * "User level" function to send data via serial.  Return value is the
 * length of data successfully copied to the TX buffer.
 ***************************************************************************/
uint16_t serial_sendSCIC(serialSCIC_t *s, char *data, uint16_t len)
{
    uint16_t i = 0;
    if (len && s->TX.size < BUF_SIZESCIC) {
        for (i = 0; i < len; i++) {
            if (buf_writeSCIC_1(&s->TX, data[i] & 0x00FF) != 0) break;
        }
        s->sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
        s->sci->SCIFFTX.bit.TXFFIENA = 1;       // TX: enable fifo interrupt
    }
    return i;
}

// For Serial D
uint16_t init_serialSCID(serialSCID_t *s, uint32_t baud)
{
    volatile struct SCI_REGS *sci;
    uint32_t clk;

    if (s == &SerialD) {
        sci = &ScidRegs;
        s->sci = sci;
        init_bufferSCID(&s->TX);
        GPIO_SetupPinMux(105, GPIO_MUX_CPU1, 6);
        GPIO_SetupPinOptions(105, GPIO_INPUT, GPIO_PULLUP);
        GPIO_SetupPinMux(104, GPIO_MUX_CPU1, 6);
        GPIO_SetupPinOptions(104, GPIO_OUTPUT, GPIO_PUSHPULL);
    }
    else {
        return 1;
    }

    /* init for standard baud,8N1 comm */
    sci->SCICTL1.bit.SWRESET = 0;       // init SCI state machines and opt flags
    sci->SCICCR.all = 0x0;
    sci->SCICTL1.all = 0x0;
    sci->SCICTL2.all = 0x0;
    sci->SCIPRI.all = 0x0;
    clk = LSPCLK_HZ;                    // set baud rate
    clk /= baud*8;
    clk--;
    sci->SCILBAUD.all = clk & 0xFF;
    sci->SCIHBAUD.all = (clk >> 8) & 0xFF;

    sci->SCICCR.bit.SCICHAR = 0x7;      // (8) 8 bits per character
    sci->SCICCR.bit.PARITYENA = 0;      // (N) disable party calculation
    sci->SCICCR.bit.STOPBITS = 0;       // (1) transmit 1 stop bit
    sci->SCICCR.bit.LOOPBKENA = 0;      // disable loopback test
    sci->SCICCR.bit.ADDRIDLE_MODE = 0;  // idle-line mode (non-multiprocessor SCI comm)

    sci->SCIFFCT.bit.FFTXDLY = 0;       // TX: zero-delay

    sci->SCIFFTX.bit.SCIFFENA = 1;      // enable SCI fifo enhancements
    sci->SCIFFTX.bit.TXFIFORESET = 0;
    sci->SCIFFTX.bit.TXFFIL = 0x0;// TX: fifo interrupt at all levels   ???? is this correct
    sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    sci->SCIFFTX.bit.TXFIFORESET = 1;

    sci->SCIFFRX.bit.RXFIFORESET = 0;   // RX: fifo reset
    sci->SCIFFRX.bit.RXFFINTCLR = 1;    // RX: clear interrupt flag
    sci->SCIFFRX.bit.RXFFIENA = 1;      // RX: enable fifo interrupt
    sci->SCIFFRX.bit.RXFFIL = 0x1;      // RX: fifo interrupt
    sci->SCIFFRX.bit.RXFIFORESET = 1;   // RX: re-enable fifo

    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.TXWAKE = 0;
    sci->SCICTL1.bit.SLEEP = 0;         // disable sleep mode
    sci->SCICTL1.bit.RXENA = 1;         // enable SCI receiver
    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL1.bit.TXENA = 1;         // enable SCI transmitter
    sci->SCICTL1.bit.SWRESET = 1;       // re-enable SCI

    /* enable PIE interrupts */
    if (s == &SerialD) {
        PieCtrlRegs.PIEIER8.bit.INTx7 = 1;
        PieCtrlRegs.PIEIER8.bit.INTx8 = 1;
        PieCtrlRegs.PIEACK.all = (PIEACK_GROUP8);
        IER |= (M_INT8);
    }

    return 0;
}

void uninit_serialSCID(serialSCID_t *s)
{
    volatile struct SCI_REGS *sci = s->sci;

    /* disable PIE interrupts */
    if (s == &SerialD) {
        PieCtrlRegs.PIEIER8.bit.INTx7 = 0;
        PieCtrlRegs.PIEIER8.bit.INTx8 = 0;
        IER &= ~M_INT8;
    }

    sci->SCICTL1.bit.RXERRINTENA = 0;   // disable receive error interrupt
    sci->SCICTL2.bit.RXBKINTENA = 0;    // disable receiver/error interrupt
    sci->SCICTL2.bit.TXINTENA = 0;      // disable transmitter interrupt

    sci->SCICTL1.bit.RXENA = 0;         // disable SCI receiver
    sci->SCICTL1.bit.TXENA = 0;         // disable SCI transmitter
}



/***************************************************************************
 * SERIAL_SEND()
 *
 * "User level" function to send data via serial.  Return value is the
 * length of data successfully copied to the TX buffer.
 ***************************************************************************/
uint16_t serial_sendSCID(serialSCID_t *s, char *data, uint16_t len)
{
    uint16_t i = 0;
    if (len && s->TX.size < BUF_SIZESCID) {
        for (i = 0; i < len; i++) {
            if (buf_writeSCID_1(&s->TX, data[i] & 0x00FF) != 0) break;
        }
        s->sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
        s->sci->SCIFFTX.bit.TXFFIENA = 1;       // TX: enable fifo interrupt
    }
    return i;
}



/***************************************************************************
 * TXxINT_DATA_SENT()
 *
 * Executed when transmission is ready for additional data.  These functions
 * read the next char of data and put it in the TXBUF register for transfer.
 ***************************************************************************/
#ifdef _FLASH
#pragma CODE_SECTION(TXAINT_data_sent, ".TI.ramfunc");
#endif
__interrupt void TXAINT_data_sent(void)
{
    char data;
    if (buf_readSCIA_1(&SerialA.TX,0,&data) == 0) {
        while ( (buf_readSCIA_1(&SerialA.TX,0,&data) == 0)
                && (SerialA.sci->SCIFFTX.bit.TXFFST != 0x10) ) {
            buf_removeSCIA(&SerialA.TX, 1);
            SerialA.sci->SCITXBUF.all = data;
        }
    } else {
        SerialA.sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    }
    SerialA.sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}


//for serialB
#ifdef _FLASH
#pragma CODE_SECTION(TXBINT_data_sent, ".TI.ramfunc");
#endif
__interrupt void TXBINT_data_sent(void)
{
    char data;
    if (buf_readSCIB_1(&SerialB.TX,0,&data) == 0) {
        while ( (buf_readSCIB_1(&SerialB.TX,0,&data) == 0)
                && (SerialB.sci->SCIFFTX.bit.TXFFST != 0x10) ) {
            buf_removeSCIB(&SerialB.TX, 1);
            SerialB.sci->SCITXBUF.all = data;
        }
    } else {
        SerialB.sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    }
    SerialB.sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}


//for serialC
#ifdef _FLASH
#pragma CODE_SECTION(TXCINT_data_sent, ".TI.ramfunc");
#endif
__interrupt void TXCINT_data_sent(void)
{
    char data;
    if (buf_readSCIC_1(&SerialC.TX,0,&data) == 0) {
        while ( (buf_readSCIC_1(&SerialC.TX,0,&data) == 0)
                && (SerialC.sci->SCIFFTX.bit.TXFFST != 0x10) ) {
            buf_removeSCIC(&SerialC.TX, 1);
            SerialC.sci->SCITXBUF.all = data;
        }
    } else {
        SerialC.sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    }
    SerialC.sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}

//for serialD
#ifdef _FLASH
#pragma CODE_SECTION(TXDINT_data_sent, ".TI.ramfunc");
#endif
__interrupt void TXDINT_data_sent(void)
{
    char data;
    if (buf_readSCID_1(&SerialD.TX,0,&data) == 0) {
        while ( (buf_readSCID_1(&SerialD.TX,0,&data) == 0)
                && (SerialD.sci->SCIFFTX.bit.TXFFST != 0x10) ) {
            buf_removeSCID(&SerialD.TX, 1);
            SerialD.sci->SCITXBUF.all = data;
        }
    } else {
        SerialD.sci->SCIFFTX.bit.TXFFIENA = 0;      // TX: disable fifo interrupt
    }
    SerialD.sci->SCIFFTX.bit.TXFFINTCLR = 1;  // TX: clear interrupt flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}

//extern float turn;
//extern float globalx;
//extern float globaly;
//extern float bearing;
//extern float Vref;
//This function is called each time a char is received over UARTA.
//for SerialA
#ifdef _FLASH
#pragma CODE_SECTION(RXAINT_recv_ready, ".TI.ramfunc");
#endif
__interrupt void RXAINT_recv_ready(void)
{
    RXAdata = SciaRegs.SCIRXBUF.all;
    /* SCI PE or FE error */
    if (RXAdata & 0xC000) {
        SciaRegs.SCICTL1.bit.SWRESET = 0;
        SciaRegs.SCICTL1.bit.SWRESET = 1;
        SciaRegs.SCIFFRX.bit.RXFIFORESET = 0;
        SciaRegs.SCIFFRX.bit.RXFIFORESET = 1;
    } else {
        RXAdata = RXAdata & 0x00FF;
        numRXA ++;
        if (RXAdata == 'a') {
            //turn = turn + 0.05;
        } else if (RXAdata == 'd') {
           // turn = turn - 0.05;
        } else if (RXAdata == 'w') {
           // Vref = Vref + 0.1;

        } else if (RXAdata == 's') {
         //   Vref = Vref - 0.1;

        } else if (RXAdata == ' ') {
          //  Vref = 0;
           // turn = 0;
        } else if (RXAdata == 'm') {
           // globalx = 0.0;
          //  globaly = 0.0;
            //EQep1Regs.QPOSCNT = 0;
            //EQep2Regs.QPOSCNT = 0;
            //bearing = 0.0;
        } else {
          //  turn = 0;
           // Vref = 0.5;
        }
    }
    SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}

//for SerialB
#ifdef _FLASH
#pragma CODE_SECTION(RXBINT_recv_ready, ".TI.ramfunc");
#endif
__interrupt void RXBINT_recv_ready(void)
{
    RXBdata = ScibRegs.SCIRXBUF.all;

    /* SCI PE or FE error */
    if (RXBdata & 0xC000) {
        ScibRegs.SCICTL1.bit.SWRESET = 0;
        ScibRegs.SCICTL1.bit.SWRESET = 1;
        ScibRegs.SCIFFRX.bit.RXFIFORESET = 0;
        ScibRegs.SCIFFRX.bit.RXFIFORESET = 1;
    } else {
        RXBdata = RXBdata & 0x00FF;
        // Do something with recieved character
        numRXB ++;
    }

    ScibRegs.SCIFFRX.bit.RXFFINTCLR = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}


// for SerialC
#ifdef _FLASH
#pragma CODE_SECTION(RXCINT_recv_ready, ".TI.ramfunc");
#endif
__interrupt void RXCINT_recv_ready(void)
{
    RXCdata = ScicRegs.SCIRXBUF.all;

    /* SCI PE or FE error */
    if (RXCdata & 0xC000) {
        ScicRegs.SCICTL1.bit.SWRESET = 0;
        ScicRegs.SCICTL1.bit.SWRESET = 1;
        ScicRegs.SCIFFRX.bit.RXFIFORESET = 0;
        ScicRegs.SCIFFRX.bit.RXFIFORESET = 1;
    } else {
        RXCdata = RXCdata & 0x00FF;
        numRXC ++;

    }

    ScicRegs.SCIFFRX.bit.RXFFINTCLR = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}


//for SerialD
#ifdef _FLASH
#pragma CODE_SECTION(RXDINT_recv_ready, ".TI.ramfunc");
#endif
int setup = 1;
int i = 0;
__interrupt void RXDINT_recv_ready(void)
{
    RXDdata = ScidRegs.SCIRXBUF.all;

    /* SCI PE or FE error */
    if (RXDdata & 0xC000) {
        ScidRegs.SCICTL1.bit.SWRESET = 0;
        ScidRegs.SCICTL1.bit.SWRESET = 1;
        ScidRegs.SCIFFRX.bit.RXFIFORESET = 0;
        ScidRegs.SCIFFRX.bit.RXFIFORESET = 1;
    } else {
        RXDdata = RXDdata & 0x00FF;
        numRXD ++;

        if (com_state == 0) { //wait for April Tag data from pi
            if (RXDdata == '*'){
                com_state = 1;//pre echo state
            } else if (RXDdata == '!'){
                com_state = 2;//pre sending state
            } else if (RXDdata == '#'){
                com_state = 3;//wait for desired position data from pi
            } else {
                com_state = 0;
            }
        } else if (com_state == 1) {
            if (RXDdata == '*') {
                com_state = 10;//echo state
            } else {
                com_state = 0;
            }
        } else if (com_state == 10) { //echo state
            if (received_count % 2 == 0) {
                temp_MSB = RXDdata;
            } else {
                received_pi[received_count/4].parts[(received_count%4)/2] = ((RXDdata << 8) | temp_MSB) & 0xFFFF;
            }
            received_count += 1;

            if (received_count == 12){ // after receiving 3 sets of 4 bytes of data
                com_state = 0;
                received_count = 0;
                cx = received_pi[0].value; //set cx to first 4 bytes
                cy = received_pi[1].value; //set cy to second 4 bytes
                cbearing = received_pi[2].value; //set cbearing to third 4 bytes
                apriltag = 1; //flag that we received data from AprilTags
            }

        } else if (com_state == 3) {
            if (RXDdata == '#') {
                com_state = 20;//echo state
            } else {
                com_state = 0;
            }
        } else if (com_state == 20) {
            if (received_count % 2 == 0) {
                temp_MSB = RXDdata;
            } else {
                received_pi[received_count/4].parts[(received_count%4)/2] = ((RXDdata << 8) | temp_MSB) & 0xFFFF;
            }
            received_count += 1;

            if (received_count == 200){ // after receiving 50 sets of 4 bytes of data
                com_state = 0;
                received_count = 0;
                for (int i = 0;i<25;i++) { //add values to an xarray and a yarray, alternating as their sent one at a time
                    xarray[i] = received_pi[i*2].value;
                    yarray[i] = received_pi[i*2+1].value;
                }

            }

        } else if (com_state == 2) {
            if (RXDdata == '!') {
                int i = 0;
                for (i = 0; i < 2; i++) {
                    to_send[i].value = 0.1234+0.1*i;
                }
                for (i = 0; i < 2; i++) {
                    send_sci[4*i] = to_send[i].parts[0] & 0xFF;
                    send_sci[4*i+1] = (to_send[i].parts[0]>>8) & 0xFF;
                    send_sci[4*i+2] = to_send[i].parts[1] & 0xFF;
                    send_sci[4*i+3] = (to_send[i].parts[1]>>8) & 0xFF;
                }
                serial_sendSCID(&SerialD, send_sci, 8);
                com_state = 0;
            } else {
                com_state = 0;
            }
        }




    }

    ScidRegs.SCIFFRX.bit.RXFFINTCLR = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}


// SerialA only setup for Tera Term connection
char serial_printf_bufSCIA[BUF_SIZESCIA];

uint16_t serial_printf(serialSCIA_t *s, char *fmt, ...)
{
    va_list ap;

    va_start(ap,fmt);
    vsprintf(serial_printf_bufSCIA,fmt,ap);
    va_end(ap);

    return serial_sendSCIA(s,serial_printf_bufSCIA,strlen(serial_printf_bufSCIA));
}

aprilmav_test.py

Python
This code is used for the AprilTag and sending the location found from them
#!/usr/bin/env python3
'''
Main script. Will use Apriltags to localise position and send via mavlink

'''
import time
from importlib import import_module
from statistics import mean
from collections import deque
import argparse
import threading
import signal
import sys
import os
import socket #for open TCP

import yaml
import numpy
import cv2

from dt_apriltags import Detector
from pymavlink import mavutil

from lib.geo import tagDB
from lib.videoStream import videoThread
from lib.saveStream import saveThread

import serial
import struct
import time
from serial import Serial

exit_event = threading.Event()


#OPEN TCP
TCP_IP = '172.16.112.87'
TCP_PORT = 12321 #can modify if port is busy
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)

conn, addr = s.accept()
read_bool = 1;
while read_bool:
    data = conn.recv(BUFFER_SIZE)
    if not data: break
    print("received data:", data) #to verify string is read
    read_bool = 0
conn.close()

data = data.decode() #removes b from string
xandy = data.split() #split sent string into array
x = xandy[:len(xandy)//2] #split first half to get x values
y = xandy[len(xandy)//2:] #split second half to get y values
x = [eval(i) for i in x] #convert strings to integers
y = [eval(i) for i in y] #convert strings to integers

print(x)
print(y)

#initialize serial port so we can send drawing data from the LabVIEW and pose data from the AprilTag code to the red board
ser = serial.Serial("/dev/ttyAMA1", 115200) #Open port with baud rate

ser.write(str.encode('#')) #send two hashtags so that C code knows we're sending desired position
ser.write(str.encode('#'))
for i in range(25):
    ser.write(struct.pack('f',float(x[i]))) #send floats to C code
    ser.write(struct.pack('f',float(y[i])))
print(i) #make sure it finished
time.sleep(.1)
#end drawing data



def signal_handler(signum, frame):
    exit_event.set()

#Main class for AprilTag, initialized pose variables, update pose, and send data to the red board
class statusThread(threading.Thread):
    #initialized x,y,z postions and row, pitch, yaw angles
    def __init__(self):
        threading.Thread.__init__(self)
        self.lastFiveProTimes = deque(maxlen=5)
        self.pos = (0, 0, 0)
        self.rot = (0, 0, 0)
        self.pktSent = 0
    #updates position and angle data to newPos and newRot
    def updateData(self, proTime, newPos, newRot, pktWasSent):
        self.lastFiveProTimes.append(proTime)
        self.pos = newPos
        self.rot = newRot
        self.pktSent = pktWasSent
    #prints postion and angle data to terminal on the Raspberry Pi, sends position and angle data to the red board
    def run(self):
        while True:
            if len(self.lastFiveProTimes) > 0:
                fps = 1/mean(self.lastFiveProTimes)
            else:
                fps = 0
            #print out position and angle data in terminal
            print("Status: {0:.1f}fps, PosNED = {1}, PosRPY = {2}, Packets sent = {3}".format(
                fps, self.pos, self.rot, self.pktSent))
            #for j in range(200):
            #write data to serial port, this is the protocal for UART
            ser.write(str.encode('*'))
            ser.write(str.encode('*'))
            # we will only send x,y,and bearing (yaw) data to the red board
            for i in range(2):
                ser.write(struct.pack('f',self.pos[0]))
                ser.write(struct.pack('f',self.pos[1]))
                ser.write(struct.pack('f',self.rot[2]))
            time.sleep(.1)
            if exit_event.wait(timeout=2):
                return

# class for MAVlink communication protocol, will not be used in our application
class mavThread(threading.Thread):
    def __init__(self, device, baud, source_system):
        threading.Thread.__init__(self)
        self.device = device
        self.baud = baud
        self.source_system = source_system
        self.heartbeatTimestamp = time.time()
        self.lock = threading.Lock()
        self.conn = None
        self.goodToSend = False
        self.reset_counter = 0
        self.pos = (0, 0, 0)
        self.speed = (0, 0, 0)
        self.rot = (0, 0, 0)
        self.time = 0
        self.pktSent = 0
        self.target_system = 1
        self.origin_lat = -35.363261
        self.origin_lon = 149.165230
        self.origin_alt = 0
        self.posDelta = (0, 0, 0)
        self.rotDelta = (0, 0, 0)

    def updateData(self, newPos, newRot, t, posDelta, rotDelta):
        with self.lock:
            if self.time != 0:
                # time is in usec here, remember to convert to sec
                self.speed = numpy.array(posDelta)/ (1E-6 * (t - self.time))
            self.pos = newPos
            self.rot = newRot
            self.time = t
            self.posDelta = posDelta
            self.rotDelta = rotDelta

    def run(self):
        # Start mavlink connection
        try:
            self.conn = mavutil.mavlink_connection(self.device, autoreconnect=True, source_system=self.source_system,
                                                   baud=self.baud, force_connected=False, source_component=mavutil.mavlink.MAV_COMP_ID_VISUAL_INERTIAL_ODOMETRY)
        except Exception as msg:
            print("Failed to start mavlink connection on %s: %s" %
                  (self.device, msg,))
            raise

        # wait for the heartbeat msg to find the system ID. Need to exit from here too
        # We are sending a heartbeat signal too, to allow ardupilot to init the comms channel
        while True:
            self.sendHeartbeatAndEKFOrigin()
            if self.conn.wait_heartbeat(timeout=0.5) != None:
                # Got a hearbeart, go to next loop
                self.goodToSend = True
                break
            if exit_event.is_set():
                return

        print("Got Heartbeat from APM (system %u component %u)" %
              (self.conn.target_system, self.conn.target_system))
        self.send_msg_to_gcs("Starting")

        while True:
            msg = self.conn.recv_match(blocking=True, timeout=0.5)
            # loop at 20 Hz
            time.sleep(0.05)
            self.sendPos()
            self.sendSpeed()
            #self.sendPosDelta()
            self.sendHeartbeatAndEKFOrigin()
            if exit_event.is_set():
                self.send_msg_to_gcs("Stopping")
                return

    def sendHeartbeatAndEKFOrigin(self):
        # send heartbeat and EKF origin messages if more than 1 sec since last message
        if (self.heartbeatTimestamp + 1) < time.time():
            self.conn.mav.heartbeat_send(mavutil.mavlink.MAV_TYPE_ONBOARD_CONTROLLER,
                                         mavutil.mavlink.MAV_AUTOPILOT_GENERIC,
                                         0,
                                         0,
                                         0)
            self.set_default_global_origin()
            self.heartbeatTimestamp = time.time()

    def getPktSent(self):
        with self.lock:
            return self.pktSent

    # https://mavlink.io/en/messages/common.html#STATUSTEXT
    def send_msg_to_gcs(self, text_to_be_sent):
        # MAV_SEVERITY: 0=EMERGENCY 1=ALERT 2=CRITICAL 3=ERROR, 4=WARNING, 5=NOTICE, 6=INFO, 7=DEBUG, 8=ENUM_END
        text_msg = 'AprilMAV: ' + text_to_be_sent
        self.conn.mav.statustext_send(
            mavutil.mavlink.MAV_SEVERITY_INFO, text_msg.encode())

    # Send a mavlink SET_GPS_GLOBAL_ORIGIN message (http://mavlink.org/messages/common#SET_GPS_GLOBAL_ORIGIN), for the EKF origin

    def set_default_global_origin(self):
        current_time_us = int(round(time.time() * 1000000))
        self.conn.mav.set_gps_global_origin_send(self.target_system,
                                                 int(self.origin_lat*1.0e7),
                                                 int(self.origin_lon*1.0e7),
                                                 int(self.origin_alt*1.0e3),
                                                 current_time_us)

    def sendPos(self):
        # Send a vision pos estimate
        # https://mavlink.io/en/messages/common.html#VISION_POSITION_ESTIMATE
        # if self.getTimestamp() > 0:
        if self.goodToSend:
            current_time_us = int(round(time.time() * 1000000))
            # estimate error - approx 0.01m in pos and 0.5deg in angle
            cov_pose = 0.01
            cov_twist = 0.5
            covariance = numpy.array([cov_pose, 0, 0, 0, 0, 0,
                                      cov_pose, 0, 0, 0, 0,
                                      cov_pose, 0, 0, 0,
                                      cov_twist, 0, 0,
                                      cov_twist, 0,
                                      cov_twist])
            with self.lock:
                self.conn.mav.vision_position_estimate_send(
                    current_time_us, self.pos[0], self.pos[1], self.pos[2], self.rot[0], self.rot[1], self.rot[2], covariance, reset_counter=self.reset_counter)
                self.pktSent += 1

    def sendSpeed(self):
        # Send a vision speed estimate
        # https://mavlink.io/en/messages/common.html#VISION_SPEED_ESTIMATE
        if self.goodToSend:
            current_time_us = int(round(time.time() * 1000000))
            # estimate error - approx 0.05m/s in pos
            cov_pose = 0.05
            covariance = numpy.array([cov_pose, 0, 0,
                                      0, cov_pose, 0,
                                      0, 0, cov_pose])
            with self.lock:
                self.conn.mav.vision_speed_estimate_send(
                    current_time_us, self.speed[0], self.speed[1], self.speed[2], covariance, reset_counter=self.reset_counter)
                self.pktSent += 1

    def sendPosDelta(self):
        # Send a vision pos delta
        # https://mavlink.io/en/messages/ardupilotmega.html#VISION_POSITION_DELTA
        if self.goodToSend:
            with self.lock:
                current_time_us = int(round(time.time() * 1000000))
                delta_time_us = current_time_us - self.time
                current_confidence_level = 80

                # Send the message
                self.conn.mav.vision_position_delta_send(
                    current_time_us,    # us: Timestamp (UNIX time or time since system boot)
                    delta_time_us,	    # us: Time since last reported camera frame
                    self.rotDelta,    # float[3] in radian: Defines a rotation vector in body frame that rotates the vehicle from the previous to the current orientation
                    self.posDelta,   # float[3] in m: Change in position from previous to current frame rotated into body frame (0=forward, 1=right, 2=down)
                    current_confidence_level # Normalized confidence value from 0 to 100.
                )
                self.pktSent += 1

#python argument for AprilTags, we will modify the "tagsize" to 96mm (size of our printed tags), "camera" to GenericUSB camera, and "video" to enable camera output
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("--tagSize", type=int, default=96,
                        help="Apriltag size in mm")
    parser.add_argument("--camera", type=str, default="GenericUSB",
                        help="Camera profile in camera.yaml")
    parser.add_argument("--maxerror", type=int, default=400,
                        help="Maximum pose error to use, in n*E-8 units")
    parser.add_argument("--outfile", type=str, default="geo_test_results.csv",
                        help="Output tag data to this file")
    parser.add_argument(
        "--device", type=str, default="udpin:127.0.0.1:14550", help="MAVLink connection string")
    parser.add_argument("--baud", type=int, default=115200,
                        help="MAVLink baud rate, if using serial")
    parser.add_argument("--source-system", type=int,
                        default=1, help="MAVLink Source system")
    parser.add_argument("--imageFolder", type=str, default="",
                        help="Save processed images to this folder")
    parser.add_argument("--video", type=int, default=1,
                        help="Output video to port, 0 to disable")
    parser.add_argument("--decimation", type=int,
                        default=2, help="Apriltag decimation")
    args = parser.parse_args()

    print("Initialising")

    # Open camera settings/
    with open('camera.yaml', 'r') as stream:
        parameters = yaml.load(stream, Loader=yaml.FullLoader)
    camParams = parameters[args.camera]

    # initialize the camera
    camera = None
    try:
        print(parameters[args.camera]['cam_name'])
        mod = import_module("lib." + parameters[args.camera]['cam_name'])
        camera = mod.camera(parameters[args.camera])
    except (ImportError, KeyError):
        print('No camera with the name {0}, exiting'.format(args.camera))
        sys.exit(0)

    # allow the camera to warmup
    time.sleep(2)

    at_detector = Detector(searchpath=['apriltags3py/apriltags/lib', 'apriltags3py/apriltags/lib'],
                           families='tagStandard41h12',
                           nthreads=4,
                           quad_decimate=args.decimation,
                           quad_sigma=0.4,
                           refine_edges=1,
                           decode_sharpening=1,
                           debug=0)

    # All tags live in here
    tagPlacement = tagDB(False)

    outfile = open(args.outfile, "w+")
    # left, up, fwd, pitch, yaw, roll
    outfile.write("{0},{1},{2},{3},{4},{5},{6}\n".format(
        "Filename", "PosX (m)", "PosY (m)", "PosZ (m)", "RotX (rad)", "RotY (rad)", "RotZ (rad)"))

    # Need to reconstruct K and D if using fisheye lens (not used in this project)
    if camParams['fisheye']:
        K = numpy.zeros((3, 3))
        D = numpy.zeros((4, 1))
        K[0, 0] = camParams['cam_params'][0]
        K[1, 1] = camParams['cam_params'][1]
        K[0, 2] = camParams['cam_params'][2]
        K[1, 2] = camParams['cam_params'][3]
        K[2, 2] = 1
        D[0][0] = camParams['cam_paramsD'][0]
        D[1][0] = camParams['cam_paramsD'][1]
        D[2][0] = camParams['cam_paramsD'][2]
        D[3][0] = camParams['cam_paramsD'][3]

        dim1 = None

    signal.signal(signal.SIGINT, signal_handler)

    # Start MAVLink comms thread
    threadMavlink = mavThread(args.device, args.baud, args.source_system)
    threadMavlink.start()

    # Start Status thread
    threadStatus = statusThread()
    threadStatus.start()

    # Start save image thread, if desired
    threadSave = None
    if args.imageFolder != "":
        threadSave = saveThread(args.imageFolder, exit_event)
        threadSave.start()

    # video stream out, if desired
    threadVideo = None
    if args.video != 0:
        threadVideo = videoThread(args.video, exit_event)
        threadVideo.start()

    i = 0
    while True:
        # print("--------------------------------------")

        myStart = time.time()

        # grab an image (and timestamp in usec) from the camera
        # estimate 50usec from timestamp to frame capture on next line
        timestamp = int(round(time.time() * 1000000)) + 50
        file = camera.getFileName()
        #print("Timestamp of capture = {0}".format(timestamp))
        imageBW = camera.getImage()
        i += 1

        # we're out of images
        if imageBW is None:
            break

        # AprilDetect, after accounting for distortion (if fisheye)
        if camParams['fisheye'] and dim1 is None:
            # Only need to get mapping at first frame
            # dim1 is the dimension of input image to un-distort
            dim1 = imageBW.shape[:2][::-1]
            map1, map2 = cv2.fisheye.initUndistortRectifyMap(
                K, D, numpy.eye(3), K, dim1, cv2.CV_16SC2)
        if camParams['fisheye']:
            imageBW = cv2.remap(
                imageBW, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
            #tags = at_detector.detect(undistorted_img, True, camParams['cam_params'], args.tagSize/1000)
        # else:
        tags = at_detector.detect(
            imageBW, True, camParams['cam_params'], args.tagSize/1000)

        # add any new tags to database, or existing one to duplicates
        tagsused = 0
        for tag in tags:
            if tag.pose_err < args.maxerror*1e-8:
                tagsused += 1
                tagPlacement.addTag(tag)

        tagPlacement.getBestTransform()

        if file:
            print("File: {0}".format(file))

        # get current location and rotation state of vehicle in ArduPilot NED format (rel camera)
        (posD, rotD) = tagPlacement.getArduPilotNED()
        (posR, rotR) = tagPlacement.getArduPilotNED(radians=True)
        (posRDelta, rotRDelta) = tagPlacement.getArduPilotNEDDelta(radians=True)

        outfile.write("{0},{1:.3f},{2:.3f},{3:.3f},{4:.1f},{5:.1f},{6:.1f}\n".format(
            file, posR[0], posR[1], posR[2], rotR[0], rotR[1], rotR[2]))

        #print("Time to capture, detect and localise = {0:.3f} sec, using {2}/{1} tags".format(time.time() - myStart, len(tags), len(tagPlacement.tagDuplicatesT)))

        # Create and send MAVLink packet
        threadMavlink.updateData(posR, rotR, timestamp, posRDelta, rotRDelta)
        #wasSent = threadMavlink.sendPos(posR[0], posR[1], posR[2], rotR[0], rotR[1], rotR[2], timestamp)

        # Send to status thread
        threadStatus.updateData(time.time(
        ) - myStart, (posD[0], posD[1], posD[2]), (rotD[0], rotD[1], rotD[2]), threadMavlink.getPktSent())

        # Send to save thread
        if threadSave:
            threadSave.save_queue.put((imageBW, os.path.join(
                ".", args.imageFolder, "processed_{:04d}.jpg".format(i)), posD, rotD, tags))

        # Get ready for next frame
        tagPlacement.newFrame()

        # Send to video stream, if option
        if threadVideo:
            threadVideo.frame_queue.put((imageBW, posD, rotD, tags))

        if exit_event.is_set():
            break

Main

C/C++
This is the code that controls the robot
//#############################################################################
// FILE:   LABstarter_main.c
//
// TITLE:  Lab Starter
//#############################################################################

// Included Files
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include "F28x_Project.h"
#include "driverlib.h"
#include "device.h"
#include "F28379dSerial.h"
#include "LEDPatterns.h"
#include "song.h"
#include "dsp.h"
#include "fpu32/fpu_rfft.h"
#include "control.h" // this is what I will put my functions in I guess
#include "MatrixMath.h"

#define PI          3.1415926535897932384626433832795
#define TWOPI       6.283185307179586476925286766559
#define HALFPI      1.5707963267948966192313216916398
// The Launchpad's CPU Frequency set to 200 you should not change this value
#define LAUNCHPAD_CPU_FREQUENCY 200

extern float cx;
extern float cy;
extern float cbearing;

// Interrupt Service Routines predefinition
__interrupt void cpu_timer0_isr(void);
__interrupt void cpu_timer1_isr(void);
__interrupt void cpu_timer2_isr(void);
__interrupt void SWI_isr(void);
__interrupt void SPIB_isr(void); //initialize interrupt function for lab 5

// Count variables
uint32_t numTimer0calls = 0;
uint32_t numSWIcalls = 0;
extern uint32_t numRXA;
uint16_t UARTPrint = 0;
uint16_t LEDdisplaynum = 0;

//initialize variables for lab 5
int count_up = 1; // "boolean" which indicates whether we're increasing (1) or decreasing (0). Start by increasing for exercise 3
uint16_t PWM_val = 0; //init our pwm
int16_t spivalue1 = 0; //raw spi values
int16_t spivalue2 = 0; // raw spi
int16_t spivalue3 = 0; //raw spi
float spival1_volt = 0.0; //spi values converted to voltage
float spival2_volt = 0.0;// voltage
float spival3_volt = 0.0;//voltage
int16_t dummy= 0; //temp value for storing spirxbus's first val
int16_t accelXraw = 0;// raw IMU data
int16_t accelYraw = 0;// raw IMU data
int16_t accelZraw = 0;// raw IMU data
int16_t gyroXraw = 0; //Raw gyroscope data from IMU
int16_t gyroYraw = 0;//Raw gyroscope data from IMU
int16_t gyroZraw = 0;//Raw gyroscope data from IMU
float accelXreading = 0.0;// Raw accel converted to float
float accelYreading = 0;// Raw accel converted to float
float accelZreading = 0;// Raw accel converted to float
float gyroXreading = 0;// Raw gyro converted to float
float gyroYreading = 0;// Raw gyro converted to float
float gyroZreading = 0;// Raw gyro converted to float
int16_t temp = 0;// temp value

//initialize variables for lab 6
float LeftWheel = 0.0; //left wheel angle
float RightWheel = 0.0; // right wheel angle
float PosLeft_k = 0.0; // total distance the left wheel has traveled
float PosRight_k = 0.0; // total distance the right wheel has traveled
float uLeft = 0.0; // velocity of the left wheel
float uRight = 0.0; // velocity of the right wheel
float PosLeft_k_1 = 0.0; //previous position of the left wheel
float PosRight_k_1 = 0.0; // previous pos of the right wheel
float VLeftK = 0.0; // gain of the left wheel
float VRightK = 0.0; // gain of the right wheel
uint16_t TBPRD_val = 2500; //setting the period of the PWM signal here for exercises 1 2 and 4 - we will not change this but it is nice to have set. Set to 2500 bc of 20kHz (and no divide)
float Kp = .5; //proportional constant for controller
float Ki = 1.0; //interral constant for controller
float Vref = 0.0; // reference speed
float ILeft_k = 0.0;
float IRight_k = 0.0;
float ILeft_k_1 = 0.0;
float IRight_k_1 = 0.0;
float eLeft_k = 0.0;
float eRight_k = 0.0;
float eLeft_k_1 = 0.0;
float eRight_k_1 = 0.0;
//uint16_t satL = 0;
//uint16_t satR = 0;
float Kturn = 3.0;
//float eturn = 0.0;
//float turn = 0.0; // value to set the turn
float globalx = 0.0; // dead reckoning x coordinate in ft
float globaly = 0.0; // dead reckoning y coordinate in ft
float bearing = 0.0; // dead reckoning bearing angle in rad
float bearing_k_1 = 0.0; // added when matt fucked with shit
float LeftWheel_k_1 = 0.0;
float RightWheel_k_1 = 0.0;
float xdot_k_1 = 0.0;
float ydot_k_1 = 0.0;
float xdot = 0.0;
float ydot = 0.0;
float wLeftK = 0.0;
float wRightK = 0.0;
float theta_avg_k = 0.0;
float omega_avg_k = 0.0;
extern int ready;

extern float cur_x_e;
extern float cur_y_e;
extern float cur_bearing_e;
extern float cur_vel_x_e;
extern float cur_vel_y_e;
extern float cur_omega_in_e;
extern int last_line_index;
//extern uint16_t TBPRD_val; //setting the period of the PWM signal here for exercises 1 2 and 4 - we will not change this but it is nice to have set. Set to 2500 bc of 20kHz (and no divide)

float eturn=0;
float turn=0;
float eturn_I=0;
float vel_right=0;
float vel_left=0;
float eturn_I_1=0;
float zero_x=0;
float zero_y=0;
float shift_pos_x=0;
float shift_pos_y=0;
float shift_line_x2=0;
float shift_line_y2=0;
float ux=0;
float uy=0;
float top=0;
float bottom=0;
float proj_x=0;
float proj_y=0;
float comp_x=0;
float comp_y=0;
float slope_line=0;
float slope=0;
float slope_robot_line=0;
float eturn_d=0;
float omega=0;
float eturn_1=0;
//float k_turn_I = .5;// this will need to be tuned to damp the system
//float k_turn_p = .2; // tune for pid;
float eturn_p=0;
float k_turn_d = 0; // tune for the d
int satR=0;
int satL=0;
float finalx_1 = 0.0;
float finaly_1 = 0.0;
float finalbearing_1 = 0.0;
float velocity_x = 0.0;
float velocity_y = 0.0;
float omega_final = 0.0;

// initialize variables for 3D Kalman Filter
float F[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; // state transition model
float B[3][2] = {{1,0},{1,0},{0,1}}; // control input model
#define ProcUncert 0.0001
#define CovScalar 10
float Q[3][3] = {{ProcUncert,0,ProcUncert/CovScalar},
                 {0,ProcUncert,ProcUncert/CovScalar},
                 {ProcUncert/CovScalar,ProcUncert/CovScalar,ProcUncert}}; // process noise (covariance of encoders and gyro)
float H[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; // observation model
#define MeasUncert 1
float R[3][3] = {{MeasUncert,0,MeasUncert/CovScalar},
                 {0,MeasUncert,MeasUncert/CovScalar},
                 {MeasUncert/CovScalar,MeasUncert/CovScalar,MeasUncert}}; // measurement noise (covariance of april tags)
float S[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; // innovation covariance
float S_inv[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; // innovation covariance matrix inverse
float K[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; // optimal Kalman gain
float x_pred[3][1] = {{0},{0},{0}}; // predicted state
float P_pred[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; // predicted covariance (measure of estimated variance of the state)
float u[2][1] = {{0},{0}}; // control input in terms of velocity and angular velocity
float Bu[3][1] = {{0},{0},{0}}; // matrix multiplication of B and u
float temp_3x3[3][3]; // intermediate storage
float temp_3x1[3][1]; // intermediate storage
float ytilde[3][1]; // difference between predictions
float z[3][1]; // state measurement
float eye3[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; // 3x3 identity matrix
float apriltag = 0; // flag for when data is recieved from the april tag system
float finalx = 0; // x coordinate generated from kalman filter in ft
float finaly = 0; // y coordinate generated from kalman filter in ft
float finalbearing = 0; // bearing angle generated from kalman filter in rad

void setupSpib(void); // initialize function for exercise 4
void init_eQEPs(void); // initialize functions for lab 6
float readEncLeft(void);
float readEncRight(void);
//void setEPWM2A(float controleffort);
//void setEPWM2B(float controleffort);
void aim2(float bearing_target, float distance);
int working = 0; // just to see whats happening
float x_2 = 0;
float y_2 = 0;
float xarray[100]; // recall size is 500 by 500 so to scale divide by 500 pixels and mult by size of paper in inches
float yarray[100];
float xarray_i[100];
float yarray_i[100];
int line_index = 0;
float last_line_index_float = 0;
int index_of_last_value = 24;



void main(void)
{
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xD_SysCtrl.c file.
    InitSysCtrl();
    ready = 0;
    xarray[0] = 0;
    yarray[0] = 0;
    last_line_index = index_of_last_value;
    gen_line(xarray_i[0],yarray_i[0]);
    update_pos(0,0,0,0,0,0);


    InitGpio();

    // Blue LED on LaunchPad
    GPIO_SetupPinMux(31, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(31, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPASET.bit.GPIO31 = 1;

    // Red LED on LaunchPad
    GPIO_SetupPinMux(34, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(34, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPBSET.bit.GPIO34 = 1;

    // LED1 and PWM Pin
    GPIO_SetupPinMux(22, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(22, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPACLEAR.bit.GPIO22 = 1;

    // LED2
    GPIO_SetupPinMux(94, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(94, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPCCLEAR.bit.GPIO94 = 1;

    // LED3
    GPIO_SetupPinMux(95, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(95, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPCCLEAR.bit.GPIO95 = 1;

    // LED4
    GPIO_SetupPinMux(97, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(97, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPDCLEAR.bit.GPIO97 = 1;

    // LED5
    GPIO_SetupPinMux(111, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(111, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPDCLEAR.bit.GPIO111 = 1;

    // LED6
    GPIO_SetupPinMux(130, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(130, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPECLEAR.bit.GPIO130 = 1;

    // LED7
    GPIO_SetupPinMux(131, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(131, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPECLEAR.bit.GPIO131 = 1;

    // LED8
    GPIO_SetupPinMux(25, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(25, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPACLEAR.bit.GPIO25 = 1;

    // LED9
    GPIO_SetupPinMux(26, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(26, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPACLEAR.bit.GPIO26 = 1;

    // LED10
    GPIO_SetupPinMux(27, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(27, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPACLEAR.bit.GPIO27 = 1;

    // LED11
    GPIO_SetupPinMux(60, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(60, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPBCLEAR.bit.GPIO60 = 1;

    // LED12
    GPIO_SetupPinMux(61, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(61, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPBCLEAR.bit.GPIO61 = 1;

    // LED13
    GPIO_SetupPinMux(157, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(157, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPECLEAR.bit.GPIO157 = 1;

    // LED14
    GPIO_SetupPinMux(158, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(158, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPECLEAR.bit.GPIO158 = 1;

    // LED15
    GPIO_SetupPinMux(159, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(159, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPECLEAR.bit.GPIO159 = 1;

    // LED16
    GPIO_SetupPinMux(160, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(160, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPFCLEAR.bit.GPIO160 = 1;

    //WIZNET Reset
    GPIO_SetupPinMux(0, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(0, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPASET.bit.GPIO0 = 1;

    //ESP8266 Reset
    GPIO_SetupPinMux(1, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(1, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPASET.bit.GPIO1 = 1;

    //SPIRAM  CS  Chip Select
    GPIO_SetupPinMux(19, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(19, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPASET.bit.GPIO19 = 1;

    //DRV8874 #1 DIR  Direction
    GPIO_SetupPinMux(29, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(29, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPASET.bit.GPIO29 = 1;

    //DRV8874 #2 DIR  Direction
    GPIO_SetupPinMux(32, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(32, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPBSET.bit.GPIO32 = 1;

    //DAN28027  CS  Chip Select pin
    GPIO_SetupPinMux(9, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(9, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPASET.bit.GPIO9 = 1;

    //MPU9250  CS  Chip Select
    GPIO_SetupPinMux(66, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(66, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPCSET.bit.GPIO66 = 1;

    //WIZNET  CS  Chip Select
    GPIO_SetupPinMux(125, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(125, GPIO_OUTPUT, GPIO_PUSHPULL);
    GpioDataRegs.GPDSET.bit.GPIO125 = 1;

    //PushButton 1
    GPIO_SetupPinMux(4, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(4, GPIO_INPUT, GPIO_PULLUP);

    //PushButton 2
    GPIO_SetupPinMux(5, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(5, GPIO_INPUT, GPIO_PULLUP);

    //PushButton 3
    GPIO_SetupPinMux(6, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(6, GPIO_INPUT, GPIO_PULLUP);

    //PushButton 4
    GPIO_SetupPinMux(7, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(7, GPIO_INPUT, GPIO_PULLUP);

    //Joy Stick Pushbutton
    GPIO_SetupPinMux(8, GPIO_MUX_CPU1, 0);
    GPIO_SetupPinOptions(8, GPIO_INPUT, GPIO_PULLUP);

    // Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    DINT;

    // Initialize the PIE control registers to their default state.
    // The default state is all PIE interrupts disabled and flags
    // are cleared.
    // This function is found in the F2837xD_PieCtrl.c file.
    InitPieCtrl();

    // Disable CPU interrupts and clear all CPU interrupt flags:
    IER = 0x0000;
    IFR = 0x0000;

    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2837xD_DefaultIsr.c.
    // This function is found in F2837xD_PieVect.c.
    InitPieVectTable();

    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this project
    EALLOW;  // This is needed to write to EALLOW protected registers
    PieVectTable.TIMER0_INT = &cpu_timer0_isr;
    PieVectTable.TIMER1_INT = &cpu_timer1_isr;
    PieVectTable.TIMER2_INT = &cpu_timer2_isr;
    PieVectTable.SCIA_RX_INT = &RXAINT_recv_ready;
    PieVectTable.SCIB_RX_INT = &RXBINT_recv_ready;
    PieVectTable.SCIC_RX_INT = &RXCINT_recv_ready;
    PieVectTable.SCID_RX_INT = &RXDINT_recv_ready;
    PieVectTable.SCIA_TX_INT = &TXAINT_data_sent;
    PieVectTable.SCIB_TX_INT = &TXBINT_data_sent;
    PieVectTable.SCIC_TX_INT = &TXCINT_data_sent;
    PieVectTable.SCID_TX_INT = &TXDINT_data_sent;

    PieVectTable.SPIB_RX_INT = &SPIB_isr;

    PieVectTable.EMIF_ERROR_INT = &SWI_isr;
    EDIS;    // This is needed to disable write to EALLOW protected registers


    // Initialize the CpuTimers Device Peripheral. This function can be
    // found in F2837xD_CpuTimers.c
    InitCpuTimers();

    // Configure CPU-Timer 0, 1, and 2 to interrupt every given period:
    // 200MHz CPU Freq,                       Period (in uSeconds)
    //ConfigCpuTimer(&CpuTimer0, LAUNCHPAD_CPU_FREQUENCY, 10000);// set to ever 10 ms for exercise 2
    //ConfigCpuTimer(&CpuTimer0, LAUNCHPAD_CPU_FREQUENCY, 20000);// set to ever 20 ms for exercise 3
    ConfigCpuTimer(&CpuTimer0, LAUNCHPAD_CPU_FREQUENCY, 1000);// set to ever 1 ms for exercise 4
    ConfigCpuTimer(&CpuTimer1, LAUNCHPAD_CPU_FREQUENCY, 4000); // run every 4 ms for lab 6 exercise 1
    ConfigCpuTimer(&CpuTimer2, LAUNCHPAD_CPU_FREQUENCY, 4000); //prints every 50 times, so 5 times a second

    // Enable CpuTimer Interrupt bit TIE
    CpuTimer0Regs.TCR.all = 0x4000;
    CpuTimer1Regs.TCR.all = 0x4000;
    CpuTimer2Regs.TCR.all = 0x4000;

    
    GPIO_SetupPinMux(2, GPIO_MUX_CPU1, 1); //set EPWM2A instead of GPIO2 EXERCISE 2: robot motors
    GPIO_SetupPinMux(3, GPIO_MUX_CPU1, 1); //set EPWM2B instead of GPIO3 EXERCISE 2: robot motors
    GPIO_SetupPinMux(14, GPIO_MUX_CPU1, 1); //set EPWM8A instead of GPIO14 EXERCISE 3: RC motors
    GPIO_SetupPinMux(15, GPIO_MUX_CPU1, 1); //set EPWM8B instead of GPIO15 EXERCISE 3: RC motors
    
    //copied from lab 3 for lab 6
    GPIO_SetupPinMux(2, GPIO_MUX_CPU1, 1); //set EPWM2A instead of GPIO2 EXERCISE 2: robot motors
    GPIO_SetupPinMux(3, GPIO_MUX_CPU1, 1); //set EPWM2B instead of GPIO3 EXERCISE 2: robot motors
    GpioCtrlRegs.GPAPUD.bit.GPIO14 = 1; // For EPWM8A
    GpioCtrlRegs.GPAPUD.bit.GPIO15 = 1; // For EPWM8B
    
    
    //init pwm 2A and 2B for robot motor (exercise 2)
    EPwm2Regs.TBCTL.bit.CTRMODE = 0; //TBCTL Count up mode
    EPwm2Regs.TBCTL.bit.FREE_SOFT = 2; // TBCTL Free Soft emulation mode
    EPwm2Regs.TBCTL.bit.PHSEN = 0; // TBCTL disable phase loading
    EPwm2Regs.TBCTL.bit.CLKDIV = 0; // TBCTL clock divide by 1
    EPwm2Regs.TBCTR = 0; // TBCTR start timer at 0
    EPwm2Regs.TBPRD = TBPRD_val; // set period to the value specified by the global variable at the top
    EPwm2Regs.CMPA.bit.CMPA = TBPRD_val/2; //start duty cycle at 50%
    EPwm2Regs.AQCTLA.bit.CAU = 1; // signal pin clear (low) when TBCTR = CMPA
    EPwm2Regs.AQCTLA.bit.ZRO = 2; // signal pin set high when TBCTR = 0
    EPwm2Regs.TBPHS.bit.TBPHS = 0; // set TBPHS to 0 (phase offset) to be safe
    //init for just PWM 2B
    EPwm2Regs.CMPB.bit.CMPB = TBPRD_val/2; //start duty cycle at 50%
    EPwm2Regs.AQCTLB.bit.CBU = 1; // signal pin clear (low) when TBCTR = CMPA
    EPwm2Regs.AQCTLB.bit.ZRO = 2; // signal pin set high when TBCTR = 0
    
    
    
    EPwm8Regs.TBCTL.bit.CTRMODE = 0; //TBCTL Count up mode
    EPwm8Regs.TBCTL.bit.FREE_SOFT = 2; // TBCTL Free Soft emulation mode
    EPwm8Regs.TBCTL.bit.PHSEN = 0; // TBCTL disable phase loading
    EPwm8Regs.TBCTL.bit.CLKDIV = 4; // TBCTL clock divide by 16
    EPwm8Regs.TBCTR = 0; // TBCTR start timer at 0
    EPwm8Regs.TBPRD = 62500; // set period using 50 Hz and clock divide by 16
    EPwm8Regs.CMPA.bit.CMPA = 5000; //start duty cycle at 8% (TBPRD * .08)
    EPwm8Regs.AQCTLA.bit.CAU = 1; // signal pin clear (low) when TBCTR = CMPA
    EPwm8Regs.AQCTLA.bit.ZRO = 2; // signal pin set high when TBCTR = 0
    EPwm8Regs.TBPHS.bit.TBPHS = 0;  // set TBPHS to 0 (phase offset) to be safe
    //init for just PWM 8B
    EPwm8Regs.CMPB.bit.CMPB = 5000; //start duty cycle at 8%
    EPwm8Regs.AQCTLB.bit.CBU = 1; // signal pin clear (low) when TBCTR = CMPA
    EPwm8Regs.AQCTLB.bit.ZRO = 2; // signal pin set high when TBCTR = 0
    
    

    init_serialSCIA(&SerialA,115200);
    //    init_serialSCIB(&SerialB,115200);
    //    init_serialSCIC(&SerialC,115200);
    init_serialSCID(&SerialD,115200);

    //BEGIN LAB 5: insert code from lab manual - then cut and paste into below function
    setupSpib(); //run function before interrupts are enabled and after init_serialSCIA

    //LAB 6:
    init_eQEPs();

    // Enable CPU int1 which is connected to CPU-Timer 0, CPU int13
    // which is connected to CPU-Timer 1, and CPU int 14, which is connected
    // to CPU-Timer 2:  int 12 is for the SWI.
    IER |= M_INT1;
    IER |= M_INT8;  // SCIC SCID
    IER |= M_INT9;  // SCIA
    IER |= M_INT12;
    IER |= M_INT13;
    IER |= M_INT14;
    IER |= M_INT6; //for lab 5 exercise 2

    // Enable TINT0 in the PIE: Group 1 interrupt 7
    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
    // Enable SWI in the PIE: Group 12 interrupt 9
    PieCtrlRegs.PIEIER12.bit.INTx9 = 1;
    //for lab 5 exercise 2
    // Enable SWI in the PIE: Group 6 interrupt 3
    PieCtrlRegs.PIEIER6.bit.INTx3 = 1;

    // Enable global Interrupts and higher priority real-time debug events
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM


    // to set the last line index


    //PRint line ---------------------------------------------------------------------------------------------------------------
    // IDLE loop. Just sit and loop forever (optional):
    while(1)
    {
        if (UARTPrint == 1 ) {
                //serial_printf(&SerialA,"ADC values 1(should be 0):%.3fV 2: %.3fV 3:%.3fV\r\n",spival1_volt, spival2_volt, spival3_volt);
            //serial_printf(&SerialA,"accelx:%.3f accely:%.3f accelz:%.3f gyrox:%.3f gyroy:%.3f gyroz:%.3f \r\n",accelXreading, accelYreading, accelZreading, gyroXreading, gyroYreading, gyroZreading);
            //serial_printf(&SerialA, "Left Wheel (rad):%.3f Right Wheel (rad):%.3f Left Wheel (ft):%.3f Right Wheel (ft):%.3f\r\n", LeftWheel, RightWheel, PosLeft_k, PosRight_k); // for lab 6 exercise 1
            //serial_printf(&SerialA, "Left Speed (ft/s):%.3f Right Speed (ft/s):%.3f \r\n", VLeftK, VRightK); // for lab 6 exercise 2
            //serial_printf(&SerialA, "globax x coord: %.3f global y coord: %.3f \r\n", globalx, globaly);//lab 6 excersize 5
            //serial_printf(&SerialA, "cx = %.3f cy = %.3f\r\n", cx, cy);//lab 6 excersize 5
            serial_printf(&SerialA, "system is running");
            UARTPrint = 0;
        }
    }
}


// SWI_isr,  Using this interrupt as a Software started interrupt
__interrupt void SWI_isr(void) {

    // These three lines of code allow SWI_isr, to be interrupted by other interrupt functions
    // making it lower priority than all other Hardware interrupts.
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP12;
    asm("       NOP");                    // Wait one cycle
    EINT;                                 // Clear INTM to enable interrupts



    // Insert SWI ISR Code here.......


    numSWIcalls++;
    
    DINT;

}

// cpu_timer0_isr - CPU Timer0 ISR
__interrupt void cpu_timer0_isr(void)
{
    CpuTimer0.InterruptCount++;

    numTimer0calls++;

//    if ((numTimer0calls%50) == 0) {
//        PieCtrlRegs.PIEIFR12.bit.INTx9 = 1;  // Manually cause the interrupt for the SWI
//    }

    if ((numTimer0calls%250) == 0) {
        displayLEDletter(LEDdisplaynum);
        LEDdisplaynum++;
        if (LEDdisplaynum == 0xFFFF) {  // prevent roll over exception
            LEDdisplaynum = 0;
        }
    }


    // Blink LaunchPad Red LED
    GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;

    // Acknowledge this interrupt to receive more interrupts from group 1
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    //Clear GPIO9 Low to act as a Slave Select. Right now, just to scope. Later to select DAN28027 chip
    //GpioDataRegs.GPFCLEAR.bit.GPIO160 = 1;
//    GpioDataRegs.GPACLEAR.bit.GPIO9 = 1;//setting gpio9 to be 0 //this is for slave select - recall active low
    //SpibRegs.SPIFFRX.bit.RXFFIL = 2; // Issue the SPIB_RX_INT when two values are in the RX FIFO for exercise 2
//    SpibRegs.SPIFFRX.bit.RXFFIL = 3; // Issue the SPIB_RX_INT when three values are in the RX FIFO for exercise 3


    //lab 5 exercise 3
    if (PWM_val >= 3000) { //if PWM_val is equal to 3000 (max)...
        count_up = 0; //... start counting down
    } else if(PWM_val <= 0) { //if PWM_val is equal to 0...
        count_up = 1; // ... start counting up
    }
    if (count_up){
        PWM_val+=10;//increase the PWM_val if we are counting up
    } else {
        PWM_val-=10; //decrease the PWM_val if we are counting down
    }
    //SpibRegs.SPITXBUF = 0x00DA; // send initial start command
    //SpibRegs.SPITXBUF = PWM_val; // send PWM_val
    //SpibRegs.SPITXBUF = PWM_val; // send again

    //lab 5 exercise 4
//    SpibRegs.SPICCR.bit.SPICHAR = 0xF;
    GpioDataRegs.GPCCLEAR.bit.GPIO66 = 1; // pulled low
    SpibRegs.SPIFFRX.bit.RXFFIL = 8; // Issue the SPIB_RX_INT when 7 values are in the RX FIFO
    SpibRegs.SPITXBUF = ((0x8000) | (0x3A00)); // making the bits 10111010000000 by making the top bit 1 check documentation for exact setup
    SpibRegs.SPITXBUF = 0;// setting these to 0 for start
    SpibRegs.SPITXBUF = 0;
    SpibRegs.SPITXBUF = 0;
    SpibRegs.SPITXBUF = 0;
    SpibRegs.SPITXBUF = 0;
    SpibRegs.SPITXBUF = 0;
    SpibRegs.SPITXBUF = 0;
/*
    while(SpibRegs.SPIFFRX.bit.RXFFST !=8); // wait for the correct number of 16 bit values to be received into the RX FIFO
    GpioDataRegs.GPCSET.bit.GPIO66 = 1; // Slave Select High
    temp = SpibRegs.SPIRXBUF; // read the additional number of garbage receive values off the RX FIFO to clear out the RX FIFO
    temp = SpibRegs.SPIRXBUF; //read and discard
    temp = SpibRegs.SPIRXBUF;//read and discard
    temp = SpibRegs.SPIRXBUF;//read and discard
    temp = SpibRegs.SPIRXBUF;//read and discard
    temp = SpibRegs.SPIRXBUF;//read and discard
    temp = SpibRegs.SPIRXBUF;//read
    DELAY_US(10); // Delay 10us to allow time for the MPU-2950 to get ready for next transfer. */
}

// cpu_timer1_isr - CPU Timer1 ISR
__interrupt void cpu_timer1_isr(void)
{ 
    LeftWheel = readEncLeft();// sets left wheel distance (technically total amt of angle change)
    RightWheel = readEncRight(); // sets left wheel distance (technically total amt of angle change)
    wLeftK = (LeftWheel- LeftWheel_k_1) / 0.004; // calculates velocity based on time difference and previous position
    wRightK = (RightWheel - RightWheel_k_1) / 0.004; // same here but right

    PosLeft_k = LeftWheel / 5.128; //converts from rad to ft
    PosRight_k = RightWheel / 5.128; // doing it again


    bearing = .1946/.56759*(RightWheel - LeftWheel); // this finds the "compass" direction. but it is really just the angle change since beginning
    theta_avg_k = .5*(RightWheel + LeftWheel); // finds the average distance of the robot
    omega_avg_k = .5*(wRightK + wLeftK); // finds the avg velocity of the robot
    xdot = .19460*omega_avg_k*cos(bearing); // finds the x velocity of the robot
    ydot = .19460*omega_avg_k*sin(bearing); // finds the y velocity of the robot

    globalx = globalx + .004*(xdot+xdot_k_1)/2; // this is global x coordinate with starting pos as 0
    globaly = globaly + .004*(ydot+ydot_k_1)/2; // global y coordinate with starting pos as 0

    VLeftK = (PosLeft_k - PosLeft_k_1) / 0.004; // calculates velocity of the left wheel based on time difference and previous position
    VRightK = (PosRight_k - PosRight_k_1) / 0.004; // calculates the velocity of the right wheel based on time difference and previous position
    omega = (bearing - bearing_k_1)/0.004; // calculates the angular velocity of the the bearing angle based on time difference and previous angle
    velocity_x = (finalx - finalx_1)/.004;
    velocity_y= (finalx - finalx_1)/.004;
    omega_final = (finalbearing - finalbearing_1)/.004;
    
    // set these values
    cur_x_e = finalx; // sets the x coordinate used in the path generation function to the kalman filter results
    cur_y_e = finaly; // sets the y coordinate used in the path generation function to the kalman filter results
    cur_bearing_e = finalbearing; // sets the bearing angle used in the path generation function to the kalman filter results
    cur_vel_x_e = xdot; // sets the x velocity used in the path generation function to the kalman filter results
    cur_vel_y_e = ydot; // sets the y velocity used in the path generation function to the kalman filter results
    cur_omega_in_e = omega; //sets the angular velocity of the bearing angle used in the path generation function to the kalman filter results
    
  
    /*
    cur_x_e = globalx; // 
    cur_y_e = globaly; // 
    cur_bearing_e = bearing; // 
    cur_vel_x_e = xdot; // 
    cur_vel_y_e = ydot; // 
    cur_omega_in_e = omega; //
    */
  
    // Call the path generation function
    working = go();
    // if(!working & ready) {
    //    line_index = line_index + 1;
    //    x_2 = xarray_i[line_index];
    //    y_2 = yarray_i[line_index];
    //    gen_line(x_2, y_2); // neex x_2 to be the second point in the line and y_2 to be the first point
    //}

    PosLeft_k_1 = PosLeft_k;// all of the code in this section is setting the previous values of all of the needed values so we can integrate or derive
    PosRight_k_1 = PosRight_k;
    eLeft_k_1 = eLeft_k;
    eRight_k_1 = eRight_k;
    //ILeft_k_1 = ILeft_k;
    //IRight_k_1 = IRight_k;
    LeftWheel_k_1 = LeftWheel;
    RightWheel_k_1 = RightWheel;
    xdot_k_1 = xdot;
    ydot_k_1 = ydot;
    bearing_k_1 = bearing; // was addded when matt fucked with shit
    finalbearing_1 = finalbearing;
    finalx_1 = finalx;
    finaly_1 = finaly;

    CpuTimer1.InterruptCount++;
    /*
    CpuTimer1.InterruptCount++;

    PosLeft_k_1 = PosLeft_k;// all of the code in this section is setting the previous values of all of the needed values so we can integrate or derive
    PosRight_k_1 = PosRight_k;
    eLeft_k_1 = eLeft_k;
    eRight_k_1 = eRight_k;
    ILeft_k_1 = ILeft_k;
    IRight_k_1 = IRight_k;
    LeftWheel_k_1 = LeftWheel;
    RightWheel_k_1 = RightWheel;
    xdot_k_1 = xdot;
    ydot_k_1 = ydot;

    LeftWheel = readEncLeft();// sets left wheel distance (technically total amt of angle change)
    RightWheel = readEncRight(); // sets left wheel distance (technically total amt of angle change)
    wLeftK = (LeftWheel- LeftWheel_k_1) / 0.004; // calculates velocity based on time difference and previous position
    wRightK = (RightWheel - RightWheel_k_1) / 0.004; // same here but right

    PosLeft_k = LeftWheel / 5.128; //converts from rad to ft
    PosRight_k = RightWheel / 5.128; // doing it again


    bearing = .1946/.56759*(RightWheel - LeftWheel); // this finds the "compass" direction. but it is really just the angle change since beginning
    theta_avg_k = .5*(RightWheel + LeftWheel); // finds the average distance of the robot
    omega_avg_k = .5*(wRightK + wLeftK); // finds the avg velocity of the robot
    xdot = .19460*omega_avg_k*cos(bearing); // finds the x velocity of the robot
    ydot = .19460*omega_avg_k*sin(bearing); // finds the yvelocity of the robot

    globalx = globalx + .004*(xdot+xdot_k_1)/2; // this is global x coordinate with starting pos as 0
    globaly = globaly + .004*(ydot+ydot_k_1)/2; // global y coordinate with starting pos as 0

    VLeftK = (PosLeft_k - PosLeft_k_1) / 0.004; // calculates velocity based on time difference and previous position
    VRightK = (PosRight_k - PosRight_k_1) / 0.004;


    eturn = (VLeftK - VRightK) + turn; // error but the turn is to help with turning
    eLeft_k = Vref - VLeftK - Kturn*eturn; // error left
    eRight_k = Vref - VRightK + Kturn*eturn; // error right (to be used with pid)

    if (satR) {
        // don't run the else so that we stop summing no more integral windup
    } else {
        IRight_k = IRight_k_1 + 0.004 * (eRight_k + eRight_k_1) / 2; // integrate for PID
    }
    if (satL) {
        // dont run the else so that we stop summing
    } else {
        ILeft_k = ILeft_k_1 + 0.004 * (eLeft_k + eLeft_k_1) / 2; // integrate for PID
    }

    uLeft = Kp * eLeft_k + Ki * ILeft_k; // PI for left wheel
    uRight = Kp * eRight_k + Ki * IRight_k; // PI for right wheel

    if ((uRight < 10) & (uRight > -10)) { // this is code to make sure that we don't request too much
        satR = 0; // reset the satR
    }
    if ((uLeft < 10) & (uLeft > -10)) {
        satL = 0; // reset the satL
    }
*/


   // setEPWM2A(uRight); // finally we send the speed request
  //  setEPWM2B(-uLeft);


}

// cpu_timer2_isr CPU Timer2 ISR
__interrupt void cpu_timer2_isr(void)
{
    // import and convert the x and y point values from LabView and set the ready flag so that the path function moves the robot car
    for(int j =0; j < 100; j++) {
           xarray_i[j] = xarray[j]/500*3;
           yarray_i[j] = yarray[j]/500*3;
    } if (xarray[1] != 0.0 & yarray[1] != 0.0) {
    ready = 1;
    }

    // Blink LaunchPad Blue LED
    GpioDataRegs.GPATOGGLE.bit.GPIO31 = 1;

    CpuTimer2.InterruptCount++;

    if ((CpuTimer2.InterruptCount % 50) == 0) { // print the voltage every 50 times cpu_timer2_isr is run
        UARTPrint = 1;
    }
}

__interrupt void SPIB_isr(void){
    //spivalue1 = SpibRegs.SPIRXBUF; // Read first 16 bit value off RX FIFO. Probably is zero since no chip.
    //spivalue2 = SpibRegs.SPIRXBUF; // Read second 16 bit value off RX FIFO. Again probably zero for exercise 2.
    //spivalue3 = SpibRegs.SPIRXBUF; // Read third 16 bit value off RX FIFO. Added for exercise 3 (to read from DAN29027)
    //GpioDataRegs.GPASET.bit.GPIO9 = 1; // Set GPIO9 high to end Slave Select. Now Scope. Later to deselect DAN28027
    // Later when actually communicating with the DAN28027 do something with the data. Now do nothing.
    //spival1_volt = spivalue1 / 4095.0 * 3.3; //convert raw value to voltage values, this first one should be 0
    //spival2_volt = spivalue2 / 4095.0 * 3.3; //convert raw value to voltage values, this first one should be 0
    //spival3_volt = spivalue3 / 4095.0 * 3.3; //convert raw value to voltage values, this first one should be 0

    //SpibRegs.SPIFFRX.bit.RXFFOVFCLR = 1; // Clear Overflow flag just in case of an overflow
    //SpibRegs.SPIFFRX.bit.RXFFINTCLR = 1; // Clear RX FIFO Interrupt flag so next interrupt will happen
    //PieCtrlRegs.PIEACK.all = PIEACK_GROUP6; // Acknowledge INT6 PIE interrupt


    //exercise 4
    GpioDataRegs.GPCSET.bit.GPIO66 = 1; //set the bit high as a chip select
    dummy = SpibRegs.SPIRXBUF; // temp value for the first thing sent

    accelXraw = SpibRegs.SPIRXBUF;// these are signed lol but really just raw data
    accelYraw = SpibRegs.SPIRXBUF;
    accelZraw = SpibRegs.SPIRXBUF;

    accelXreading = accelXraw*4.0/32767.0; //converting to real value
    accelYreading = accelYraw*4.0/32767.0;
    accelZreading = accelZraw*4.0/32767.0;

    dummy = SpibRegs.SPIRXBUF; // temp

    gyroXraw = SpibRegs.SPIRXBUF;// these are signed lol but really just raw data
    gyroYraw = SpibRegs.SPIRXBUF;
    gyroZraw = SpibRegs.SPIRXBUF;

    gyroXreading = gyroXraw*250.0/32767.0;//converting to real value
    gyroYreading = gyroYraw*250.0/32767.0;
    gyroZreading = gyroZraw*250.0/32767.0;


    // 3D Kalman Filter Code
    // Import April Tag X, Y, Bearing Angle. We'll call them cx, cy, cbearing

    // Step 0: update B, u, and Q
    // Bu is the integration of the x, y, and bearing angle. When added to the current values they will be the predicted values for the next time step
    // x and y positions come from the optical encoder data
    // bearing angle is from the z gyro IMU reading
    B[0][0] = cosf(bearing)*0.001;
    B[1][0] = sinf(bearing)*0.001;
    B[2][1] = 0.001;
    u[0][0] = 0.5*(VLeftK + VRightK); // average velocity of left and right wheels
    u[1][0] = gyroZreading*PI/180; // rad/s

    // Step 1: predict the state and estimate covariance
    Matrix3x2_Mult(B, u, Bu); // Bu = B*u
    Matrix3x1_Add(x_pred, Bu, x_pred, 1.0, 1.0); // x_pred = x_pred(old) + Bu
    Matrix3x3_Add(P_pred, Q, P_pred, 1.0, 1.0); // P_pred = P_pred(old) + Q

    // Step 2: If data is sent from the april tag system, incorporate it into the Kalman filter values
    if (1 == apriltag) {
        apriltag = 0;
        // enter the april tag data into the z matrix to later compute error between the current predicted values
        z[0][0] = cx*3.28084; // converted from meters to ft
        z[1][0] = cy*3.28084; // converted from meters to ft
        z[2][0] = cbearing;
        // Step 2a: calculate the innovation/measurement residual, ytilde
        // this is the error between the measured values and the predicted values
        Matrix3x1_Add(z, x_pred, ytilde, 1.0, -1.0); // ytilde = z-x_pred
        // Step 2b: calculate innovation covariance, S
        Matrix3x3_Add(P_pred, R, S, 1.0, 1.0); // S = P_pred + R
        // Step 2c: calculate the optimal Kalman gain, K
        Matrix3x3_Invert(S, S_inv);
        Matrix3x3_Mult(P_pred, S_inv, K); // K = P_pred*(S^-1)
        // Step 2d: update the state estimate x_pred = x_pred(old) + K*ytilde
        Matrix3x1_Mult(K, ytilde, temp_3x1);
        Matrix3x1_Add(x_pred, temp_3x1, x_pred, 1.0, 1.0);
        // Step 2e: update the covariance estimate P_pred = P_pred(old)*(I-K)
        Matrix3x3_Add(eye3, K, temp_3x3, 1.0, -1.0);
        Matrix3x3_Mult(temp_3x3, P_pred, P_pred);

        // reset globax, globaly, bearing to reduce drift
        globalx = x_pred[0][0];
        globaly = x_pred[1][0];
        bearing = x_pred[2][0];
    } // end of correction step

    // set x,y,theta to the updated and corrected Kalman values.
    finalx= x_pred[0][0];
    finaly = x_pred[1][0];
    finalbearing = x_pred[2][0];


    SpibRegs.SPIFFRX.bit.RXFFOVFCLR=1; // Clear Overflow flag
    SpibRegs.SPIFFRX.bit.RXFFINTCLR=1; // Clear Interrupt flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP6;
}

void setupSpib(void) //Call this function in main() somewhere after the DINT; line of code.
{
    //Step 1.
    // cut and paste here all the SpibRegs initializations you found for part 3.
    //Also dont forget to cut and paste the GPIO settings for GPIO9, 63, 64, 65,66 which are also a part of the SPIB setup.
    GPIO_SetupPinMux(9, GPIO_MUX_CPU1, 0); // Set as GPIO9 and used as DAN28027 SS
    GPIO_SetupPinOptions(9, GPIO_OUTPUT, GPIO_PUSHPULL); // Make GPIO9 an Output Pin
    GpioDataRegs.GPASET.bit.GPIO9 = 1; //Initially Set GPIO9/SS High so DAN28027 is not selected
    GPIO_SetupPinMux(66, GPIO_MUX_CPU1, 0); // Set as GPIO66 and used as MPU-9250 SS
    GPIO_SetupPinOptions(66, GPIO_OUTPUT, GPIO_PUSHPULL); // Make GPIO66 an Output Pin
    GpioDataRegs.GPCSET.bit.GPIO66 = 1; //Initially Set GPIO66/SS High so MPU-9250 is not selected
    GPIO_SetupPinMux(63, GPIO_MUX_CPU1, 15); //Set GPIO63 pin to SPISIMOB
    GPIO_SetupPinMux(64, GPIO_MUX_CPU1, 15); //Set GPIO64 pin to SPISOMIB
    GPIO_SetupPinMux(65, GPIO_MUX_CPU1, 15); //Set GPIO65 pin to SPICLKB
    EALLOW;
    GpioCtrlRegs.GPBPUD.bit.GPIO63 = 0; // Enable Pull-ups on SPI PINs Recommended by TI for SPI Pins
    GpioCtrlRegs.GPCPUD.bit.GPIO64 = 0;
    GpioCtrlRegs.GPCPUD.bit.GPIO65 = 0;
    GpioCtrlRegs.GPBQSEL2.bit.GPIO63 = 3; // Set I/O pin to asynchronous mode recommended for SPI
    GpioCtrlRegs.GPCQSEL1.bit.GPIO64 = 3; // Set I/O pin to asynchronous mode recommended for SPI
    GpioCtrlRegs.GPCQSEL1.bit.GPIO65 = 3; // Set I/O pin to asynchronous mode recommended for SPI
    EDIS;
    // ---------------------------------------------------------------------------
    SpibRegs.SPICCR.bit.SPISWRESET = 0; // Put SPI in Reset
    SpibRegs.SPICTL.bit.CLK_PHASE = 1; //This happens to be the mode for both the DAN28027 and
    SpibRegs.SPICCR.bit.CLKPOLARITY = 0; //The MPU-9250, Mode 01.
    SpibRegs.SPICTL.bit.MASTER_SLAVE = 1; // Set to SPI Master
    SpibRegs.SPICCR.bit.SPICHAR = 15; // Set to transmit and receive 16 bits each write to SPITXBUF
    SpibRegs.SPICTL.bit.TALK = 1; // Enable transmission
    SpibRegs.SPIPRI.bit.FREE = 1; // Free run, continue SPI operation
    SpibRegs.SPICTL.bit.SPIINTENA = 0; // Disables the SPI interrupt
    SpibRegs.SPIBRR.bit.SPI_BIT_RATE = 49; // Set SCLK bit rate to 1 MHz so 1us period. SPI base clock is
    // 50MHZ. And this setting divides that base clock to create SCLKs period
    SpibRegs.SPISTS.all = 0x0000; // Clear status flags just in case they are set for some reason
    SpibRegs.SPIFFTX.bit.SPIRST = 1;// Pull SPI FIFO out of reset, SPI FIFO can resume transmit or receive.
    SpibRegs.SPIFFTX.bit.SPIFFENA = 1; // Enable SPI FIFO enhancements
    SpibRegs.SPIFFTX.bit.TXFIFO = 0; // Write 0 to reset the FIFO pointer to zero, and hold in reset
    SpibRegs.SPIFFTX.bit.TXFFINTCLR = 1; // Write 1 to clear SPIFFTX[TXFFINT] flag just in case it is set
    SpibRegs.SPIFFRX.bit.RXFIFORESET = 0; // Write 0 to reset the FIFO pointer to zero, and hold in reset
    SpibRegs.SPIFFRX.bit.RXFFOVFCLR = 1; // Write 1 to clear SPIFFRX[RXFFOVF] just in case it is set
    SpibRegs.SPIFFRX.bit.RXFFINTCLR = 1; // Write 1 to clear SPIFFRX[RXFFINT] flag just in case it is set
    SpibRegs.SPIFFRX.bit.RXFFIENA = 1; // Enable the RX FIFO Interrupt. RXFFST >= RXFFIL
    SpibRegs.SPIFFCT.bit.TXDLY = 16; // Set delay between transmits to 16 spi clocks. Needed by DAN28027 chip
    SpibRegs.SPICCR.bit.SPISWRESET = 1; // Pull the SPI out of reset
    SpibRegs.SPIFFTX.bit.TXFIFO = 1; // Release transmit FIFO from reset.
    SpibRegs.SPIFFRX.bit.RXFIFORESET = 1; // Re-enable receive FIFO operation
    SpibRegs.SPICTL.bit.SPIINTENA = 1; // Enables SPI interrupt. !! I dont think this is needed. Need to Test
    SpibRegs.SPIFFRX.bit.RXFFIL = 16; //Interrupt Level to 16 words or more received into FIFO causes interrupt. This is just the initial setting for the register. Will be changed below

    SpibRegs.SPICCR.bit.SPICHAR = 0xF; // send 16 bits at a time
    SpibRegs.SPIFFCT.bit.TXDLY = 0x00; // Make sure the TXdelay in between each transfer to 0.
    //-----------------------------------------------------------------------------------------------------------------
    //Step 2.
    // perform a multiple 16 bit transfer to initialize MPU-9250 registers 0x13,0x14,0x15,0x16
    // 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C 0x1D, 0x1E, 0x1F. Use only one SS low to high for all these writes
    // some code is given, most you have to fill you yourself.
    GpioDataRegs.GPCCLEAR.bit.GPIO66 = 1; // Slave Select Low
    // Perform the number of needed writes to SPITXBUF to write to all 13 registers. Remember we are sending 16 bit transfers, so two registers at a time after the first 16 bit transfer.
    SpibRegs.SPITXBUF = 0x1300; // To address 00x13 write 0x00
    SpibRegs.SPITXBUF = 0x0000; // To address 00x14 and address 00x15, write 0x00
    SpibRegs.SPITXBUF = 0x0000; // To address 00x16 and address 00x17, write 0x00
    SpibRegs.SPITXBUF = 0x0013; // To address 00x18 write 0x00, and address 19 write 0x13
    SpibRegs.SPITXBUF = 0x0200; // To address 00x1A write 0x02, and address 1B write 0x00 //by setting 1A to 02 we are selecting the bandwidth of the IMU // by setting 1B to 00 we are activating the DLPF reg
    SpibRegs.SPITXBUF = 0x0806; // To address 00x1C write 0x08, and address 1D write 0x06// 1c > 8 sets full scale to 4g of gyro // 1D > 06 activates the DLPF and sets it to 5 hz
    SpibRegs.SPITXBUF = 0x0000; // To address 00x1E write 0x00, and address 1F write 0x00

    while(SpibRegs.SPIFFRX.bit.RXFFST !=7); // wait for the correct number of 16 bit values to be received into the RX FIFO
    GpioDataRegs.GPCSET.bit.GPIO66 = 1; // Slave Select High
    temp = SpibRegs.SPIRXBUF; // read the additional number of garbage receive values off the RX FIFO to clear out the RX FIFO
    temp = SpibRegs.SPIRXBUF;
    temp = SpibRegs.SPIRXBUF;
    temp = SpibRegs.SPIRXBUF;
    temp = SpibRegs.SPIRXBUF;
    temp = SpibRegs.SPIRXBUF;
    temp = SpibRegs.SPIRXBUF;
    DELAY_US(10); // Delay 10us to allow time for the MPU-2950 to get ready for next transfer.

    //Step 3.
    // perform a multiple 16 bit transfer to initialize MPU-9250 registers 0x23,0x24,0x25,0x26, 0x27, 0x28, 0x29.
    // Use only one SS low to high for all these writes, some code is given, most you have to fill you yourself.
    GpioDataRegs.GPCCLEAR.bit.GPIO66 = 1; // Slave Select Low
    // Perform the number of needed writes to SPITXBUF to write to all 7 registers
    SpibRegs.SPITXBUF = 0x2300; // To address 00x23 write 0x00
    SpibRegs.SPITXBUF = 0x408C; // To address 00x24 write 0x40 // To address 00x25 write 0x8C
    SpibRegs.SPITXBUF = 0x0288; // To address 00x26 write 0x02 // To address 00x27 write 0x88
    SpibRegs.SPITXBUF = 0x0C0A; // To address 00x28 write 0x0C // To address 00x29 write 0x0A

    while(SpibRegs.SPIFFRX.bit.RXFFST != 4); // wait for the correct number of 16 bit values to be received into the RX FIFO

    GpioDataRegs.GPCSET.bit.GPIO66 = 1; // Slave Select High
    temp = SpibRegs.SPIRXBUF; // read the additional number of garbage receive values off the RX FIFO to clear out the RX FIFO
    temp = SpibRegs.SPIRXBUF;
    temp = SpibRegs.SPIRXBUF;
    temp = SpibRegs.SPIRXBUF;
    DELAY_US(10); // Delay 10us to allow time for the MPU-2950 to get ready for next transfer.

    //Step 4.
    // perform a single 16 bit transfer to initialize MPU-9250 register 0x2A
    GpioDataRegs.GPCCLEAR.bit.GPIO66 = 1; //CS low
    SpibRegs.SPITXBUF = 0x2A81; // Write to address 0x2A the value 0x81
    // wait for one byte to be received
    while(SpibRegs.SPIFFRX.bit.RXFFST !=1);
    GpioDataRegs.GPCSET.bit.GPIO66 = 1; //Slave Select High
    temp = SpibRegs.SPIRXBUF; //clear
    DELAY_US(10);
    // The Remainder of this code is given to you and you do not need to make any changes.
    GpioDataRegs.GPCCLEAR.bit.GPIO66 = 1;
    SpibRegs.SPITXBUF = (0x3800 | 0x0001); // 0x3800 with a 1 at the end
...

This file has been truncated, please download it to see its full contents.

control.h

C Header File
This is the header file for control.c
/*
 * control.h
 *
 *  Created on: Dec 15, 2022
 *      Author: mcy2
 */

#include <math.h>
// here are the variables

struct position {
    float x;
    float y;
    float bearing;
    float omega;
    float velx;
    float vely;
    float distance_to_pos;
    //float dist_to_line;
    //int direction_to_line;// boolean left of the robot is positive
   // float distance_along_line;
    float bearing_wanted;

};

struct line {
    //float line_global_heading;
    float x1;
    float y1;
    float x2;
    float y2;
    float length;
    int index_line;
    int pen_down_bool;

};

void aim2(float bearing_target, float distance);
float aim(struct position pos, struct line prev_line);// this function will generate the angle that the wheels should be
void gen_line(float x_2, float y_2);// this function will generate the line that I want to follow
//void set_wheel_speeds(float turn_angle);
void set_pen_down(int pen_down);
void update_pos(float cur_x, float cur_y, float cur_bearing, float cur_vel_x, float cur_vel_y, float omega_in);

int go(void);// this position will make the wheels run, it will return 1 when it is "close enough" to the point 0 is running.

void setEPWM2A(float controleffort);
void setEPWM2B(float controleffort);

Credits

Madison Yang

Madison Yang

2 projects • 1 follower
Matthew Lim

Matthew Lim

1 project • 0 followers
Weihao Cheng

Weihao Cheng

3 projects • 0 followers
Alex Stevens

Alex Stevens

1 project • 0 followers

Comments