Skip to content

Commit

Permalink
Merge branch 'master' of github.com:undera/pylgbst
Browse files Browse the repository at this point in the history
  • Loading branch information
undera committed Jul 18, 2018
2 parents 8f1e3cb + 16b1612 commit 7bfe700
Show file tree
Hide file tree
Showing 27 changed files with 834 additions and 422 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
*.iml
*.pyc
*.pyc
build
22 changes: 17 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
sudo: false
language: python
virtualenv:
system_site_packages: true

matrix:
include:
- os: linux
python: 2.7
- os: linux
python: 3.5
- os: linux
python: 3.6
python: 3.4

addons:
apt:
packages:
- libboost-python-dev
- libboost-thread-dev
- libbluetooth-dev

- libglib2.0-dev
- libdbus-1-dev
- libdbus-glib-1-dev
- libgirepository-1.0-1

- python-dbus
- python-gi
- python3-dbus
- python3-gi
install:
- pip install codecov gattlib
script: coverage run --source=. `which nosetests` . --nocapture
- pip install codecov nose-exclude gattlib pygatt gatt pexpect


script: coverage run --source=. `which nosetests` tests --nocapture --exclude-dir=examples

after_success:
- coverage report -m
- codecov
81 changes: 58 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Python library to interact with Move Hub
from pylgbst.comms_gatt import GattConnection# Python library to interact with Move Hub

