=================== boatd documentation =================== .. contents:: :backlinks: none Introduction ============ Boatd is designed to be the manager for a boat control system, granting graceful startup, telemetry, logging and a built in simulator. There are two main components of a system written using boatd: - the *driver* interfaces with the particular set of hardware in the boat. - the *behaviour* performs a set of actions to make the boat do a particular task. The API available for these scripts is supposed to be declarative, with the idea that for any boat with a driver written, any behaviour script will work. .. figure:: _static/boatd-arch.png :scale: 50 % Installing ========== Boatd is currently tested and supported on Python 2.7 and 3.4. Support for python 2 may be dropped in the near future. Installing in a virtualenv from PyPi (recommended) -------------------------------------------------- This installs boatd in a `virtualenv `_, keeping it separate from the rest of the system. First, create a new virtualenv:: $ virtualenv env Activate this virtualenv:: $ source env/bin/activate Install boatd and its dependencies from the latest published stable release:: $ pip install boatd Installing for development -------------------------- First, clone the repository and change to the directory:: $ git clone https://github.com/boatd/boatd.git $ cd boatd Create a new virtualenv:: $ virtualenv boatd-dev-env Activate this virtualenv:: $ source boatd-dev-env/bin/activate Install boatd in editable mode from the local copy:: $ pip install --editable . Installing when you don't care and live life on the edge (system wide installation) ----------------------------------------------------------------------------------- First install dependencies: On any Debian based distribution (Debian, Ubuntu, Mint etc): .. code:: bash $ apt-get install python-yaml On Red Hat systems (Fedora, CentOS, etc): .. code:: bash $ dnf install PyYAML Then clone the repository and change to the directory:: $ git clone https://github.com/boatd/boatd.git $ cd boatd Run the installer:: $ sudo python setup.py install Running boatd ============= .. code:: bash $ boatd --help usage: boatd [-h] [--version] [CONFIG FILE] Experimental robotic sailing boat daemon. positional arguments: CONFIG FILE a path to a configuration file optional arguments: -h, --help show this help message and exit --version show program's version number and exit After you have installed boatd, it can be run with ``$ boatd``. You will need to create a configuration file. It should look something like: .. code:: yaml boatd: port: 2222 interface: 127.0.0.1 plugin_directory: null plugins: - logger: period: 10 filename: logs/gps_trace driver: file: example/basic_driver.py behaviours: - example: file: example/basic_behaviour.py The example config file (``boatd-config.yaml.example``) can be modified for your boat. Output will be similar to: .. code:: bash $ boatd [15:43:55] loaded function heading as "heading" [15:43:55] loaded function get_wind as "wind_direction" [15:43:55] loaded function get_wind_speed as "wind_speed" [15:43:55] loaded function position as "position" [15:43:55] loaded function rudder as "rudder" [15:43:55] loaded function sail as "sail" [15:43:55] loaded driver from example/basic_driver.py The original aim was this command would also run your behaviour directly after startup, but this functionality is not yet implemented (see `the issue `_). After boatd is running, you should run your behaviour manually. If you would like to use a different config file in a different location, pass the path as an argument to ``boatd``. For example, ``$ boatd /etc/boatd/fancy-conf.yaml``. Using the boatd API =================== Boatd's main method of interaction is via the JSON API. ``/`` ----- - ``GET`` Returns the current status and version of boatd. Example output: .. code:: json { "boatd": { "version": 1.1 } } ``/boat`` --------- - ``GET`` Returns attributes about the current state of the boat. Example output: .. code:: json { "active": false, "position": [2.343443, null], "heading": 2.43, "wind": { "direction": 8.42, "speed": 25 } } ``/wind`` --------- - ``GET`` Returns properties of the wind. Example output: .. code:: json { "direction": 8.42, "speed": 25 } ``/behaviours`` --------------- - ``GET`` Returns data about available and current behaviours. Example output: .. code:: json { "current": null, "behaviours": { "basic": { "filename": "example/basic_behaviour.py", "running": false } } } - ``POST`` Change the currently running behaviour. Setting the current behaviour to ``null`` will cause no behaviour to be run. Examples: .. code:: json { "current": null } .. code:: json { "current": "basic" } Drivers ======= Driver basics ------------- Boatd drivers are implemented as a simple user defined class in a loadable python module. When a behaviour script requires information about the current state of the boat or needs to send a command to some hardware, boatd runs one of the methods in the driver. To write a driver, a python module should be created that contains an object named ``driver``. This object must be an instance of a class inheriting from and implementing the interface defined in ``BaseBoatdDriver``: .. autoclass:: boatd.BaseBoatdDriver :members: Note that the driver instance **must** be named ``driver``, otherwise boatd won't know where to find it. Example driver -------------- An example: .. code:: python import boatd class MyFancyBoatDriver(boatd.BaseBoatdDriver): def __init__(self): # initialize some things here pass def heading(self): return 30.0 def wind_direction(self): return 45.0 def wind_speed(self): return 4.0 def position(self): return (0, 0) def rudder(self, angle): print('moving rudder to', angle) def sail(self, angle): print('moving sail to', angle) def reconnect(self): pass # create an instance of the driver class driver = MyFancyBoatDriver() Configuring boatd to use a driver --------------------------------- Once you've written a driver, you can tell boatd to load it as the active driver by setting ``scripts.driver`` in your configuration file. Eg: .. code:: yaml scripts: driver: example/driver.py This can be a relative path, as with the example above. It can also be absolute. boatd will also expand ``~`` to your home directory: .. code:: yaml scripts: driver: ~/git/sails-boatd-driver/driver.py Plugins ======= Plugins are loadable python modules that run in a separate thread inside boatd. They have access to the current data about the boat. Plugins are enabled with the main boatd configuration file. Each plugin may have a few extra parameters, but all have the ``enabled`` parameter to enable or disable it. Example: .. code-block:: yaml plugins: - some_plugin_name: enabled: true Bundled plugins --------------- Boatd comes with a few plugins preinstalled. These are: - ``logger`` This logs data about the current state of the boat to a file periodically. Configuration parameters: - ``period`` - the time in seconds between each logged line - ``filename`` - the path to the file logs will be written to Example: .. code-block:: yaml plugins: - logger: enabled: true period: 10 filename: logs/log_trace - ``gpx_logger`` This logs data about the current state of the boat to a GPX formatted file periodically. Configuration parameters: - ``period`` - the time in seconds between each logged line - ``filename`` - the path to the file logs will be written to, the filename will be appended with a timestamp Example: .. code-block:: yaml plugins: - gpx_logger: enabled: true period: 1 filename: logs/gpx_log - ``mavlink`` This allows boatd to communicate using a subset of the mavlink protocol. Configuration parameters: - ``device`` - the serial port to use - ``baud`` - baud rate to use with the serial port Example: .. code-block:: yaml plugins: - mavlink: enabled: true device: /dev/ttyUSB0 baud: 115200 Writing new plugins ------------------- To implement a plugin, a class must be implemented that conforms to a certain interface (similar to how drivers are defined). The interface is simple: .. autoclass:: boatd.BasePlugin :members: An example implementation would be: .. code:: python from boatd import BasePlugin class ExamplePlugin(BasePlugin): def main(self): while self.running: position = self.boatd.boat.position() print('logging some stuff ', position) plugin = LoggerPlugin Some things to note: - You automatically get access to an object called ``self.boatd``. This contains a ``boat`` attribute which you can use to interact with the live boat. - ``self.running`` can be used to check if the plugin should end. When the plugin is started by boatd, this will be set to ``True``. When boatd is about to quit or plugins need to be stopped for some other reason, it will be set to ``False``. python-boatdclient ================== Boatd has a client library written for python. It contains a python wrapper module and a command line client. You can install python-boatdclient from PyPi by running:: $ pip install python-boatdclient Boatdclient includes the following user facing classes: .. autoclass:: boatdclient.Boat :members: .. autoclass:: boatdclient.Behaviour :members: ``Boat`` returns and uses special classes for bearings and latitude longitude points. These contain some common functionality. .. autoclass:: boatdclient.Point :members: .. autoclass:: boatdclient.Bearing :members: Testing ======= To run tests, install tox .. code:: bash $ pip install tox and run ``tox``. If all the tests pass, the output should be similar to: .. code:: $ tox GLOB sdist-make: /home/louis/git/boatd/setup.py py27 inst-nodeps: /home/louis/git/boatd/.tox/dist/boatd-1.1.3.zip py27 installed: boatd==1.1.3,coverage==4.0.2,coveralls==1.1,docopt==0.6.2,p luggy==0.3.1,py==1.4.30,pytest==2.8.2,pytest-cov==2.2.0,PyYAML==3.11,reques ts==2.8.1,tox==2.2.1,virtualenv==13.1.2,wheel==0.24.0 py27 runtests: PYTHONHASHSEED='2985615961' py27 runtests: commands[0] | py.test -v --cov boatd boatd ========================= test session starts ========================== platform linux2 -- Python 2.7.10, pytest-2.8.2, py-1.4.30, pluggy-0.3.1 -- /home/louis/git/boatd/.tox/py27/bin/python2.7 cachedir: .cache rootdir: /home/louis/git/boatd, inifile: plugins: cov-2.2.0 collected 50 items boatd/tests/test_api.py::TestAPI::test_GET PASSED boatd/tests/test_api.py::TestAPI::test_content_type PASSED ... snipped ====================== 50 passed in 1.39 seconds ======================= _______________________________ summary ________________________________ py27: commands succeeded py34: commands succeeded pypy: commands succeeded flake8: commands succeeded congratulations :) This will run all test environments. To run an individual environment, run ``tox -e py27``, or more generally ``tox -e ``, replacing env with ``py27``, ``py34``, ``pypy`` or ``flake8`` (style checks). The current test results from the head of the ``master`` branch can be found `here `_.