Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:603c28b75dc1, committed 2014-05-20
- Comitter:
- Throwbot
- Date:
- Tue May 20 07:42:25 2014 +0000
- Commit message:
- BT
Changed in this revision
| robot.cpp | Show annotated file Show diff for this revision Revisions of this file |
| robot.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 603c28b75dc1 robot.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/robot.cpp Tue May 20 07:42:25 2014 +0000
@@ -0,0 +1,381 @@
+/* mbed ROBOT Library, for SUTD evobot project, Generation 1
+ * Copyright (c) 2013, SUTD
+ * Author: Mark VanderMeulen
+ *
+ * Dec 18, 2013
+ *
+ * You may want to rewrite this entire library, as this one is only half-finished
+ *
+ * This library allows the user to use each module on the Evobot Generation 1
+ * Functionality:
+ * -Bluetooth connection
+ * -MPU (accelerometer/gyroscope) connection
+ * -Orientation in the XY plane (using Z-axis gyroscope only)
+ * -Remote control functionality (via bluetooth)
+ *
+ * Future functions:
+ * -Switch to turn bluetooth on/off
+ * -Switch to turn MPU on/off (in case of connection errors with the MPU: restart and reconnect
+ * -Calculation of distance travelled (use integration of accelerometer, maybe use Kalman filter)
+ * -Access to the DMP (Digital motion processor) on the MPU to calculate 3D orientation.
+ * -RF mesh network so robots can connect to eachother
+ * -Camera (requires an add-on to the circuit board at the moment)
+ */
+
+
+#include "robot.h"
+#include "math.h"
+//*********************************CONSTRUCTOR*********************************//
+Robot::Robot() : bt(tx_bt,rx_bt),
+ rf24(PTD2, PTD3, PTD1, PTD0, PTD5, PTD4),
+ mpu(PTE0, PTE1),
+ myled(LED),
+ btSwitch(PTE25),
+ currentSensor(CURRENTSENSOR_PIN),
+ irSensorL(irL),
+ irSensorC(irC),
+ irSensorR(irR),
+ voltageSensor(VOLTAGESENSOR_PIN),
+ PWMA(MOT_PWMA_PIN),
+ PWMB(MOT_PWMB_PIN),
+ AIN1(MOT_AIN1_PIN),
+ AIN2(MOT_AIN2_PIN),
+ BIN1(MOT_BIN1_PIN),
+ BIN2(MOT_BIN2_PIN),
+ STBY(MOT_STBY_PIN)
+{
+
+ stop(); //Initialize motors as stopped//
+
+ btSwitch = 1; //turn on bluetooth
+ myled = 0; //turn ON status LED (0 = on, 1 = 0ff)
+ timeNext = 0;
+ //currentAvg = 0; /////////////REMOVE currentAvg LATER. TESTING PURPOSES ONLY////////
+
+ target_angle = 0; //direction we want the robot to be pointed
+ angle_origin = 0; //you can use this to modify the angle of origin
+ origin = 0; //the (x,y) location of the origin (this should be a point, not a double)
+ rz = 0; //The current rotation in the Z-axis
+ dx = 0; //The current displacement in the x-axis (side-side)
+ dy = 0; //The current displacement in the y-axis (forward-back)
+ dz = 0; //The current displacement in the z-axis (up-down)
+
+ AUTO_ORIENT = 1; //robot will automatically orient iteslf using the gyroscope
+ REMOTE_CONTROL = 1; //robot can be controlled over bluetooth
+
+ tt.start(); //start timer
+ mpu.testConnection();
+ wait(1);
+ MPU_OK = 0;
+
+ //initialize MPU
+ if (mpu.testConnection()) {
+ mpu.setBW(MPU6050_BW_10); //default set low pass filter bandwidth to 10HZ
+ mpu.setGyroRange(MPU6050_GYRO_RANGE_500); //default set the gyro range to 500deg/s (robot turning exceeds 250deg/s)
+ mpu.setAcceleroRange(MPU6050_ACCELERO_RANGE_2G); //default set accelero range to 2g
+ MPU_OK=1;
+ myled = 0; //turn on LED
+ calibrate();
+ } else if(0) { //this section is current disabled. change to (1) if you want to retry the accelerometer connection.
+ myled = 1; //turn off LED
+ for (int i = 0; i<25; i++) {
+ myled = !myled;
+ wait_ms(50);
+ if (mpu.testConnection()) {
+ i = 25;
+ myled = 0;
+ MPU_OK=1;
+ } else
+ myled = 1;
+ wait_ms(50);
+ }
+ }
+ myled = MPU_OK; //If LED is off, it is ok. If LED is on, there was a MPU error. Board needs to be restarted.
+ //In the future, at a transistor to switch on/off the mpu in case there is an MPU error. Right now it needs a manual restart.
+
+ bt.baud(BaudRate_bt); //Set bluetooth baud rate
+
+ //Initialize RF chip
+//char txData[TRANSFER_SIZE], rxData[TRANSFER_SIZE];
+// int txDataCnt = 0;
+// int rxDataCnt = 0;
+ rf24.powerUp();
+ rf24.setTransferSize( TRANSFER_SIZE );
+
+ rf24.setReceiveMode();
+ rf24.enable();
+
+
+
+}
+
+//*********************************MOTORS*********************************//
+void Robot::motor_control(int Lspeed, int Rspeed)
+{
+ //Controls the motors. 0 = stopped, 100 = full speed, -100 = reverse speed
+ if (!Lspeed && !Rspeed) //stop//
+ STBY = 0;
+ else
+ STBY = 1;
+
+ //make sure 'speeds' are between -100 and 100, and not between abs(0 to 10)
+ if(Lspeed > 100) Lspeed = 100;
+ else if (Lspeed < -100) Lspeed = -100;
+ else if (Lspeed < 0 && Lspeed > -15) Lspeed = -15; //prevent speed from being less than 15
+ else if (Lspeed > 0 && Lspeed < 15) Lspeed = 15;
+ if(Rspeed > 100) Rspeed = 100;
+ else if (Rspeed < -100) Rspeed = -100;
+ else if (Rspeed < 0 && Rspeed > -15) Rspeed = -15;
+ else if (Rspeed > 0 && Rspeed < 15) Rspeed = 15;
+
+ if (!Rspeed) { //if right motor is stopped
+ AIN1 = 0;
+ AIN2 = 0;
+ PWMA = 0;
+ } else if (!Lspeed) { //if left motor is stopped
+ BIN1 = 0;
+ BIN2 = 0;
+ PWMB = 0;
+ }
+ //RIGHT MOTOR//
+ if(Rspeed > 0) { //Right motor fwd
+ AIN1 = MOTOR_R_DIRECTION; //set the motor direction
+ AIN2 = !AIN1;
+ } else { //Right motor reverse
+ AIN2 = MOTOR_R_DIRECTION;
+ AIN1 = !AIN2;
+ }
+ PWMA = abs(Rspeed/100.0);
+ //LEFT MOTOR//
+ if(Lspeed >0) {
+ BIN1 = MOTOR_L_DIRECTION;
+ BIN2 = !BIN1;
+ } else {
+ BIN2 = MOTOR_L_DIRECTION;
+ BIN1 = !BIN2;
+ }
+ PWMB = abs(Lspeed/100.0);
+}
+
+void Robot::stop()
+{
+ motor_control(0,0);
+}
+void Robot::set_speed(int Speed)
+{
+ speed = Speed;
+ motor_control(speed,speed);
+}
+
+//************************Setting direction of robot****************************//
+void Robot::set_direction(double angle)
+{
+ //Set the direction the robot should be facing from origin(in radians)
+ target_angle = angle;
+}
+void Robot::set_direction_deg(double angle)
+{
+ //Set the direction the robot should be facing from origin (in degrees)
+ target_angle = angle*M_PI/180;
+}
+void Robot::auto_enable(bool x)
+{
+ AUTO_ORIENT = x;
+}
+
+//************************UPDATE: To be called in main loop***************************//
+//This calculates position and angle
+//Also orients robot in the correct direction
+//if 'print' is 1, print acceleration and gyro data over bluetooth
+void Robot::update()
+{
+ double SP;
+ int rotationSpeed;
+ //int n=50;
+
+ double Kp = 100; //weighting values for PID controller. Only Proportional component is used.
+ double Ki = 0; //Integral component is not used
+ double Kd = 0; //derivative component is not used
+
+ if(MPU_OK) { //only do this if MPU is connected
+ wait(0.1);
+ mpu.getAcceleroRaw(accdata);
+ mpu.getGyroRaw(gyrodata);
+ time = tt.read();
+//bt.printf("s;t_%d;1_%lf;2_%lf;3_%d;4_%d;5_%d;6_%d;7_%d;8_%d;9_%lf;10_%lf;11_%lf;s\n\r",time_robot,getCurrent(),getVoltage(),accdata[0],accdata[1],accdata[2],gyrodata[0],gyrodata[1],gyrodata[2],irReadL(),irReadC(),irReadR());
+ /*if(REMOTE_CONTROL) { //if remote control over bluetooth is enabled
+ m_ctrl=remote_ctrl(); //call the romote control function
+ }*/
+ if(AUTO_ORIENT) { //enable PID control of angle
+ SP = target_angle; //desired angle (radians)
+ rz = rz + ((gyrodata[2]-gyroOffset[2])*(time-timePrev)/gyroCorrect); //rz is the rotation(radians) from start
+ Irz = Irz + (rz-SP)*(time-timePrev); //Irz needs to be reset every so often, or it should be ignored
+ rotationSpeed = (Kp*(rz-SP) + Ki*Irz + Kd*gyrodata[2]/gyroCorrect);
+ /*data[0]= getCurrent();
+ data[1]= getVoltage();
+ data[2]= accdata[0];
+ data[3]= accdata[1];
+ data[4]= accdata[2];
+ data[5]= gyrodata[0];
+ data[6]= gyrodata[1];
+ data[7]= gyrodata[2];
+ data[8]= irReadL();
+ data[9]= irReadC();
+ data[10]= irReadC();
+ data[11]= rz;*/
+
+ //TODO: pull "rotationspeed" up to 10 if it is less than 10. This will(should) improve the ability to drive straight
+
+ if(time > timeNext || (speed==0 && rotationSpeed ==0)) { //prevent the motor control from being set too often
+ timeNext = time + MOTOR_INTERVAL/1000.0; //only set the motor speed every 10ms
+ // if(abs(rz-SP)>(10*M_PI/180))
+ // {
+ // motor_control((speed+rotationSpeed)/20, (speed-rotationSpeed)/20); //Set motor speeds
+ //}
+ // else
+ //{
+ motor_control((speed+rotationSpeed), (speed-rotationSpeed)); //Set motor speeds
+ //}
+ }
+ }
+ timePrev = time;
+ }
+}
+
+void Robot::remote_ctrl(char c,int desired_speed,int desired_angle)
+{
+ //This is a private function
+ Irz = 0;
+ switch (c) {
+ case ctrl_forward:
+ speed = -1*desired_speed;
+ break;
+ case ctrl_backward:
+ speed = 1*desired_speed;
+ break;
+ case ctrl_right:
+ target_angle += 90*M_PI/180;
+ break;
+ case ctrl_left:
+ target_angle -= 90*M_PI/180;
+ break;
+ case ctrl_calibrate:
+ calibrate();
+ break;
+ case ctrl_turn_angle_cw:
+ target_angle +=desired_angle*M_PI/180;
+ break;
+ case ctrl_turn_angle_ccw:
+ target_angle -=desired_angle*M_PI/180;
+ break;
+ default:
+ speed = 0;
+ stop();
+ break;
+ }
+}
+//*********************************CALIBRATE*********************************//
+void Robot::calibrate()
+{
+ stop();
+ wait(1.5);
+ double timeNOW = tt.read();
+ int count=0;
+ int i;
+
+ //set the accelerometer and gyro offsets
+ while(tt.read()<timeNOW+1.5) { //calculate gyro offset
+ mpu.getGyroRaw(gyrodata);
+ mpu.getAcceleroRaw(accdata);
+ for(i=0; i<3; i++) {
+ gyroOffset[i] += gyrodata[i];
+ accOffset[i] += accdata[i];
+ }
+ count++;
+ }
+ for(i=0; i<3; i++) {
+ gyroOffset[i] = gyroOffset[i]/count; //rxOffset
+ accOffset[i] = accOffset[i]/count;
+ }
+ accOffset[2] = 0; //we don't want to remove GRAVITY from the z-axis accelerometer.
+}
+
+//*********************************ROBOT-SENSORS*********************************//
+
+double Robot::getCurrent()
+{
+
+ double Vsensor = currentSensor.read();
+ Vsensor = 1000*((.8998-Vsensor)/.6411);
+ return Vsensor;
+}
+double Robot::getVoltage()
+{
+ float voltage = 3.3*(voltageSensor.read()); // convert analog value to voltage at node
+ voltage *= 1.5; // inverse of voltage divider
+ return voltage;
+}
+void Robot::getIMU(float *adata, float *gdata)
+{
+ mpu.getAcceleroRaw(accdata);
+ mpu.getGyroRaw(gyrodata);
+ /*imuFilter.updateFilter(gyrodata[0],gyrodata[1],gyrodata[2],accdata[0],accdata[1],accdata[2]);
+ imuFilter.computeEuler();
+ gdata[0]=(float)imuFilter.getRoll();
+ gdata[1]=(float)imuFilter.getPitch();
+ gdata[2]= (float)imuFilter.getYaw();*/
+ // adata[0] = (float) (accdata[0]);
+ //adata[1] = (float) (accdata[1]);
+ //adata[2] = (float) (accdata[2]);
+ adata[0] = ((float) (accdata[0]-accOffset[0]))/32655*9.81*2;
+ adata[1]= ((float) (accdata[1]-accOffset[1]))/32655*9.81*2;
+ adata[2]= ((float) (accdata[2]-accOffset[2]))/32655*9.81*2;
+ gdata[0]=(((float)(gyrodata[0]-gyroOffset[0]))/((float)gyroCorrect))*180/(M_PI);
+ gdata[1]=(((float)(gyrodata[1]-gyroOffset[1]))/((float)gyroCorrect))*180/(M_PI);
+ gdata[2]=(((float)(gyrodata[2]-gyroOffset[2]))/((float)gyroCorrect))*180/(M_PI);
+}
+
+double Robot::irReadL()
+{
+ int C = 14;
+ double D = -1.1;
+ double r = irSensorL.read();
+ double reading=(pow(r,D)* C )+ 4;
+ return reading;
+
+}
+
+double Robot::irReadC()
+{
+ int C = 14;
+ double D = -1.1;
+ double r = irSensorC.read();
+ double reading=(pow(r,D)* C )+ 4;
+ return reading;
+}
+
+double Robot::irReadR()
+{
+ int C = 14;
+ double D = -1.1;
+ double r = irSensorR.read();
+ double reading=(pow(r,D)* C )+ 4;
+ return reading;
+}
+double Robot::return_rotation()
+{
+ return rz;
+}
+int Robot::isMPU()
+{
+ return MPU_OK;
+}
+
+//******************RF24 CHIP FUNCTIONS****************************//
+void Robot::rf24_power(int x)
+{
+ if(x) //power up
+ rf24.powerUp();
+ else //power down
+ rf24.powerDown();
+}
\ No newline at end of file
diff -r 000000000000 -r 603c28b75dc1 robot.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/robot.h Tue May 20 07:42:25 2014 +0000
@@ -0,0 +1,177 @@
+#ifndef ROBOT_H
+#define ROBOT_H
+
+#include "mbed.h"
+#include "MPU6050.h"
+#include "nRF24L01P.h"
+
+#define BaudRate_bt 9600 //Baud rate of 9600
+#define tx_bt PTA2 //Bluetooth connection pins
+#define rx_bt PTA1 //Bluetooth connection pins
+#define tx_mpu PTE0 //MPU connection pins
+#define rx_mpu PTE1 //MPU connection pins
+#define mpu_bandwidth MPU6050_BW_20 //set the MPU low pass filter bandwidth to 20hz
+
+#define LED PTE3 //status LED pin
+#define CURRENTSENSOR_PIN PTC2
+#define VOLTAGESENSOR_PIN PTB0
+
+#define CURRENT_R1 180 //160.0 //values of the current sensor opamp resistors
+#define CURRENT_R2 10
+#define CURRENT_R3 80
+#define CURRENT_R4 84.7
+#define VREF3_3 3.3 //digital logic voltage
+#define VREF5 5.0 //5v voltage //NOTE: 5v voltage is consistent when using new batts, but not using old blue batts
+
+#define irL PTB1
+#define irC PTB3
+#define irR PTB2
+
+#define MOT_PWMA_PIN PTA4 //Motor control pins
+#define MOT_PWMB_PIN PTA5
+#define MOT_STBY_PIN PTA15
+#define MOT_AIN1_PIN PTA14
+#define MOT_AIN2_PIN PTA13
+#define MOT_BIN1_PIN PTA16
+#define MOT_BIN2_PIN PTA17
+
+#define M_PI 3.14159265359 //PI
+#define gyroCorrect 3720 //divide raw gyro data by this to get result in RAD/SECOND (if gyroRange is 500 rad/s)
+
+//Correct direction of motors. If number = 1, forward. If number = 0, backwards (for if motors are wired backwards)
+#define MOTOR_R_DIRECTION 1
+#define MOTOR_L_DIRECTION 1
+
+#define MOTOR_INTERVAL 20 //defines the interval (in milliseconds) between when motor can be set
+//NOTE: Can't make this less than 20ms, because that is the PWM frequency
+
+//Key bindings for remote control robot - for the future try to use arrow keys instead of 'asdw'
+#define ctrl_forward 'i' //forward
+#define ctrl_backward 'k' //back
+#define ctrl_left 'j' //turn left
+#define ctrl_right 'l' //turn right
+#define ctrl_calibrate 'c' //re-calibrate the accelerometer and gyro
+#define ctrl_turn_angle_cw 'o' // turn angle
+#define ctrl_turn_angle_ccw 'p'
+// The nRF24L01+ supports transfers from 1 to 32 bytes, but Sparkfun's
+// "Nordic Serial Interface Board" (http://www.sparkfun.com/products/9019)
+// only handles 4 byte transfers in the ATMega code.
+#define TRANSFER_SIZE 4
+
+class Robot
+{
+public:
+ /**
+ * Constructor - does nothing atm
+ */
+ Robot();
+
+ /**
+ * MOTOR CONTROLS
+ */
+ void motor_control(int Lspeed, int Rspeed); //Input speed for motors. Integer between 0 and 100
+ void stop(); //stop motors
+ void set_direction(double angle); //set angle for the robot to face (from origin)
+ void set_direction_deg(double angle);
+ void set_speed(int Speed ); //set speed for robot to travel at
+ void auto_enable(bool x);
+ /**
+ * MPU CONTROLS
+ */
+
+ /**
+ * UPDATE (this must be called repeatedly so the robot will sample accelerometer to find position)
+ */
+ void update(); //print variable decides which values to print
+ void remote_ctrl(char c,int desired_speed, int desired_angle);
+ //print = 0: nothing
+ //print = 1: Accelerometer and gyro
+ //print = 2: Current and voltage
+
+ // calibrate the gyro and accelerometer //
+ void calibrate();
+
+ /**
+ * Status: find the distance, orientation, battery values, etc of the robot
+ */
+ //void distanceTravelled(double x[3])
+ //void orientation(something quaternion? on xy plane?)
+ double getCurrent(); //Get the current drawn by the robot
+ double getCurrent(int n); //get the current, averaged over n samples
+ double getVoltage(); //get the battery voltage (ask connor for completed function)
+ void getIMU(float *adata, float *gdata);
+ double irReadL();
+ double irReadC();
+ double irReadR();
+ double return_rotation();
+ int isMPU();
+
+
+ //Wireless connections
+ Serial bt; //bluetooth connection
+ nRF24L01P rf24; //RF network connection
+
+ //RF24 network functions//
+ void rf24_power(int status); //power on or off the RF network
+ char rf24_read();
+ int rf24_write(char letter); //write a letter to RF
+ int rf24_write(char* buffer, int length); //write
+ int acc[3];
+ int gyr[3];
+
+
+
+ //-------------------PRIVATE VARIABLES AND FUNCTIONS-----------------------------------------------//
+private:
+
+ //commands for remote control robot
+
+ MPU6050 mpu; //MPU connection
+ DigitalOut myled; //(PTE3) Processor LED (1 = off, 0 = on)
+ DigitalOut btSwitch;
+ AnalogIn currentSensor;
+ AnalogIn irSensorL;
+ AnalogIn irSensorC;
+ AnalogIn irSensorR;
+ AnalogIn voltageSensor;
+
+ double dx; //distance travelled in x direction
+ double dy; //distance travelled in y direction
+ double dz; //distance travelled in z direction (zero?)
+ double origin; //location of robot origin (or can be set if robot starting location is known.
+ double target_angle; //direction that we want the robot to face (radians)
+
+ int accdata[3]; //data from accelerometer (raw)
+ int gyrodata[3]; //data from gyro (raw)
+ //double gyroCorrect; //= 3720; //divide by this to get gyro data in RAD/SECOND. This is above as a #DEFINE
+ int gyroOffset[3]; //Correction value for each gyroscope to zero the values.
+ int accOffset[3]; //correction value for each accelerometer
+int speed; //set the speed of robot
+ /**Angle is always measured in clockwise direction, looking down from the top**/
+ /*Angle is measured in RADIANS*/
+ double rz; //Direction robot is facing
+ double Irz; //integral of the rotation offset from target. (Optionally) Used for PID control of direction
+ double angle_origin; //Angle of origin (can be changed later, or set if robot starts at known angle)
+ bool AUTO_ORIENT; //if this flag is 1, the robot automatically orients itself to selected direction
+ bool REMOTE_CONTROL; //if this flag is 1, the robot will be controlled over bluetooth
+
+ /////////// Motor control variables ///////////
+ PwmOut PWMA;//(MOT_PWMA_PIN);
+ PwmOut PWMB;//(MOT_PWMB_PIN);
+ DigitalOut AIN1;//(MOT_AIN1_PIN);
+ DigitalOut AIN2;//(MOT_AIN2_PIN);
+ DigitalOut BIN1;//(MOT_BIN1_PIN);
+ DigitalOut BIN2;//(MOT_BIN2_PIN);
+ DigitalOut STBY;//(MOT_STBY_PIN);
+ double timeNext; //next time that the motor is allowed to be updated
+
+ bool MPU_OK;
+
+ Timer tt; //timer
+
+ double time; //time of current iteration
+ double timePrev; //time of previous iteration
+
+
+};
+#endif
\ No newline at end of file