_Move Hub is central controller block of [LEGO® Boost Robotics Set](https://www.lego.com/en-us/boost)._

In fact, Move Hub is just Bluetooth hardware, all manipulations are done with commands passed through Bluetooth Low Energy (BLE) wireless protocol. One of ways to issue these commands is to write Python program using this library.

Best way to start is to look into [`demo.py`](examples/demo.py) file, and run it (assuming you have installed library).

If you have Vernie assembled, you might run scripts from [`vernie`](examples/vernie/) directory.
If you have Vernie assembled, you might run scripts from [`examples/vernie`](examples/vernie/) directory.

Demonstrational videos:

Expand All @@ -29,17 +29,17 @@ Demonstrational videos:

## Usage

_Please note that it requires [gattlib](https://bitbucket.org/OscarAcena/pygattlib) to be installed, which is not supported on Windows._
_Please note that this library requires one of Bluetooth backend libraries to be installed, please read section [here](#general-notes) for details_

Install library like this:
```bash
pip install https://github.com/undera/pylgbst/archive/0.5.tar.gz
pip install https://github.com/undera/pylgbst/archive/0.6.tar.gz
```

Then instantiate MoveHub object and start invoking its methods. Following is example to just print peripherals detected on Hub:

```python
from pylgbst import MoveHub
from pylgbst.movehub import MoveHub

hub = MoveHub()

Expand Down Expand Up @@ -67,7 +67,7 @@ All these methods are synchronous by default, means method does not return until

An example:
```python
from pylgbst import MoveHub
from pylgbst.movehub import MoveHub
import time

hub = MoveHub()
Expand All @@ -92,7 +92,7 @@ hub.motor_external.stop()
Any motor allows to subscribe to its rotation sensor. Two sensor modes are available: rotation angle (`EncodedMotor.SENSOR_ANGLE`) and rotation speed (`EncodedMotor.SENSOR_SPEED`). Example:

```python
from pylgbst import MoveHub, EncodedMotor
from pylgbst.movehub import MoveHub, EncodedMotor
import time

def callback(angle):
Expand All @@ -112,7 +112,7 @@ MoveHub's internal tilt sensor is available through `tilt_sensor` field. There a
An example:

```python
from pylgbst import MoveHub, TiltSensor
from pylgbst.movehub import MoveHub, TiltSensor
import time

def callback(pitch, roll, yaw):
Expand Down Expand Up @@ -159,7 +159,7 @@ Distance works in range of 0-10 inches, with ability to measure last inch in hig
Simple example of subscribing to sensor:

```python
from pylgbst import MoveHub, ColorDistanceSensor
from pylgbst.movehub import MoveHub, ColorDistanceSensor
import time

def callback(clr, distance):
Expand Down Expand Up @@ -194,7 +194,7 @@ You can obtain colors are present as constants `COLOR_*` and also a map of avail
Additionally, you can subscribe to LED color change events, using callback function as shown in example below.

```python
from pylgbst import MoveHub, COLORS, COLOR_NONE, COLOR_RED
from pylgbst.movehub import MoveHub, COLORS, COLOR_NONE, COLOR_RED
import time

def callback(clr):
Expand All @@ -221,7 +221,7 @@ Tip: blinking orange color of LED means battery is low.
Note that `Button` class is not real `Peripheral`, as it has no port and not listed in `devices` field of Hub. Still, subscribing to button is done usual way:

```python
from pylgbst import MoveHub
from pylgbst.movehub import MoveHub

def callback(is_pressed):
print("Btn pressed: %s" % is_pressed)
Expand All @@ -235,7 +235,7 @@ hub.button.subscribe(callback)
`MoveHub` class has field `voltage` to subscribe to battery voltage status. Callback accepts single parameter with current value. The range of values is float between `0` and `1.0`. Every time data is received, value is also written into `last_value` field of `Voltage` object. Values less than `0.2` are known as lowest values, when unit turns off.

```python
from pylgbst import MoveHub
from pylgbst.movehub import MoveHub
import time

def callback(value):
Expand All @@ -249,19 +249,56 @@ print ("Value: " % hub.voltage.last_value)

### General Notes

#### Bluetooth Connection
There is optional parameter for `MoveHub` class constructor, accepting instance of `Connection` object. By default, it uses instance of `BLEConnection` to connect directly to Move Hub. You can specify instance of `DebugServerConnection` if you are using Debug Server (more details below).
#### Bluetooth Backend Prerequisites

If you want to specify name for Bluetooth interface to use on local computer, create instance of `BLEConnection` and call `connect(if_name)` method of connection. Then pass it to `MoveHub` constructor. Like this:
You have following options to install as Bluetooth backend:

- `pip install pygatt` - [pygatt](https://github.com/peplin/pygatt) lib, works on both Windows and Linux
- `pip install gatt` - [gatt](https://github.com/getsenic/gatt-python) lib, supports Linux, does not work on Windows
- `pip install gattlib` - [gattlib](https://bitbucket.org/OscarAcena/pygattlib) - supports Linux, does not work on Windows, requires `sudo`

_Please let author know if you have discovered any compatibility/preprequisite details, so we will update this section to help future users_

Depending on backend type, you might need Linux `sudo` to be used when running Python.

#### Bluetooth Connection Options
There is optional parameter for `MoveHub` class constructor, accepting instance of `Connection` object. By default, it will try to use whatever `get_connection_auto()` returns. You have several options to manually control that:

- use `pylgbst.get_connection_auto()` to attempt backend auto-choice, autodetect uses
- use `BlueGigaConnection()` - if you use BlueGiga Adapter (`pygatt` library prerequisite)
- use `GattConnection()` - if you use GattTool Backend on Linux (`gatt` library prerequisite)
- use `GattoolConnection()` - if you use GattTool Backend on Linux (`pygatt` library prerequisite)
- use `GattLibConnection()` - if you use GattTool Backend on Linux (`gattlib` library prerequisite)
- pass instance of `DebugServerConnection` if you are using [Debug Server](#debug-server) (more details below).

All the functions above have optional arguments to specify adapter name and MoveHub mac address. Please look function source code for details.

If you want to specify name for Bluetooth interface to use on local computer, you can passthat to class or function of getting a connection. Then pass connection object to `MoveHub` constructor. Like this:
```python
from pylgbst import BLEConnection, MoveHub
from pylgbst.movehub import MoveHub
from pylgbst.comms_gatt import GattConnection

conn = BLEConnection()
conn.connect("hci1")
conn = GattConnection("hci1")
conn.connect() # you can pass MoveHub mac address as parameter here, like 'AA:BB:CC:DD:EE:FF'

hub = MoveHub(conn)
```

#### Use Disconnect in `finally`

It is recommended to make sure `disconnect()` method is called on connection object after you have finished your program. This ensures Bluetooth subsystem is cleared and avoids problems for subsequent re-connects of MoveHub. The best way to do that in Python is to use `try ... finally` clause:

```python
from pylgbst import get_connection_auto
from pylgbst.movehub import MoveHub

conn=get_connection_auto() # ! don't put this into `try` block
try:
hub = MoveHub(conn)
finally:
conn.disconnect()
```

#### Devices Detecting
As part of instantiating process, `MoveHub` waits up to 1 minute for all builtin devices to appear, such as motors on ports A and B, tilt sensor, button and battery. This not guarantees that external motor and/or color sensor will be present right after `MoveHub` instantiated. Usually, sleeping for couple of seconds gives it enough time to detect everything.

Expand All @@ -274,17 +311,15 @@ It is possible to subscribe with multiple times for the same sensor. Only one, v

Good practice for any program is to unsubscribe from all sensor subscriptions before ending, especially when used with `DebugServer`.


## Debug Server
Running debug server opens permanent BLE connection to Hub and listening on TCP port for communications. This avoids the need to re-start Hub all the time.

There is `DebugServerConnection` class that you can use with it, instead of `BLEConnection`.

Starting debug server is done like this:
Starting debug server is done like this (you may need to run it with `sudo`, depending on your BLE backend):
```bash
sudo python -c "from pylgbst.comms import *; \
import logging; logging.basicConfig(level=logging.DEBUG); \
DebugServer(BLEConnection().connect()).start()"
python -c "import logging; logging.basicConfig(level=logging.DEBUG); \
import pylgbst; pylgbst.start_debug_server()"
```

Then push green button on MoveHub, so permanent BLE connection will be established.
Expand Down
17 changes: 11 additions & 6 deletions examples/demo.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# coding=utf-8
import time
from time import sleep

from pylgbst import *
from pylgbst.comms import DebugServerConnection
from pylgbst.movehub import MoveHub
from pylgbst.movehub import MoveHub, COLORS, COLOR_BLACK
from pylgbst.peripherals import EncodedMotor, TiltSensor, Amperage, Voltage

log = logging.getLogger("demo")

Expand Down Expand Up @@ -185,9 +187,12 @@ def demo_all(movehub):
try:
connection = DebugServerConnection()
except BaseException:
logging.warning("Failed to use debug server: %s", traceback.format_exc())
connection = BLEConnection().connect()
logging.debug("Failed to use debug server: %s", traceback.format_exc())
connection = get_connection_auto()

hub = MoveHub(connection)
sleep(10000)
#demo_all(hub)
try:
hub = MoveHub(connection)
sleep(1)
# demo_all(hub)
finally:
connection.disconnect()
11 changes: 5 additions & 6 deletions examples/harmonograph/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import logging
import traceback

import time

from pylgbst import MoveHub
from pylgbst.comms import DebugServerConnection, BLEConnection
from pylgbst import get_connection_auto
from pylgbst.comms import DebugServerConnection
from pylgbst.movehub import MoveHub

if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
Expand All @@ -13,13 +12,13 @@
conn = DebugServerConnection()
except BaseException:
logging.warning("Failed to use debug server: %s", traceback.format_exc())
conn = BLEConnection().connect()
conn = get_connection_auto()

hub = MoveHub(conn)
try:
hub.motor_AB.constant(0.45, 0.45)
hub.motor_external.angled(12590, 0.1)
#time.sleep(180)
# time.sleep(180)
finally:
hub.motor_AB.stop()
if hub.motor_external:
Expand Down
3 changes: 2 additions & 1 deletion examples/plotter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import math
import time

from pylgbst import ColorDistanceSensor, COLORS, COLOR_RED, COLOR_CYAN
from pylgbst.constants import COLOR_RED, COLOR_CYAN, COLORS
from pylgbst.peripherals import ColorDistanceSensor


class Plotter(object):
Expand Down
7 changes: 4 additions & 3 deletions examples/plotter/try.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import six

from examples.plotter import Plotter
from pylgbst import EncodedMotor, PORT_AB, PORT_C, PORT_A, PORT_B, MoveHub
from pylgbst.comms import DebugServerConnection, BLEConnection
from pylgbst import get_connection_auto
from pylgbst.comms import DebugServerConnection
from pylgbst.movehub import EncodedMotor, PORT_AB, PORT_C, PORT_A, PORT_B, MoveHub
from tests import HubMock


Expand Down Expand Up @@ -223,7 +224,7 @@ def interpret_command(cmd, plotter):
conn = DebugServerConnection()
except BaseException:
logging.warning("Failed to use debug server: %s", traceback.format_exc())
conn = BLEConnection().connect()
conn = get_connection_auto()

hub = MoveHub(conn) if 1 else get_hub_mock()

Expand Down
8 changes: 5 additions & 3 deletions examples/sorter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import logging
import traceback

from pylgbst import MoveHub, COLORS, COLOR_RED, COLOR_YELLOW, COLOR_CYAN, COLOR_BLUE, COLOR_BLACK
from pylgbst.comms import DebugServerConnection, BLEConnection
from pylgbst import get_connection_auto
from pylgbst.comms import DebugServerConnection
from pylgbst.constants import COLORS, COLOR_YELLOW, COLOR_BLUE, COLOR_CYAN, COLOR_RED, COLOR_BLACK
from pylgbst.movehub import MoveHub


class ColorSorter(MoveHub):
Expand Down Expand Up @@ -82,7 +84,7 @@ def tick(self):
conn = DebugServerConnection()
except BaseException:
logging.warning("Failed to use debug server: %s", traceback.format_exc())
conn = BLEConnection().connect()
conn = get_connection_auto()

sorter = ColorSorter(conn)
empty = 0
Expand Down
Loading

0 comments on commit 7bfe700

Please sign in to comment.