diff --git a/History.txt b/History.txt deleted file mode 100644 index 743a948..0000000 --- a/History.txt +++ /dev/null @@ -1,2 +0,0 @@ -=== / 2014-05-19 - * adapt creation to allow for gem creation diff --git a/Manifest.txt b/Manifest.txt deleted file mode 100644 index d0f42f5..0000000 --- a/Manifest.txt +++ /dev/null @@ -1,56 +0,0 @@ -README.markdown -manifest.xml -Rakefile -Manifest.txt -scripts/aggregator/plots.rb -scripts/aggregator/plot_timestamper_stats.rb -test/suite_orogen.rb -test/orogen/test_trajectory_follower.rb -test/orogen/test_canbus.rb -test/orogen/test_taskmon.rb -test/orogen/test_envire.rb -test/orogen/test_gps.rb -models/orogen/camera_firewire.rb -models/orogen/laser_filter.rb -models/orogen/parport.rb -models/orogen/icp.rb -models/orogen/stereo.rb -models/orogen/corridor_navigation.rb -models/orogen/laserscanner_sick.rb -models/orogen/skid4_control.rb -models/orogen/trajectory_follower.rb -models/orogen/hokuyo.rb -models/orogen/camera_prosilica.rb -models/orogen/fog_kvh.rb -models/orogen/camera_usb.rb -models/orogen/camera_unicap.rb -models/orogen/gps.rb -models/orogen/joint_dispatcher.rb -models/orogen/pose_estimator.rb -models/orogen/corridor_planner.rb -models/orogen/iodrivers_base.rb -models/orogen/envire.rb -models/orogen/vicon.rb -models/orogen/simulation.rb -models/orogen/sonar_tritech.rb -models/orogen/transformer.rb -models/orogen/servo_dynamixel.rb -models/orogen/dynamixel.rb -models/orogen/controldev.rb -models/orogen/xsens_imu.rb -models/orogen/taskmon.rb -models/orogen/canbus.rb -models/orogen/stim300.rb -models/blueprints/planning.rb -models/blueprints/control.rb -models/blueprints/map_gen/map_generator_srv.rb -models/blueprints/map_gen/pipeline_base.rb -models/blueprints/sensors.rb -models/blueprints/vision.rb -models/blueprints/pose.rb -models/blueprints/map_gen.rb -models/blueprints/devices.rb -models/blueprints/timestamping.rb -config/init.rb -config/app.yml -History.txt diff --git a/README.markdown b/README.markdown deleted file mode 100644 index eb0fe33..0000000 --- a/README.markdown +++ /dev/null @@ -1,26 +0,0 @@ -# Bundle: rock - -* http://www.rock-robotics.org - -# DESCRIPTION - -Bundles are packages that offer a "system-wide" view of software functionality -in Rock. - -* http://rock.opendfki.de/wiki/WikiStart/Standards/RG7 for a detailed description - -This bundle provides syskit models and scripts to use Rock's navigation algorithms / components. -If you decide to use rock-roby, Rock's system management layer a set of standard folders exists. - -Details can be found here: - -* http://rock-robotics.org/master/documentation/system/index.html - -For example: - -* models/ holds the model definition files for Roby-based applications -* scripts/controllers/ contains the Roby controller files. - -# LICENSE - -* LGPLv2 or later diff --git a/Rakefile b/Rakefile index 1cc8c78..1a30ce7 100644 --- a/Rakefile +++ b/Rakefile @@ -1,36 +1,20 @@ -task :default - -package_name = 'rock' -begin - require 'hoe' +# frozen_string_literal: true - Hoe::plugin :yard +require "yard" +require "yard/rake/yardoc_task" +require "roby/app/rake" - hoe_spec = Hoe.spec package_name do - self.version = '0.1' - self.developer "Sylvain Joyeux", "sylvain.joyeux@mx4.org" - self.extra_deps << - ['rake', '>= 0.8.0'] << - ["hoe", ">= 3.0.0"] << - ["hoe-yard", ">= 0.1.2"] +task :default - self.summary = 'Root bundle for Rock software' - self.readme_file = FileList['README*'].first - self.description = paragraphs_of(readme_file, 3..5).join("\n\n") - self.licenses << "LGPLv2 or later" - self.yard_opts = [ 'models/', 'scripts/', 'config/', 'test/' ] +Roby.app.load_base_config - self.spec_extras = { - :required_ruby_version => '>= 1.8.7' - } - end +Roby::App::Rake::TestTask.new("test") - # If you need to deviate from the defaults, check utilrb's Rakefile as an example +YARD::Rake::YardocTask.new do |yard| + yard.files = ["yard/externals.rb", "models/**/*.rb", "lib/**/*.rb"] +end - Rake.clear_tasks(/^default$/) - task :default => [] - task :doc => :yard +desc "Generate YARD documentation (alias for 'yard')" +task "doc" => "yard" +task :default -rescue LoadError => e - puts "Extension for '#{package_name}' cannot be build -- loading gem failed: #{e}" -end diff --git a/manifest.xml b/manifest.xml index 8033cb4..92ac0a1 100644 --- a/manifest.xml +++ b/manifest.xml @@ -8,5 +8,6 @@ LGPL v2 or later + diff --git a/yard/externals.rb b/yard/externals.rb new file mode 100644 index 0000000..7124237 --- /dev/null +++ b/yard/externals.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Syskit + # Placeholder to tell YARD this class exists + class Component; end +end + +module Roby + module Queries + # Placeholder to tell YARD this class exists + class TaskMatcher; end + end +end diff --git a/yard/missions.md b/yard/missions.md new file mode 100644 index 0000000..4ef35d4 --- /dev/null +++ b/yard/missions.md @@ -0,0 +1,201 @@ +# Missions + +The missions are the high-level (read: UI-oriented) interface to the system. There +can be only one mission active at any given time. + +The REST API that allows to manipulate them is currently defined in `bundles/wetpaint`, +in `Wetpaint::REST::MissionAPI` and `Wetpaint::REST::MissionHelpers`. This package +defines the lower level elements on top of which the missions are built. + +The core of the mission system is to offer a JSON representation for missions, and +a mean to both represent them before they are executed, and to instanciate them +through the action system. + +The available endpoints are described in the list below. They are defined relatively +to where `Wetpaint::REST::MissionAPI` is mounted, which is +`signalk/v1/api/resources/mission` in the Wetpaint system. Each endpoint is +detailed in separate sections. + +| Endpoint | Description | +| -------- | ------------------------------------ | +| POST / | [Create a new mission](#creating-a-new-mission) | +| GET /:mission_id | [Query information about a created mission](#inspecting-an-existing-mission) | +| PUT /:mission_id/state | [Change a mission's state](#changing-a-mission-state) | + +## Workflow + +Missions must first be [created](#create). Once created, they can be +[queried](#get) or their [state modified](#changing-a-mission-state). Missions are +one-use-only, i.e. once running and/or finished they cannot be restarted (but an +identical mission can easily be created by querying the mission parameters and +creating a new one) + +## Error Handling + +On error, the endpoints will return an appropriate HTML error code (documented for each +endpoint) as well as a JSON object with appropriate information. + +## Creating a new mission + +### Endpoint + +`POST /` + +### Arguments + +| Argument | Type | Description | +| -------- | ---- | ----------- | +| type | string | The type of the mission being created | +| * | | Other arguments are specific to the mission type, see [existing mission types](#mission-types) | + +### Return Value + +| Field | Type | Description | +| ----- | ---- | ----------- | +| missionId | string | The mission ID | + +### Errors + +| Description | Code | Error Object | +| ----------- | ---- | ------------ | +| type is not an existing mission type | 400 | { "error": { "message": "invalid mission type 'TYPE'" }} +| the fields do not match the required/optional fields from the mission type | 400 | { "error": { "message": "description of the error" }} + +### Example + +`POST /` with arguments `{ "type": "transit", "routeId": "some-id" }` returns `{ missionId: "the-mission-id" }` + +### Detailed Description + +A mission has first to be created with a POST to the root of the MissionAPI +(mounted under in the Wetpaint system). The only required argument is the +`type` argument, which defines how the rest of the arguments will be +interpreted. The endpoint returns the new mission's ID, which is an arbitrary +string that allows to refer to the mission in the rest of the API + +The API calls `Seabots::Missions.from_json` that resolves the mission class +using the `type` argument. The type-to-class mapping is done using the +`Seabots::Missions::MISSION_TYPE_TO_CLASS` hash. `Missions.to_json` then +delegates to the `#to_json` method of the instance of the new class. + +After creation, the mission instance is store internally but not yet added +to the system's running plan + +## Inspecting an existing mission {#get} + +### Endpoint + +`GET /:mission_id` + +### Arguments + +| Name | Type | Description | +| -------- | ---- | ----------- | +| mission_id | string | The ID of the mission, as returned on creation | + +### Return Value + +| Field | Type | Description | +| -------- | ---- | ----------- | +| missionId | string | The ID of the mission, as returned on creation | +| state | string | The mission state (see [the list of mission states](#mission-states)) | +| * | | The mission parameters, identical to the ones given to {#create}. They are type-specific, see [the existing mission types](#mission-types) for more information | + +### Detailed description + +The endpoint returns a JSON document of the same format than the one used for +creation, augmented with mission ID and state information. + +## Changing a mission state + +### Endpoint + +`PUT /:mission_id/state` + +### Arguments + +| Name | Type | Description | +| -------- | ---- | ----------- | +| mission_id | string | The ID of the mission, as returned on creation | +| value.target | string | `running` or `terminated` | + +### Return Value + +This endpoint does not return anything + +### Errors + +| Description | Code | Error Object | +| ----------- | ---- | ------------ | +| value.target is `running` but the mission has already finished | 400 | { "error": { "message": "mission has been started but finished or was aborted" }} +| value.target is `stopped` but the mission is neither active nor running | 400 | { "error": { "message": "mission has been started but finished or was aborted" }} +| value.target is invalid | 400 | { "error": { "message": "invalid target state" }} + +### Detailed Description + +This endpoint allows to change the [mission's state](#mission-states). A created +mission that has never been started can be started by calling it with the +`running` target. An active or running mission can be terminated with +`terminated` + +The endpoint is idempotent. One can call with a `running` target while in +`active` or `running` state, or `terminated` on a finished mission. + +Making a mission active will automatically terminate any other active mission. + +## Existing Mission Types + +### Transit + +The transit mission represents a route following behavior. The route has to be +created and the trajectory planned separately using the relevant APIs. + +The transit mission requires the following parameters: + +| Field | Description | +| ----- | ----------- | +| routeId | The ID of a planned route | +### Survey + +The survey mission represents following a route for the purpose of survey. The +route has to be created and the trajectory planned separately using the relevant +APIs. + +| Field | Description | +| ----- | ----------- | +| routeId | The ID of a planned route | + +## Mission States + +| Name | Description | +| ---- | ----------- | +| pending | Created but never started | +| active | Present in plan, but not yet running | +| running | Running | +| success | Finished successfully | +| failed | Finished unsuccessfully | +| aborted | Terminated while in `active` state (i.e. before it got even started) | +| unknown | Invalid state (should never happen) | + +## Creating new mission types + +To create a new mission type, one has to create: + +- a mission class (see below) +- a JSON schema for the mission representation in JSON +- an action that returns an instance of this type's mission +- register the mission class on `Seabots::Missions::MISSION_TYPE_TO_CLASS` + +Mission classes are subclasses of Seabots::Tasks::Missions::Base. The subclass +**must** overload the following methods, which are documented on +Seabots::Tasks::Missions::Base: + +| Name | Description | +| ------------------ | ----------- | +| self.from_json | Create a new mission. Should ultimately call `create(action_interface, **action_arguments)`, where `action_arguments` will be passed to `instanciate` once the mission is activated. The JSON object MUST be validated using `JSON::Schema.validate!` from [json-schema](https://github.com/voxpupuli/json-schema). The REST API catches the validation error and returns an appropriate error code (400). Additional validation errors should raise `InvalidMissionJSON` | +| self.instanciate | Create a runnable representation of the mission. This is usually done by calling a separately defined action on `action_interface`, as e.g. `action_interface.mission_usv_transit.as_plan(**action_arguments) | +| json_type | Return the type of the mission as string (e.g. "transit") | + +Additionally, the `activate` instance method can be overloaded to modify action +arguments that need to be modified on activation. `USVTransit` for instance +sets the trajectory's reference time to `Time.now`