-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from Vinz1911/feature/refactoring-2021
refactoring + compatibility for latest spike/ri firmware
- Loading branch information
Showing
7 changed files
with
304 additions
and
695 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,68 @@ | ||
# PrimePowerUP | ||
# PrimePoweredUP | ||
|
||
`PrimePoweredUP` contains a library for Lego Spike Prime to connect to PoweredUP Remote (Handset) over BLE. | ||
The core is based on the MicroPython ubluetooth low level api. | ||
|
||
### Compatibility | ||
- Works with the latest version of `Spike Prime` and `Mindstorms Robot Inventor`. | ||
|
||
### Description | ||
- the library use lot of memory. i recommend to pre compile the library from `remote/control` and install it on the prime hub. | ||
a very good way to do that is using this awesome tool: [Spike Tools](https://github.com/XenseEducation/spiketools-release/releases) | ||
pre compiled library can also be downloaded in releases section: [Pre-Compiled Library](https://github.com/Vinz1911/PrimePowerUP/releases) | ||
|
||
- there are two examples in `examples` folder. The first one shows how to light up dot's on Prime Hub and the second one | ||
shows how to control a motor pair with the remote. examples are created by using the control.py installed as pre compiled lib | ||
(it's also possible to copy all together and load it on the hub) | ||
|
||
### Known Problems: | ||
- the ubluetooth class has some problems with event loop based functions from Lego. This means, if you run a event loop based | ||
function within the button pressed callback, the entire hub will freeze. This is currently not possible to fix that, maybe with | ||
a new firmare which supports uasyncio library. **Event based functions ?!** are functions like playing sound until end, wait for or | ||
motor functions like run_to_position or run_for_degrees and so on. | ||
- the library is build for the use inside the `Python VM`. This means you need the advanced Python setup for the Spike Prime. | ||
- for an easy start with the advanced Python setup, it's recommended to use VSCode with this plugin: [Spike Prime/RI Extension](https://marketplace.visualstudio.com/items?itemName=PeterStaev.lego-spikeprime-mindstorms-vscode). | ||
- **WARNING: LIBRARY DOES NOT WORK WITH THE REGULAR PYTHON SETUP** | ||
- examples can be found in `./examples` directory. | ||
|
||
### Usage | ||
- The pre-compiled library is inside of the `./remote` directory, it's recommended to copy the library inside the `./spike` directory | ||
of the Spike Prime. You can do this by using a script or with [rshell](https://github.com/dhylands/rshell). | ||
|
||
```bash | ||
# example using rshell | ||
Connecting to /dev/cu.usbmodem3382397933381 (buffer-size 512)... | ||
Trying to connect to REPL connected | ||
Retrieving sysname ... LEGO Technic Large Hub | ||
... | ||
Welcome to rshell. Use Control-D (or the exit command) to exit rshell. | ||
|
||
# copy file to hub | ||
/remote> cp ./remote.mpy /pyboard/spike/ | ||
``` | ||
#### Example | ||
```python | ||
from runtime import VirtualMachine | ||
from spike import PrimeHub, MotorPair | ||
from spike.remote import Remote, Buttons | ||
from util.print_override import spikeprint as print | ||
|
||
# create remote | ||
remote = Remote() | ||
|
||
|
||
async def on_start(vm, stack): | ||
print("connecting...") | ||
await remote.connect() # wait for connecting establishment | ||
print("connected") | ||
|
||
while True: | ||
buttons = remote.pressed() # read pressed buttons | ||
print(buttons) # Output is a tuple for example: (LEFT_PLUS, RIGHT_PLUS, CENTER) | ||
yield | ||
|
||
|
||
async def on_cancel(vm, stack): | ||
remote.cancel() # disconnect if the program exit's | ||
|
||
|
||
def setup(rpc, system, stop): | ||
vm = VirtualMachine(rpc, system, stop, "3f157bda4908") | ||
vm.register_on_start("f76afdd318a1", on_start) | ||
vm.register_on_button("accda9ebca74", on_cancel, "center", "pressed") | ||
return vm | ||
``` | ||
|
||
### Known Issues: | ||
- The library uses an async connection process, this is why we need the python vm for the usage. performance is also better. | ||
- The library uses internally ble notification service, sometimes the hub needs a restart to make this work (if tuple is empty on button press). | ||
- I didn't found a good way to disconnect the remote if you reach the end of a program (there is currently no way to run `cleanup` code on program's end). fallback solution is to use the `Start/Stop` button. | ||
So just for clarification: **remote needs to be reconnected on program start**. if your program is exited and the remote is still connected | ||
you need to unpair the remote by holding the green button until it's unpaired. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,34 @@ | ||
from spike import PrimeHub, LightMatrix, Button, StatusLight, ForceSensor, MotionSensor, Speaker, ColorSensor, App, DistanceSensor, Motor, MotorPair | ||
from spike.control import wait_for_seconds, wait_until, Timer | ||
from remote.control import PoweredUPRemote, PoweredUPColors, PoweredUPButtons | ||
from runtime import VirtualMachine | ||
from spike import PrimeHub | ||
from spike.remote import Remote, Buttons | ||
from util.print_override import spikeprint as print | ||
|
||
""" | ||
LEGO(R) SPIKE PRIME + POWERED UP | ||
-------------------------------- | ||
# create remote | ||
remote = Remote() | ||
|
||
This is a basic example: | ||
This example let light up different dot's on | ||
a prime/inventor hub for different buttons pressed | ||
on the powered up remote | ||
""" | ||
|
||
async def on_start(vm, stack): | ||
hub = PrimeHub() | ||
print("connecting...") | ||
await remote.connect() | ||
print("connected") | ||
hub.status_light.on('blue') | ||
|
||
def on_connect(): | ||
""" | ||
callback on connect | ||
""" | ||
hub.status_light.on("blue") | ||
while True: | ||
buttons = remote.pressed() | ||
if Buttons.LEFT in buttons: hub.light_matrix.set_pixel(0, 0, brightness=100) | ||
if Buttons.LEFT not in buttons: hub.light_matrix.set_pixel(0, 0, brightness=0) | ||
if Buttons.RIGHT in buttons: hub.light_matrix.set_pixel(0, 1, brightness=100) | ||
if Buttons.RIGHT not in buttons: hub.light_matrix.set_pixel(0, 1, brightness=0) | ||
yield | ||
|
||
|
||
def on_disconnect(): | ||
""" | ||
callback on disconnect | ||
""" | ||
hub.status_light.on("white") | ||
async def on_cancel(vm, stack): | ||
remote.cancel() | ||
|
||
|
||
def on_button(button): | ||
""" | ||
callback on button press | ||
:param button: button id | ||
""" | ||
hub.light_matrix.off() | ||
if button == PoweredUPButtons.LEFT_PLUS: | ||
hub.light_matrix.set_pixel(0, 0, brightness=100) | ||
elif button == PoweredUPButtons.LEFT_RED: | ||
hub.light_matrix.set_pixel(1, 0, brightness=100) | ||
elif button == PoweredUPButtons.LEFT_MINUS: | ||
hub.light_matrix.set_pixel(2, 0, brightness=100) | ||
elif button == PoweredUPButtons.RIGHT_PLUS: | ||
hub.light_matrix.set_pixel(3, 0, brightness=100) | ||
elif button == PoweredUPButtons.RIGHT_RED: | ||
hub.light_matrix.set_pixel(4, 0, brightness=100) | ||
elif button == PoweredUPButtons.RIGHT_MINUS: | ||
hub.light_matrix.set_pixel(0, 1, brightness=100) | ||
elif button == PoweredUPButtons.LEFT_PLUS_RIGHT_PLUS: | ||
hub.light_matrix.set_pixel(0, 2, brightness=100) | ||
elif button == PoweredUPButtons.RELEASED: | ||
hub.light_matrix.off() | ||
else: | ||
hub.light_matrix.off() | ||
|
||
|
||
# set up hub | ||
hub = PrimeHub() | ||
|
||
# create remote and connect | ||
remote = PoweredUPRemote() | ||
remote.debug = True | ||
remote.on_connect(callback=on_connect) | ||
remote.on_disconnect(callback=on_disconnect) | ||
remote.on_button(callback=on_button) | ||
remote.connect() | ||
def setup(rpc, system, stop): | ||
vm = VirtualMachine(rpc, system, stop, "3f157bda4908") | ||
vm.register_on_start("f76afdd318a1", on_start) | ||
vm.register_on_button("accda9ebca74", on_cancel, "center", "pressed") | ||
return vm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,40 @@ | ||
from spike import PrimeHub, LightMatrix, Button, StatusLight, ForceSensor, MotionSensor, Speaker, ColorSensor, App, DistanceSensor, Motor, MotorPair | ||
from spike.control import wait_for_seconds, wait_until, Timer | ||
from remote.control import PoweredUPRemote, PoweredUPColors, PoweredUPButtons | ||
|
||
""" | ||
LEGO(R) SPIKE PRIME + POWERED UP | ||
-------------------------------- | ||
This is a basic example: | ||
This example let control a motor pair | ||
with the powered up remote | ||
""" | ||
|
||
|
||
def on_connect(): | ||
""" | ||
callback on connect | ||
""" | ||
hub.status_light.on("blue") | ||
|
||
|
||
def on_disconnect(): | ||
""" | ||
callback on disconnect | ||
""" | ||
hub.status_light.on("white") | ||
motor_pair.stop() | ||
|
||
|
||
def on_button(button): | ||
""" | ||
callback on button press | ||
:param button: button id | ||
""" | ||
if button == PoweredUPButtons.RIGHT_PLUS: | ||
motor_pair.start(speed=75) | ||
elif button == PoweredUPButtons.RIGHT_MINUS: | ||
motor_pair.start(speed=-75) | ||
elif button == PoweredUPButtons.LEFT_PLUS_RIGHT_PLUS: | ||
motor_pair.start(steering=-45, speed=75) | ||
elif button == PoweredUPButtons.LEFT_MINUS_RIGHT_PLUS: | ||
motor_pair.start(steering=45, speed=75) | ||
elif button == PoweredUPButtons.LEFT_MINUS_RIGHT_MINUS: | ||
motor_pair.start(steering=45, speed=-75) | ||
elif button == PoweredUPButtons.LEFT_PLUS_RIGHT_MINUS: | ||
motor_pair.start(steering=-45, speed=-75) | ||
elif button == PoweredUPButtons.RELEASED: | ||
motor_pair.stop() | ||
else: | ||
motor_pair.stop() | ||
|
||
|
||
# set up hub | ||
hub = PrimeHub() | ||
|
||
# set up motors | ||
motor_pair = MotorPair('A', 'B') | ||
motor_pair.set_stop_action('coast') | ||
|
||
# create remote and connect | ||
remote = PoweredUPRemote() | ||
remote.on_connect(callback=on_connect) | ||
remote.on_disconnect(callback=on_disconnect) | ||
remote.on_button(callback=on_button) | ||
remote.connect() | ||
from runtime import VirtualMachine | ||
from spike import PrimeHub, MotorPair | ||
from spike.remote import Remote, Buttons | ||
from util.print_override import spikeprint as print | ||
|
||
# create remote | ||
remote = Remote() | ||
|
||
|
||
async def on_start(vm, stack): | ||
hub = PrimeHub() | ||
pair = MotorPair('A', 'B') | ||
pair.set_stop_action('coast') | ||
|
||
print("connecting...") | ||
await remote.connect() | ||
print("connected") | ||
hub.status_light.on('blue') | ||
|
||
while True: | ||
buttons = remote.pressed() | ||
if buttons == (Buttons.RIGHT_PLUS,): pair.start(speed=65) | ||
elif buttons == (Buttons.RIGHT_MINUS,): pair.start(speed=-65) | ||
elif buttons == (Buttons.LEFT_MINUS, Buttons.RIGHT_PLUS): pair.start(speed=65, steering=-45) | ||
elif buttons == (Buttons.LEFT_PLUS, Buttons.RIGHT_PLUS): pair.start(speed=65, steering=45) | ||
elif buttons == (Buttons.LEFT_MINUS, Buttons.RIGHT_MINUS): pair.start(speed=-65, steering=-45) | ||
elif buttons == (Buttons.LEFT_PLUS, Buttons.RIGHT_MINUS): pair.start(speed=-65, steering=45) | ||
else: pair.stop() | ||
yield | ||
|
||
|
||
async def on_cancel(vm, stack): | ||
remote.cancel() | ||
|
||
|
||
def setup(rpc, system, stop): | ||
vm = VirtualMachine(rpc, system, stop, "3f157bda4908") | ||
vm.register_on_start("f76afdd318a1", on_start) | ||
vm.register_on_button("accda9ebca74", on_cancel, "center", "pressed") | ||
return vm |
Oops, something went wrong.