Almost complete source code sample. I've tweaked how I decided to do this. The Skateboard class is now the master. It contains an IMU and AmpFlow class to do the balancing and motor control.
Things of note, isUserOnSkateboard and doesComputerHaveEnoughPower are delegates. Tje power checks and UI updates are functions that update every so many cycles. Why do this? Updating an interface and do extra power checks could be expensive in time. By doing it every 1000 cycles or whatever I pick, I get feedback data but not the constant overhead of a task that isn't needed.
From my Skateboard class
public void StartSelfBalancing()
{
// safety checks, Does computer have power, Is User on skateboard
if (isUserOnSkateboard == null || doesComputerHaveEnoughPower == null)
return;
doesComputerHaveEnoughPower(); // first time full check
internalDoesMotorControllerHaveEnoughPower();
if (!DoesComputerHaveEnoughPower()) // does computer actually have enough power to operate safely?
return;
// lets wait for the user to get on the skateboard.
while (!IsUserOnSkateboard())
Thread.Sleep(50);
motorController.OpenComPort();
setupMotorController();
imu.StartImu();
ImuData data = new ImuData();
while (IsUserOnSkateboard() && hasEnoughPower(data))
{
data = imu.GetImuData();
// todo: do awesome magical calculations
int leftMotorPower = 0; // todo: properly calculate it
int rightMotorPower = 0; // todo: properly calculate it
motorController.SetMotorSpeed(Core.Skateboard.Types.Enums.MotorChannel.A, leftMotorPower);
motorController.SetMotorSpeed(Core.Skateboard.Types.Enums.MotorChannel.B, rightMotorPower);
UpdateUserInterface(data);
}
// be sure motors are off
motorController.SetMotorSpeed(Core.Skateboard.Types.Enums.MotorChannel.A, 0);
motorController.SetMotorSpeed(Core.Skateboard.Types.Enums.MotorChannel.B, 0);
motorController.CloseComPort();
imu.StopImu();
}
I'll post some pictures from this weekends work on the frame.