Find the bug! Needs fixing. Not tuned! And something crashes the board. When vibrating a lot (probably high gains or high d-term / d-term noise) or when the robot leans a lot to one side everything freezes. Both loops blinking leds stop completely and steppers stay at last command. I've tried electronic fixes and lastly put the controller on its own power supply. Can be triggered even without any power electronics connected (rocking the robot by hand). So it seems to be software related!
215 lines
5.8 KiB
C++
215 lines
5.8 KiB
C++
#include "mbed.h"
|
|
|
|
// STD
|
|
#include <cmath>
|
|
|
|
// Mbed
|
|
#include "mbed_events.h"
|
|
|
|
// target definitions
|
|
#include "src/targets/revo_f4/pins.h"
|
|
// Mmath
|
|
#include "src/math/Utilities.h"
|
|
// Drivers
|
|
#include "src/drivers/MPU6000.h"
|
|
#include "src/drivers/stepper.h"
|
|
#include "src/drivers/servo.h"
|
|
// Control
|
|
#include "src/control/lpf.h"
|
|
#include "src/control/PID.h"
|
|
#include "src/control/ImuFusion.h"
|
|
|
|
#define WHEEL_SIZE 0.09f
|
|
|
|
using namespace targets::revo_f4;
|
|
using namespace drivers;
|
|
using namespace control;
|
|
using namespace math;
|
|
|
|
EventQueue queue;
|
|
|
|
|
|
// MPU setup
|
|
SPI spi(PA_7, PA_6, PA_5); //define the SPI (mosi, miso, sclk). Default frequency is 1Mhz
|
|
mpu6000_spi imu(spi,PA_4); //define the mpu6000 object
|
|
|
|
PwmOut ledBlue(D4);
|
|
DigitalOut ledOrg(D5);
|
|
|
|
Stepper motorL(PC_9, PC_7, PC_8);
|
|
Stepper motorR(PB_15, PB_14, PC_6);
|
|
|
|
Servo servo(PA_0);
|
|
|
|
// Interrupt pin from Gyro to MCU
|
|
InterruptIn gyroINT(PC_4);
|
|
|
|
Timer timer;
|
|
|
|
// TODO: Figure out some good values
|
|
controllerPI throttleControl(0.0025, 0.01, 5, 0); // 0.065, 0.05, 12, 40
|
|
|
|
// TODO: Figure out some good values
|
|
controllerPD angleControl(25.0, 35.25, 400);
|
|
// Alternatively try controllerPD2 which has another Dterm implementation
|
|
|
|
// Draft of some control function
|
|
// this runs in the context of eventThread and is triggered by the gyro ISR pin
|
|
void controlFunc()
|
|
{
|
|
static ImuFusion imuFusion(&imu);
|
|
static float controlOutput(0.0f);
|
|
|
|
// Calculate dT in sec
|
|
float dT = timer.read_us()/(float)1000000.0;
|
|
timer.reset();
|
|
|
|
// Retrieve IMU angle (Only x-axis implemented for now)
|
|
float angleX = imuFusion.getAngle(dT);
|
|
// Reset anything left in the IMU FIFO queue
|
|
imu.fifo_reset();
|
|
|
|
// If the robot is above this angle we turn off motors
|
|
static bool disabled = false;
|
|
if (abs(angleX) > (float)50.0f && !disabled)
|
|
{
|
|
controlOutput = 0.0f; // rinse integral
|
|
disabled = true;
|
|
}
|
|
else if (abs(angleX) < (float)50.0f && disabled)
|
|
{
|
|
disabled = false;
|
|
}
|
|
|
|
/* --------------------------
|
|
Calculate estimated groundspeed
|
|
of the robot.
|
|
TODO: Inject correct input (compensate for robot rotation)
|
|
-------------------------- */
|
|
// Calculate filtered groundspeed of the robot (From deg/s to m/s)
|
|
float estimatedSpeed((motorL.getSpeed() + motorR.getSpeed())/2);
|
|
static incrementalLPF speedFilter;
|
|
float filteredEstSpeed(speedFilter.filter(estimatedSpeed));
|
|
float speedScale((1.0f/360.0f)*WHEEL_SIZE*PI);
|
|
float groundSpeed(filteredEstSpeed*speedScale);
|
|
|
|
/* --------------------------
|
|
Calculate the setpoint for
|
|
the main control (control the angle)
|
|
through this throttle control loop (PI)
|
|
TODO: TEMP turned off the throttle
|
|
control to tune the PD angle control
|
|
-------------------------- */
|
|
float throttle(0.0f); // TODO: This will be the input from remote
|
|
float angleSP = 0.0f; // Temporarily emulate an output
|
|
//float angleSP = throttleControl.run(dT, groundSpeed, throttle);
|
|
|
|
|
|
/* --------------------------
|
|
The last control loop. Angle (PD)
|
|
TODO:
|
|
-------------------------- */
|
|
// Integrating the output to obtain acceleration
|
|
if (!disabled)
|
|
{
|
|
controlOutput += angleControl.run(dT, angleX, angleSP);
|
|
|
|
controlOutput = constrain(controlOutput, 800.0f);
|
|
}
|
|
|
|
/* --------------------------
|
|
Lastly the steering is added
|
|
straight on the output
|
|
TODO: Activate when implemented
|
|
-------------------------- */
|
|
float steering(0.0f); // This will come from remote
|
|
motorL.setSpeed(controlOutput - steering);
|
|
motorR.setSpeed(controlOutput + steering);
|
|
|
|
// Blink LED at 1hz
|
|
static int i = 0;
|
|
i++;
|
|
if (i > 100)
|
|
{
|
|
i = 0;
|
|
ledOrg = !ledOrg;
|
|
}
|
|
}
|
|
|
|
// This context just pulses the blue LED
|
|
void pulseLedContext()
|
|
{
|
|
while (true)
|
|
{
|
|
float in, out;
|
|
|
|
for (in = 0; in < 2*PI; in = in + PI/50)
|
|
{
|
|
out = sin(in) + 0.5;
|
|
// We cannot set pulsewidth or period due to
|
|
// sharing timer with motor outputs. "write"
|
|
// instead sets the dutycycle in range 0-1
|
|
ledBlue.write(out);
|
|
Thread::wait(10);
|
|
}
|
|
}
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
// main() runs in its own thread
|
|
int main() {
|
|
|
|
// MPU startup at 100hz
|
|
if(imu.init(10,BITS_DLPF_CFG_188HZ)){
|
|
printf("\nCouldn't initialize MPU6000 via SPI!");
|
|
}
|
|
|
|
wait(0.1);
|
|
// Set IMU scale
|
|
int accScale = imu.set_acc_scale(BITS_FS_16G);
|
|
wait(0.1);
|
|
int gyroScale = imu.set_gyro_scale(BITS_FS_2000DPS);
|
|
wait(0.1);
|
|
|
|
// Calibrate and Trim acc & gyro
|
|
bool calibrationResult = imu.resetOffset_gyro();
|
|
imu.calib_acc(0);
|
|
calibrationResult = imu.resetOffset_acc();
|
|
|
|
// Enable/Activate the Gyro interrupt
|
|
imu.enableInterrupt();
|
|
|
|
// Start the timer used by the control loop
|
|
timer.start(); // Used to calc dT
|
|
|
|
/*-------------- Visible start sequence ------------*/
|
|
// Start sweeping the arm
|
|
servo.sweep(0.0, 1, 2);
|
|
|
|
// Start the pulsing blue led
|
|
Thread ledPulseThread;
|
|
ledPulseThread.start(callback(&pulseLedContext));
|
|
|
|
// Create realtime eventhandler for control loop
|
|
Thread eventThread(osPriorityRealtime);
|
|
eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
|
|
|
|
// Attach gyro interrupt to add a control event
|
|
gyroINT.rise(queue.event(&controlFunc));
|
|
|
|
// Enable motor controllers (Will power the motors with no movement)
|
|
motorL.enable();
|
|
motorR.enable();
|
|
motorL.setDirection(1);
|
|
motorR.setDirection(-1);
|
|
|
|
Thread::wait(1000);
|
|
|
|
// Servo Nod to tell us that we are done
|
|
servo.nod();
|
|
|
|
servo.setPosition(-0.2);
|
|
|
|
wait(osWaitForever);
|
|
} |