diff --git a/.github/makecode/blocks.png b/.github/makecode/blocks.png new file mode 100644 index 0000000..6c62415 Binary files /dev/null and b/.github/makecode/blocks.png differ diff --git a/README.md b/README.md index 3815800..0a7a6bd 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,14 @@ +# Micro:Bit Compass +**a simple compass made for the Micro:Bit** -> Open this page at [https://buzz-lightsnack-2007.github.io/microbit_compass/](https://buzz-lightsnack-2007.github.io/microbit_compass/) - -## Use as Extension - -This repository can be added as an **extension** in MakeCode. - -* open [https://makecode.microbit.org/](https://makecode.microbit.org/) -* click on **New Project** -* click on **Extensions** under the gearwheel menu -* search for **https://github.com/buzz-lightsnack-2007/microbit_compass** and import - -## Edit this project ![Build status badge](https://github.com/buzz-lightsnack-2007/microbit_compass/workflows/MakeCode/badge.svg) - -To edit this repository in MakeCode. - -* open [https://makecode.microbit.org/](https://makecode.microbit.org/) -* click on **Import** then click on **Import URL** -* paste **https://github.com/buzz-lightsnack-2007/microbit_compass** and click import +## Edit this project +To edit this repository in MakeCode: +1. Open [Microsoft MakeCode](https://makecode.microbit.org/). +2. Click on **Import** then click on **Import URL**. +3. Paste **https://gitdab.com/buzz-lightsnack-2007/MicroBit_Compass** and click import. ## Blocks preview - -This image shows the blocks code from the last commit in master. -This image may take a few minutes to refresh. +This image shows the blocks code from the last commit in master, although it may take a few minutes to refresh. ![A rendered view of the blocks](https://github.com/buzz-lightsnack-2007/microbit_compass/raw/master/.github/makecode/blocks.png) diff --git a/main.blocks b/main.blocks index 9720ca4..d605f78 100644 --- a/main.blocks +++ b/main.blocks @@ -1,4 +1 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..5885ff9 --- /dev/null +++ b/main.py @@ -0,0 +1,217 @@ +# compass system information +compass_info = { + 'version': 2022.1211 +} + +# compass data and settings +compass_data = { + 'configuration': { + 'modes': { + 'previous': '', + 'current': 'measurement', + 'measurement': 'number' + }, + 'loading': False, + 'errored': False + }, + 'data': { + 'measurement': 0, + 'direction': ArrowNames.NORTH + } +} + +def compass_calibrate(): + """ + This triggers calibration. + + Parameters: none + Returns: none + """ + # Enter calibration mode, saving the previous mode. + compass_data['configuration']['modes']['previous'] = compass_data['configuration']['modes']['current'] + compass_data['configuration']['modes']['current'] = 'calibrate' + compass_data['configuration']['loading'] = True + + try: + # Calibrate the compass. + input.calibrate_compass() + + except: + # Warn that an error has occured. + compass_data['configuration']['errored'] = True + + finally: + # Exit calibration mode, restoring previous mode state. + compass_data['configuration']['loading'] = False + compass_data['configuration']['modes']['current'] = compass_data['configuration']['modes']['previous'] + compass_data['configuration']['modes']['previous'] = 'calibrate' + +def measurement_update(): + """ + Record the new measurement. + + Parameters: none + Returns: (float) heading in degrees + """ + + # Get the new measurement. + compass_data['data']['measurement'] = input.compass_heading() + + # Return the new measurement. + return(compass_data['data']['measurement']) + +def measurement_arrow_update(angle = None): + """ + Display the correct directional arrow. + + Parameters: + angle: (float) the heading + Returns: (enum) directional arrow + """ + + # Automatically fill the angle value, if it isn't provided. + if angle == None: + angle = compass_data['data']['measurement'] + + # Check if the angle is negative. If it is, get the correct positive equivalent. + if angle < 0: + angle = 360 + angle + + # Check which range it falls under. (Items are clockwise.) + direction_ranges = [ + (angle < 22.5) or (angle > 337.5), + (angle >= 22.5) and (angle <= 67.5), + (angle > 67.5) and (angle < 112.5), + (angle >= 112.5) and (angle <= 157.5), + (angle > 157.5) and (angle < 202.5), + (angle >= 202.5) and (angle <= 247.5), + (angle > 247.5) and (angle < 292.5), + (angle >= 292.5) and (angle <= 337.5) + ] + + # This is the list of directions. + directions = [ + ArrowNames.NORTH, + ArrowNames.NORTH_EAST, + ArrowNames.EAST, + ArrowNames.SOUTH_EAST, + ArrowNames.SOUTH, + ArrowNames.SOUTH_WEST, + ArrowNames.WEST, + ArrowNames.NORTH_WEST + ] + + # Set the correct direction. + compass_data['data']['direction'] = directions[direction_ranges.index(True)] + + # Return the direction. + return(compass_data['data']['direction']) + +def modes_measure_toggle(mode_measure_new = None): + """ + Toggle between the compass modes. + + Parameters: + mode_measure_new: (str) the new mode + Returns: (str) the new mode + """ + + # valid modes of measurement + mode_measure = ['number', 'arrow'] + mode_measure_current_index = mode_measure.index(compass_data['configuration']['modes']['measurement']) + + if mode_measure_new: + if mode_measure_new in mode_measure: + compass_data['configuration']['modes']['measurement'] = mode_measure_new + else: + mode_measure_current_index =+ 1 + + # Check if it exceeds the maximum. + if mode_measure_current_index >= len(mode_measure): + # If so, revert it back to zero. + mode_measure_current_index = 0 + + # Apply the new mode. + compass_data['configuration']['modes']['measurement'] = mode_measure[mode_measure_current_index] + + # Return the new mode. + return(compass_data['configuration']['modes']['measurement']) + + +def LEDs_update(status = None): + """ + Update the LEDs to display the corresponding pattern. + + Parameters: + status: (str) the pattern + Returns: none + """ + + # Check if there is a custom status input. + if status == None: + # Check if an error has occured. + if compass_data['configuration']['errored']: + status = 'error' + else: + # Otherwise, the current mode might be the basis. + status = compass_data['configuration']['modes']['current'] + + if (status == 'error'): + # Display that an error has occured simply through an exclamation mark. + basic.show_string("!") + + elif (status == 'measurement'): + # measurement display + + if compass_data['configuration']['modes']['measurement'] == 'number': + # Display the numerical data. + basic.show_number(compass_data['data']['measurement']) + if compass_data['configuration']['modes']['measurement'] == 'arrow': + # Display the arrow. + basic.show_arrow(compass_data['data']['direction']) + + + else: + # Display the loading screen while the current screen is still present. + while compass_data['configuration']['loading']: + # plot + for x in range(0,5): + led.plot(x, 2) + basic.pause(100) + # unplot + for x in range (0,5): + led.unplot(x, 2) + basic.pause(100) + + +def startup(): + """ + startup script + + Parameters: none + Returns: none + """ + + compass_calibrate() + +def on_forever(): + # Update the measurements. + measurement_update() + if compass_data['configuration']['modes']['measurement'] == 'arrow': + measurement_arrow_update() + + LEDs_update() + + +def on_button_pressed_ab(): + led.stop_animation() + compass_calibrate() + +def on_button_pressed_a(): + led.stop_animation() + modes_measure_toggle() + +input.on_button_pressed(Button.AB, on_button_pressed_ab) +input.on_button_pressed(Button.A, on_button_pressed_a) +basic.forever(on_forever) +startup() \ No newline at end of file diff --git a/main.ts b/main.ts index 8b13789..9c7735d 100644 --- a/main.ts +++ b/main.ts @@ -1 +1,214 @@ +// compass system information +let compass_info = { + "version" : 2022.1211, +} +// compass data and settings +let compass_data = { + "configuration" : { + "modes" : { + "previous" : "", + "current" : "measurement", + "measurement" : "number", + } + , + "loading" : false, + "errored" : false, + } + , + "data" : { + "measurement" : 0, + "direction" : ArrowNames.North, + } + , +} + +function compass_calibrate() { + /** + This triggers calibration. + + Parameters: none + Returns: none + + */ + // Enter calibration mode, saving the previous mode. + compass_data["configuration"]["modes"]["previous"] = compass_data["configuration"]["modes"]["current"] + compass_data["configuration"]["modes"]["current"] = "calibrate" + compass_data["configuration"]["loading"] = true + try { + // Calibrate the compass. + input.calibrateCompass() + } + catch (_) { + // Warn that an error has occured. + compass_data["configuration"]["errored"] = true + } + finally { + // Exit calibration mode, restoring previous mode state. + compass_data["configuration"]["loading"] = false + compass_data["configuration"]["modes"]["current"] = compass_data["configuration"]["modes"]["previous"] + compass_data["configuration"]["modes"]["previous"] = "calibrate" + } + +} + +function measurement_update() { + /** + Record the new measurement. + + Parameters: none + Returns: (float) heading in degrees + + */ + // Get the new measurement. + compass_data["data"]["measurement"] = input.compassHeading() + // Return the new measurement. + return compass_data["data"]["measurement"] +} + +function measurement_arrow_update(angle: any = null) { + /** + Display the correct directional arrow. + + Parameters: + angle: (float) the heading + Returns: (enum) directional arrow + + */ + // Automatically fill the angle value, if it isn't provided. + if (angle == null) { + angle = compass_data["data"]["measurement"] + } + + // Check if the angle is negative. If it is, get the correct positive equivalent. + if (angle < 0) { + angle = 360 + angle + } + + // Check which range it falls under. (Items are clockwise.) + let direction_ranges = [angle < 22.5 || angle > 337.5, angle >= 22.5 && angle <= 67.5, angle > 67.5 && angle < 112.5, angle >= 112.5 && angle <= 157.5, angle > 157.5 && angle < 202.5, angle >= 202.5 && angle <= 247.5, angle > 247.5 && angle < 292.5, angle >= 292.5 && angle <= 337.5] + // This is the list of directions. + let directions = [ArrowNames.North, ArrowNames.NorthEast, ArrowNames.East, ArrowNames.SouthEast, ArrowNames.South, ArrowNames.SouthWest, ArrowNames.West, ArrowNames.NorthWest] + // Set the correct direction. + compass_data["data"]["direction"] = directions[_py.py_array_index(direction_ranges, true)] + // Return the direction. + return compass_data["data"]["direction"] +} + +function modes_measure_toggle(mode_measure_new: any = null) { + /** + Toggle between the compass modes. + + Parameters: + mode_measure_new: (str) the new mode + Returns: (str) the new mode + + */ + // valid modes of measurement + let mode_measure = ["number", "arrow"] + let mode_measure_current_index = _py.py_array_index(mode_measure, compass_data["configuration"]["modes"]["measurement"]) + if (mode_measure_new) { + if (mode_measure.indexOf(mode_measure_new) >= 0) { + compass_data["configuration"]["modes"]["measurement"] = mode_measure_new + } + + } else { + mode_measure_current_index = +1 + // Check if it exceeds the maximum. + if (mode_measure_current_index >= mode_measure.length) { + // If so, revert it back to zero. + mode_measure_current_index = 0 + } + + // Apply the new mode. + compass_data["configuration"]["modes"]["measurement"] = mode_measure[mode_measure_current_index] + } + + // Return the new mode. + return compass_data["configuration"]["modes"]["measurement"] +} + +function LEDs_update(status: string = null) { + let x: number; + /** + Update the LEDs to display the corresponding pattern. + + Parameters: + status: (str) the pattern + Returns: none + + */ + // Check if there is a custom status input. + if (status == null) { + // Check if an error has occured. + if (compass_data["configuration"]["errored"]) { + status = "error" + } else { + // Otherwise, the current mode might be the basis. + status = compass_data["configuration"]["modes"]["current"] + } + + } + + if (status == "error") { + // Display that an error has occured simply through an exclamation mark. + basic.showString("!") + } else if (status == "measurement") { + // measurement display + if (compass_data["configuration"]["modes"]["measurement"] == "number") { + // Display the numerical data. + basic.showNumber(compass_data["data"]["measurement"]) + } + + if (compass_data["configuration"]["modes"]["measurement"] == "arrow") { + // Display the arrow. + basic.showArrow(compass_data["data"]["direction"]) + } + + } else { + // Display the loading screen while the current screen is still present. + while (compass_data["configuration"]["loading"]) { + // plot + for (x = 0; x < 5; x++) { + led.plot(x, 2) + basic.pause(100) + } + // unplot + for (x = 0; x < 5; x++) { + led.unplot(x, 2) + basic.pause(100) + } + } + } + +} + +function startup() { + /** + startup script + + Parameters: none + Returns: none + + */ + compass_calibrate() +} + +input.onButtonPressed(Button.AB, function on_button_pressed_ab() { + led.stopAnimation() + compass_calibrate() +}) +input.onButtonPressed(Button.A, function on_button_pressed_a() { + led.stopAnimation() + modes_measure_toggle() +}) +basic.forever(function on_forever() { + // Update the measurements. + measurement_update() + if (compass_data["configuration"]["modes"]["measurement"] == "arrow") { + measurement_arrow_update() + } + + LEDs_update() +}) +startup() diff --git a/pxt.json b/pxt.json index bcb9150..0bd4769 100644 --- a/pxt.json +++ b/pxt.json @@ -10,7 +10,8 @@ "files": [ "README.md", "main.blocks", - "main.ts" + "main.ts", + "main.py" ], "testFiles": [ "test.ts" @@ -23,5 +24,5 @@ "supportedTargets": [ "microbit" ], - "preferredEditor": "blocksprj" + "preferredEditor": "tsprj" }