// // BalaC balancing robot (IMU:MPU6886) // by Kiraku Labo // // 1. Lay the robot flat, and power on. // 2. Wait until Gal-1 (Pitch Gyro calibration) completes. // 3. Hold still the robot upright in balance until Cal-2 (Accel & Yaw Gyro cal) completes. // // short push of power button: Gyro calibration // long push (>1sec) of power button: switch mode between standig and demo(circle) // #include #define LED 10 #define N_CAL1 100 #define N_CAL2 100 #define LCDV_MID 60 boolean serialMonitor=true; boolean standing=false; int16_t counter=0; uint32_t time0=0, time1=0; int16_t counterOverPwr=0, maxOvp=20; float power, powerR, powerL, yawPower; float varAng, varOmg, varSpd, varDst, varIang; float gyroXoffset, gyroYoffset, gyroZoffset, accXoffset; float gyroXdata, gyroYdata, gyroZdata, accXdata, accZdata; float aveAccX=0.0, aveAccZ=0.0, aveAbsOmg=0.0; float cutoff=0.1; //~=2 * pi * f (Hz) const float clk = 0.01; // in sec, const uint32_t interval = (uint32_t) (clk*1000); // in msec float Kang, Komg, KIang, Kyaw, Kdst, Kspd; int16_t maxPwr; float yawAngle=0.0; float moveDestination, moveTarget; float moveRate=0.0; const float moveStep=0.2*clk; int16_t fbBalance=0; int16_t motorDeadband=0; float mechFactR, mechFactL; int8_t motorRDir=0, motorLDir=0; bool spinContinuous=false; float spinDest, spinTarget, spinFact=1.0; float spinStep=0.0; //deg per 10msec int16_t ipowerL=0, ipowerR=0; int16_t motorLdir=0, motorRdir=0; //0:stop 1:+ -1:- float vBatt, voltAve=3.7; int16_t punchPwr, punchPwr2, punchDur, punchCountL=0, punchCountR=0; byte demoMode=0; void setup() { pinMode(LED, OUTPUT); digitalWrite(LED, HIGH); M5.begin(); Wire.begin(0, 26); //SDA,SCL imuInit(); M5.Axp.ScreenBreath(11); M5.Lcd.setRotation(2); M5.Lcd.setTextFont(4); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextSize(1); resetMotor(); resetPara(); resetVar(); calib1(); #ifdef DEBUG debugSetup(); #else setMode(false); #endif } void loop() { checkButtonP(); #ifdef DEBUG if (debugLoop1()) return; #endif getGyro(); if (!standing) { dispBatVolt(); aveAbsOmg = aveAbsOmg * 0.9 + abs(varOmg) * 0.1; aveAccZ = aveAccZ * 0.9 + accZdata * 0.1; M5.Lcd.setCursor(10,130); M5.Lcd.printf("%5.2f ", -aveAccZ); if (abs(aveAccZ)>0.9 && aveAbsOmg<1.5) { calib2(); if (demoMode==1) startDemo(); standing=true; } } else { if (abs(varAng)>30.0 || counterOverPwr>maxOvp) { resetMotor(); resetVar(); standing=false; setMode(false); } else { drive(); } } counter += 1; if (counter >= 100) { counter = 0; dispBatVolt(); if (serialMonitor) sendStatus(); } do time1 = millis(); while (time1 - time0 < interval); time0 = time1; } void calib1() { calDelay(30); digitalWrite(LED, LOW); calDelay(80); M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(0, LCDV_MID); M5.Lcd.print(" Cal-1 "); gyroYoffset=0.0; for (int i=0; i 0.1) spinFact=constrain(-(powerR+powerL)/10.0, -1.0, 1.0); //moving else spinFact=1.0; //standing if (spinContinuous) spinTarget += spinStep * spinFact; else { if (spinTarget < spinDest) spinTarget += spinStep; if (spinTarget > spinDest) spinTarget -= spinStep; } moveTarget += moveStep * (moveRate +(float)fbBalance/100.0); varSpd += power * clk; varDst += Kdst * (varSpd * clk -moveTarget); varIang += KIang * varAng * clk; power = varIang + varDst + (Kspd * varSpd) + (Kang * varAng) + (Komg * varOmg); if (abs(power) > 1000.0) counterOverPwr += 1; else counterOverPwr =0; if (counterOverPwr > maxOvp) return; power = constrain(power, -maxPwr, maxPwr); yawPower = (yawAngle - spinTarget) * Kyaw; powerR = power - yawPower; powerL = power + yawPower; ipowerL = (int16_t) constrain(powerL * mechFactL, -maxPwr, maxPwr); int16_t mdbn=-motorDeadband; int16_t pp2n=-punchPwr2; if (ipowerL > 0) { if (motorLdir == 1) punchCountL = constrain(++punchCountL, 0, 100); else punchCountL=0; motorLdir = 1; if (punchCountL 0) { if (motorRdir == 1) punchCountR = constrain(++punchCountR, 0, 100); else punchCountR=0; motorRdir = 1; if (punchCountR