OK, call me stupid :-[ I've been beating this to death all day but I can't see my mistake - all advice welcome !
Although my BT and my self-balancing robot code work separately, putting them together fails dismally - the robot balances reasonably well indefinitely, but as soon as I send it a command over BT it falls over, though the motors are still locked. It's as if it gets stuck in the BT loop, or never gets any more MPU6050 interrupts, not sure ...
I'm not understanding something here - please help
Thanks,
David
#include "I2Cdev.h"
#include <PID_v1.h>
#include "MPU6050_6Axis_MotionApps20.h"
#include <SoftwareSerial.h>
const int HC06_YELLOW=11;
const int HC06_GREEN=12;
SoftwareSerial BT(HC06_YELLOW, HC06_GREEN);
MPU6050 mpu;
bool dmpReady = false; 聽
uint8_t mpuIntStatus;
uint8_t devStatus;
uint16_t packetSize; 聽
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3];
int charIdx;
char cmdChar;
char readChar;
String readString;
double setpoint= 179.5;
double Kp = 28;
double Kd = 1.75;
double Ki = 350;
double input, output;
PID pid(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
int enA = 9;
int in1 = 4;
int in2 = 5;
int enB = 10;
int in3 = 6;
int in4 = 7;
double motorAoffset = 0.75;
double motorBoffset = 1.0;
volatile bool mpuInterrupt = false;
void dmpDataReady()
{
聽mpuInterrupt = true;
}
void setup()
{
聽Serial.begin(115200);
聽BT.begin(9600);
聽
聽 聽Serial.println(F("Initializing I2C devices..."));
聽 聽mpu.initialize();
聽 聽Serial.println(F("Testing device connections..."));
聽 聽Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
聽 聽devStatus = mpu.dmpInitialize();
聽mpu.setXAccelOffset(youroffset)
聽mpu.setXAccelOffset(-4637);
聽mpu.setYAccelOffset(605);
聽mpu.setZAccelOffset(1943);
聽mpu.setXGyroOffset(110);
聽mpu.setYGyroOffset(33);
聽mpu.setZGyroOffset(-4);
聽
聽// make sure it worked (returns 0 if so)
聽if (devStatus == 0)
聽{
聽 聽// turn on the DMP, now that it's ready
聽 聽Serial.println(F("Enabling DMP..."));
聽 聽mpu.setDMPEnabled(true);
聽 聽// enable Arduino interrupt detection
聽 聽Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
聽 聽attachInterrupt(0, dmpDataReady, RISING);
聽 聽mpuIntStatus = mpu.getIntStatus();
聽 聽// set our DMP Ready flag so the main loop() function knows it's okay to use it
聽 聽Serial.println(F("DMP ready! Waiting for first interrupt..."));
聽 聽dmpReady = true;
聽 聽// get expected DMP packet size for later comparison
聽 聽packetSize = mpu.dmpGetFIFOPacketSize();
聽 聽 聽 聽
聽 聽//setup PID
聽 聽pid.SetMode(AUTOMATIC);
聽 聽pid.SetSampleTime(10);
聽 聽pid.SetOutputLimits(-255, 255); 聽
聽}
聽else
聽{
聽 聽 聽// ERROR!
聽 聽 聽// 1 = initial memory load failed
聽 聽 聽// 2 = DMP configuration updates failed
聽 聽 聽// (if it's going to break, usually the code will be 1)
聽 聽 聽Serial.print(F("DMP Initialization failed (code "));
聽 聽 聽Serial.print(devStatus);
聽 聽 聽Serial.println(F(")"));
聽}
聽// Initialise the Motor output pins
聽pinMode(enA, OUTPUT);
聽pinMode(in1, OUTPUT);
聽pinMode(in2, OUTPUT);
聽
聽pinMode(enB, OUTPUT);
聽pinMode(in3, OUTPUT);
聽pinMode(in4, OUTPUT);
聽//By default turn off both the motors
聽Stop();
}
void loop()
{
聽// if programming failed, don't try to do anything
聽if (!dmpReady) return;
聽// wait for MPU interrupt or extra packet(s) available
聽while (!mpuInterrupt && fifoCount < packetSize)
聽{
聽 聽//no mpu data - performing PID calculations and output to motors 聽 聽
聽 聽pid.Compute(); 聽
聽 聽 聽 聽
聽 聽//Print the value of Input and Output on serial monitor to check how it is working.
聽 聽Serial.print(input); Serial.print(" =>"); Serial.println(output);
聽 聽 聽 聽 聽 聽 聽
聽 聽if (input>150 && input<200){//If the Bot is falling
聽 聽 聽 聽 聽
聽 聽 聽if (output>0) //Falling towards front
聽 聽 聽 聽Forward(); //Rotate the wheels forward
聽 聽 聽else if (output<0) //Falling towards back
聽 聽 聽 聽Reverse(); //Rotate the wheels backward
聽 聽}
聽 聽else //If Bot not falling
聽 聽 聽Stop(); //Hold the wheels still
聽 聽if (BT.available()){ 聽// if text arrived in from Serial serial
聽 聽 聽charIdx = 0;
聽 聽 聽while (BT.available())
聽 聽 聽{
聽 聽 聽 聽delay(3); 聽
聽 聽 聽 聽readChar = BT.read();
聽 聽 聽 聽if (charIdx == 0)
聽 聽 聽 聽 聽cmdChar = readChar;
聽 聽 聽 聽else
聽 聽 聽 聽 聽readString += readChar;
聽 聽 聽 聽charIdx++;
聽 聽 聽}
聽 聽 聽if (readString.length() >0)
聽 聽 聽{ 聽
聽 聽 聽 聽switch (cmdChar){
聽 聽 聽 聽 聽case 'i':
聽 聽 聽 聽 聽 聽Ki = readString.toDouble();
聽 聽 聽 聽 聽 聽break;
聽 聽 聽 聽 聽case 'd':
聽 聽 聽 聽 聽 聽Kd = readString.toDouble();
聽 聽 聽 聽 聽 聽break;
聽 聽 聽 聽 聽case 'p':
聽 聽 聽 聽 聽 聽Kp = readString.toDouble();
聽 聽 聽 聽 聽 聽break;
聽 聽 聽 聽 聽case 's':
聽 聽 聽 聽 聽 聽setpoint = readString.toDouble();
聽 聽 聽 聽 聽 聽break;
聽 聽 聽 聽 聽case 'A':
聽 聽 聽 聽 聽 聽motorAoffset = readString.toDouble();
聽 聽 聽 聽 聽 聽break;
聽 聽 聽 聽 聽case 'B':
聽 聽 聽 聽 聽 聽motorBoffset = readString.toDouble();
聽 聽 聽 聽 聽 聽break;
聽 聽 聽 聽}
聽 聽 聽
聽 聽 聽 聽debugSettings(); 聽 聽 聽 聽
聽 聽 聽 聽readString=""; 聽
聽 聽 聽}
聽 聽 聽BT.println("\n-----------------");
聽 聽}
聽}
聽// reset interrupt flag and get INT_STATUS byte
聽mpuInterrupt = false;
聽mpuIntStatus = mpu.getIntStatus();
聽// get current FIFO count
聽fifoCount = mpu.getFIFOCount();
聽// check for overflow (this should never happen unless our code is too inefficient)
聽if ((mpuIntStatus & 0x10) || fifoCount == 1024)
聽{
聽 聽// reset so we can continue cleanly
聽 聽 聽 聽mpu.resetFIFO();
聽 聽 聽 聽Serial.println(F("FIFO overflow!"));
聽 聽// otherwise, check for DMP data ready interrupt (this should happen frequently)
聽}
聽else if (mpuIntStatus & 0x02)
聽{
聽 聽// wait for correct available data length, should be a VERY short wait
聽 聽while (fifoCount < packetSize)
聽 聽 聽fifoCount = mpu.getFIFOCount();
聽 聽// read a packet from FIFO
聽 聽mpu.getFIFOBytes(fifoBuffer, packetSize);
聽 聽 聽 聽
聽 聽// track FIFO count here in case there is > 1 packet available
聽 聽// (this lets us immediately read more without waiting for an interrupt)
聽 聽fifoCount -= packetSize;
聽 聽mpu.dmpGetQuaternion(&q, fifoBuffer); //get value for q
聽 聽mpu.dmpGetGravity(&gravity, &q); //get value for gravity
聽 聽mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); //get value for ypr
聽 聽input = ypr[2] * 180/M_PI + 180;
聽}
}
void debugSettings()
{
聽BT.print("setpoint: 聽 聽 "); BT.println(setpoint);
聽BT.print("yaw: 聽 聽 聽 聽 聽"); BT.println(ypr[1]);
聽BT.print("pitch: 聽 聽 聽 聽"); BT.println(ypr[2]);
聽BT.print("Kp: 聽 聽 聽 聽 聽 "); BT.println(Kp);
聽BT.print("Kd: 聽 聽 聽 聽 聽 "); BT.println(Kd);
聽BT.print("Ki: 聽 聽 聽 聽 聽 "); BT.println(Ki);
聽BT.print("motorAoffset: "); BT.println(motorAoffset);
聽BT.print("motorBoffset: "); BT.println(motorBoffset);
}
void Forward() // Code to rotate the wheel forward
{
聽 聽// Set Motor A forward
聽digitalWrite(in1, LOW);
聽digitalWrite(in2, HIGH);
聽
聽// Set Motor B forward
聽digitalWrite(in3, LOW);
聽digitalWrite(in4, HIGH);
聽analogWrite(enA, output*motorAoffset); // Send PWM signal to motor A
聽analogWrite(enB, output*motorBoffset); // Send PWM signal to motor B
}
void Reverse() // Code to rotate the wheel Backward 聽
{
聽 聽// Set Motor A backward
聽digitalWrite(in1, HIGH);
聽digitalWrite(in2, LOW);
聽
聽// Set Motor B backward
聽digitalWrite(in3, HIGH);
聽digitalWrite(in4, LOW);
聽analogWrite(enA, output*motorAoffset*-1); // Send PWM signal to motor A
聽analogWrite(enB, output*motorBoffset*-1); // Send PWM signal to motor B
}
void Stop() // Code to stop both the wheels
{
聽 聽// Set Motor A stop
聽digitalWrite(in1, LOW);
聽digitalWrite(in2, LOW);
聽
聽// Set Motor B stop
聽digitalWrite(in3, LOW);
聽digitalWrite(in4, LOW);
聽analogWrite(enA, 0); // Send PWM signal to motor A
聽analogWrite(enB, 0); // Send PWM signal to motor B
}