diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | inc/HoverBitController.h (renamed from source/HoverBitController.h) | 31 | ||||
-rw-r--r-- | inc/Screen.h (renamed from source/Screen.h) | 6 | ||||
-rw-r--r-- | source/HoverBitController.cpp | 61 | ||||
-rw-r--r-- | source/main.cpp | 147 |
5 files changed, 141 insertions, 107 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ac32e4b..879568c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ sbeParseJson(codal codal_json) set(CODAL_APP_OUTPUT_DIR ".") set(CODAL_APP_SOURCE_DIR "source") +set(CODAL_APP_INCLUDE_DIR "inc") if("${codal.application}" STRGREATER "") set(CODAL_APP_SOURCE_DIR "${codal.application}") @@ -231,7 +232,7 @@ if("${device.libraries}" STRGREATER "") endif() #finally, find sources and includes of the application, and create a target. -RECURSIVE_FIND_DIR(INCLUDE_DIRS "./inc" "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.h") +RECURSIVE_FIND_DIR(INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/${CODAL_APP_INCLUDE_DIR}" "*.h") # *.c?? only catches .cpp, not .c, so let's be precise RECURSIVE_FIND_FILE(SOURCE_FILES "${PROJECT_SOURCE_DIR}/${CODAL_APP_SOURCE_DIR}" "*.cpp") diff --git a/source/HoverBitController.h b/inc/HoverBitController.h index 4963cd1..80ad173 100644 --- a/source/HoverBitController.h +++ b/inc/HoverBitController.h @@ -27,12 +27,20 @@ DEALINGS IN THE SOFTWARE. #include <MicroBit.h> -#define BATTERY_LOW_LIMIT 3500 +#define BATTERY_LOW_LIMIT 3500 +#define FSAFE_TLIM_THROTTLE 1000 // When to cut the throttle +#define FSAFE_TLIM_ARM 5000 // When to disarm +extern MicroBit uBit; + +/** + * This class can be used to interface with a AirBit card for controlling a HOVER:BIT kit. + * + * A lot of the features of the airbit is ignored here and made easy to understand if all + * you want to do is use it for a hoverbit. + */ class HoverBitController { private: - MicroBit* uBit; - int buzzer; int servo_1; int arm; @@ -40,26 +48,25 @@ class HoverBitController { int pitch; int yaw; int throttle; - int failSafeC; + unsigned long lastReceiveTime; bool mainController; bool batteryEmpty; int batteryMilliVolt; float batteryFactor; - public: - void init(MicroBit* _uBit); - void failSafe(void); - unsigned int getBatteryVoltage(void); + bool failSafe(void); void AirBit(int Pitch,int Arm,int Roll,int Throttle,int Yaw,int Aux1,int Aux2); + + public: + void init(); + unsigned int GetBatteryVoltage(void); void HoverControl(); int Throttle(); void Throttle(int _throttle); - int Servo1(); - void Servo1(int _servo1); - int Roll(); - void Roll(int _roll); + int Rudder(); + void Rudder(int _rudder); bool Arm(); void Arm(bool _arm); bool BatteryEmpty(); diff --git a/source/Screen.h b/inc/Screen.h index b60ba2b..e141a86 100644 --- a/source/Screen.h +++ b/inc/Screen.h @@ -67,6 +67,12 @@ static const char* const strBattLevel[] = { 000,255,255,255,000\n\ 000,255,255,255,000\n" }; +const char* const bluetoothSymbol = "\ + 000,000,255,255,000\n\ + 255,000,255,000,255\n\ + 000,255,255,255,000\n\ + 255,000,255,000,255\n\ + 000,000,255,255,000\n"; void plotYLine(MicroBit *uBit, int y1, int y2, int x); diff --git a/source/HoverBitController.cpp b/source/HoverBitController.cpp index 65ebf17..df9893e 100644 --- a/source/HoverBitController.cpp +++ b/source/HoverBitController.cpp @@ -22,7 +22,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include <MicroBit.h> #include "HoverBitController.h" /** @@ -31,8 +30,7 @@ DEALINGS IN THE SOFTWARE. * * @param _uBit the MicroBit instance */ -void HoverBitController::init(MicroBit* _uBit) { - uBit = _uBit; +void HoverBitController::init() { mainController = false; batteryEmpty = false; batteryMilliVolt = 3700; @@ -44,37 +42,43 @@ void HoverBitController::init(MicroBit* _uBit) { roll = 0; yaw = 0; throttle = 0; - failSafeC = 0; + lastReceiveTime = uBit.systemTime(); /* I am not completly sure what this does, but it seems to me like this is putting the air:bit board in some kind of "bind-mode", on the spec-sheet there isn't any documentation for what 20 pulses means tho... */ - (*uBit).sleep(100); + uBit.sleep(100); int o; for (o = 0; o < 20; o++) { AirBit(-90, 0, 90, 0, 90, 0, 0); - (*uBit).sleep(20); + uBit.sleep(20); } } /** * This is not implemented yet. */ -void HoverBitController::failSafe(void) { - // throttle = 0; - // roll = 0; - // yaw = 0; - // arm = 0; - // failSafeC++; +bool HoverBitController::failSafe(void) { + unsigned long deltaReceiveTime = uBit.systemTime() - lastReceiveTime; + if (deltaReceiveTime > FSAFE_TLIM_THROTTLE) { + Throttle(0); + Rudder(0); + AirBit(0, arm, 0, throttle, roll, roll + 45, servo_1); + } + if (deltaReceiveTime > FSAFE_TLIM_ARM) { + Arm(0); + AirBit(0, arm, 0, throttle, roll, roll + 45, servo_1); + } + return (deltaReceiveTime > FSAFE_TLIM_THROTTLE) || (deltaReceiveTime > FSAFE_TLIM_ARM); } /** * This returns the current voltage of the battery. */ -unsigned int HoverBitController::getBatteryVoltage() { +unsigned int HoverBitController::GetBatteryVoltage() { float batteryFactor = 4.42; int batteryMilliVolt = 3700; - return ((float)((&(*uBit).io.P0)->getAnalogValue()) * batteryFactor * 0.05) + ((float)batteryMilliVolt * 0.95); + return ((float)((&uBit.io.P0)->getAnalogValue()) * batteryFactor * 0.05) + ((float)batteryMilliVolt * 0.95); } /** @@ -137,14 +141,16 @@ void HoverBitController::AirBit(int Pitch,int Arm,int Roll,int Throttle,int Yaw, buf[13] = aux1S & 255; buf[14] = (6 << 2) | ((aux2S >> 8) & 3); buf[15] = aux2S & 255; - (*uBit).serial.send(buf, 16, SYNC_SPINWAIT); + uBit.serial.send(buf, 16, SYNC_SPINWAIT); } /** * Method that sends commands with the current values for all parameters. */ void HoverBitController::HoverControl() { - AirBit(0, arm, 0, throttle, roll, roll + 45, servo_1); + if (!failSafe()) { + AirBit(0, arm, 0, throttle, roll, roll + 45, servo_1); + } } int HoverBitController::Throttle() { @@ -154,28 +160,25 @@ void HoverBitController::Throttle(int _throttle) { if (_throttle > 99) { throttle = 100; } else if (_throttle < 0) { throttle = 0; } else { throttle = _throttle; } + lastReceiveTime = uBit.systemTime(); } -int HoverBitController::Servo1() { - return servo_1; -} -void HoverBitController::Servo1(int _servo1) { - if (_servo1 > 180) { servo_1 = 180; } - else if (_servo1 < 0) { servo_1 = 0; } - else { servo_1 = _servo1; } -} -int HoverBitController::Roll() { +int HoverBitController::Rudder() { + // The AirBit uses the roll parameter to control the hoverbit's rudder. return roll; } -void HoverBitController::Roll(int _roll) { - if (_roll > 90) { roll = 90; } - else if (_roll < -90) { roll = -90; } - else { roll = _roll; } +void HoverBitController::Rudder(int _rudder) { + // The AirBit uses the roll parameter to control the hoverbit's rudder. + if (_rudder > 90) { roll = 90; } + else if (_rudder < -90) { roll = -90; } + else { roll = _rudder; } + lastReceiveTime = uBit.systemTime(); } bool HoverBitController::Arm() { return (arm == 1); } void HoverBitController::Arm(bool _arm) { arm = (int)_arm; + lastReceiveTime = uBit.systemTime(); } bool HoverBitController::BatteryEmpty() { return batteryEmpty; diff --git a/source/main.cpp b/source/main.cpp index caf8ffe..de11801 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -27,6 +27,9 @@ DEALINGS IN THE SOFTWARE. #include "HoverBitController.h" #include "Screen.h" +#define VERSION "0.0.1" +#define BLE_UART_DELIM ":" + MicroBit uBit; MicroBitUARTService *uart; HoverBitController controller; @@ -44,68 +47,64 @@ DisplayMainScreenMode displayMainScreenMode = GRAPHS; void onConnected(MicroBitEvent) { bConnected = 1; uBit.audio.soundExpressions.play(ManagedString("giggle")); +} - // mobile app will send ASCII strings terminated with the colon character - ManagedString eom(":"); +void onDisconnected(MicroBitEvent) { + bConnected = 0; + uBit.audio.soundExpressions.play(ManagedString("sad")); +} - while (bConnected) { - ManagedString msg = uart->readUntil(eom); - int length = msg.length(); - const char* command = msg.toCharArray(); +void onDelim(MicroBitEvent) { + ManagedString msg = uart->readUntil(BLE_UART_DELIM); - ManagedString accString("ACC:"); + int length = msg.length(); + const char* command = msg.toCharArray(); - char cCommand = command[0]; - char cChar; - int startI = 1; - bool bEOC = false; - int valLength = 0; + ManagedString accString("ACC:"); - for (int i = 1; i < length; i++) { - cChar = command[i]; + char cCommand = command[0]; + char cChar; + int startI = 1; + bool bEOC = false; + int valLength = 0; - if (i >= length - 1) { - bEOC = true; - valLength = i - startI + 1; - } else if (cChar == 'R' || cChar == 'T' || cChar == 'A' || cChar == 'S') { - bEOC = true; - valLength = i - startI; - } + for (int i = 1; i < length; i++) { + cChar = command[i]; - if (bEOC) { - /* We will just assume that we end up with a valid integer here */ - int value = atoi(msg.substring(startI, startI + valLength).toCharArray()); - - if (cCommand == 'R') { - controller.Roll(value); - accString = accString + ManagedString("R") + ManagedString(controller.Roll()); - } else if (cCommand == 'T') { - controller.Throttle(value); - accString = accString + ManagedString("T") + ManagedString(controller.Throttle()); - } else if (cCommand == 'A') { - controller.Arm(value == 1); - accString = accString + ManagedString("A") + ManagedString(controller.Arm()); - } else if (cCommand == 'S') { - controller.Servo1(value); - accString = accString + ManagedString("S") + ManagedString(controller.Servo1()); - } + if (i >= length - 1) { + bEOC = true; + valLength = i - startI + 1; + } else if (cChar == 'R' || cChar == 'T' || cChar == 'A' || cChar == 'S') { + bEOC = true; + valLength = i - startI; + } - cCommand = cChar; - startI = i+1; - bEOC = false; + if (bEOC) { + /* We will just assume that we end up with a valid integer here */ + int value = atoi(msg.substring(startI, startI + valLength).toCharArray()); + + if (cCommand == 'R') { + controller.Rudder(value); + accString = accString + ManagedString("R") + ManagedString(controller.Rudder()); + } else if (cCommand == 'T') { + controller.Throttle(value); + accString = accString + ManagedString("T") + ManagedString(controller.Throttle()); + } else if (cCommand == 'A') { + controller.Arm(value == 1); + accString = accString + ManagedString("A") + ManagedString(controller.Arm()); + } else { + // We ignore it :) } + + cCommand = cChar; + startI = i+1; + bEOC = false; } - // @TODO: Move this to the hoverControl module, we would rather like to have that there, or in the main loop. - // it could also be in the same clause as the batttery sending, but we might want to have it more - // dependent on actual received values. - uart->send(accString); } - -} - -void onDisconnected(MicroBitEvent) { - bConnected = 0; - uBit.audio.soundExpressions.play(ManagedString("sad")); + // @TODO: Move this to the hoverControl module, we would rather like to have that there, or in the main loop. + // it could also be in the same clause as the batttery sending, but we might want to have it more + // dependent on actual received values. + uart->send(accString); } void iconBatteryDead() { @@ -195,7 +194,25 @@ void mainScreen() { bool bDelayElapsed = (uBit.systemTime() - tmpTimer) > 1000; if (bDelayElapsed) { tmpTimer = uBit.systemTime(); } - if (bDelayElapsed && bConnected) { uart->send(ManagedString("B:") + ManagedString(batteryMilliVolt)); } + if (bConnected) { + if (bDelayElapsed) { + uart->send(ManagedString("B:") + ManagedString(batteryMilliVolt)); + } + } else { + if (bDelayElapsed) { + bBLEIndicator = !bBLEIndicator; + uBit.display.clear(); + if (bBLEIndicator) { + MicroBitImage img(bluetoothSymbol); + uBit.display.print(img); + } else { + // Need to actually see this to know if I want to flash only + // blank screen or with battery. + //batteryLevelFullScreen(); + } + } + return; + } switch (displayMainScreenMode) { case OFF: @@ -216,23 +233,19 @@ void mainScreen() { } break; } - - if (bConnected) { - uBit.display.image.setPixelValue(0, 0, 255); - } else { - if (bDelayElapsed) { bBLEIndicator = !bBLEIndicator; } - if (bBLEIndicator) { - uBit.display.image.setPixelValue(0, 0, 0); - } else { - uBit.display.image.setPixelValue(0, 0, 255); - } - } } void onButtonA_press(MicroBitEvent e) { + nextMainScreenDisplayMode(); } void onButtonB_press(MicroBitEvent e) { } +void onButtonAB_press(MicroBitEvent e) { + DisplayMainScreenMode tmpDMode = displayMainScreenMode; + displayMainScreenMode = OFF; + uBit.display.scroll(VERSION); + displayMainScreenMode = tmpDMode; +} int main() { uBit.init(); @@ -245,23 +258,27 @@ int main() { /* Initialize hover:bit controller module * the init procedure have to be run within 100ms after air:bit power up */ - controller.init(&uBit); + controller.init(); // Setup listeners uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_CONNECTED, onConnected); uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, onDisconnected); + uBit.messageBus.listen(MICROBIT_ID_BLE_UART, MICROBIT_UART_S_EVT_DELIM_MATCH, onDelim); + uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonA_press); uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB_press); + uBit.messageBus.listen(MICROBIT_ID_BUTTON_AB, MICROBIT_BUTTON_EVT_CLICK, onButtonAB_press); // uartService // Note GATT table size increased from default in MicroBitConfig.h // #define MICROBIT_SD_GATT_TABLE_SIZE 0x500 uart = new MicroBitUARTService(*uBit.ble, 32, 32); + uart->eventOn(BLE_UART_DELIM); uBit.audio.soundExpressions.play(ManagedString("hello")); while (1) { - batteryMilliVolt = controller.getBatteryVoltage(); + batteryMilliVolt = controller.GetBatteryVoltage(); if (uBit.logo.isPressed()) { if (!bCapLogoIsPressed) { |