|
MIRA
|
This unit provides a webserver that allows access to MIRA using a proprietary protocol over websockets. Each websocket connection can act as a remote authority.
The protocol entirely builds up on the JSON-format. Every message that is exchanged must be a JSON-object that contains always a member "Command".
In order to gain access to MIRA each websocket connection must first checkin (like a normal Authority) using namespace and id. This can be done either by opening the websocket passing namespace and id of the created Authority e.g. ws://127.0.0.1:8080/namespace1/namespace2/AuthorityName or by sending the checkin message that must have the following syntax:
Namespace + id of an authority must form a unique identifier in the framework.
Optionally, a unique id can be generated for an authority automatically during checkin by appending a unique string to the given id, this is called an 'anonymous' authority. The Nexus checkin command can be extended by a parameter 'Anonymous' to use this:
This allows to checkin multiple authorities with the same checkin command and parameters, without the responsibility to choose unique names on the client side. It can be helpful e.g. when a remote authority is created by an HTML/Javascript page running in a web browser (see mira.js in Nexus:etc/).
To read data from a channel, use the following message. The last published channel data will be returned by a callback message to the client (see The callback message).
The read command returns a JSON representation of channel data. For e.g. image and map channel types, the JSON serialization only contains meta data like image size and type, but not the actual image data (it would not be very handy to show this e.g. in a text view). However, the Nexus provides an extension to allow reading the actual image data from channels of certain types (mira::Img<...>, mira::maps::GridMap<...>). To enable this, the read command must contain an additional 'Codec' parameter, which will describe an encoding in an image file format (supported codecs are 'png' or 'jpeg', or see below for 'raw' encoding). If this is specified, the returned message will contain an 'Img' element. This 'Img' element in turn will contain an 'Img64' element, holding a base64-encoded string that represents a buffer with the encoded image. E.g. an image.png file can be created by first applying base64decode to the 'Img64' value, then writing the result to a binary file of that name.
2 optional parameters can be used to further control the image encoding: 'Compression' can control the compression level. Valid values depend on the codec: for 'png', the compression (result size) can be selected by values 0 (weak compression) to 9 (strongest compression, default). For 'jpeg', the quality/size can be selected between 0 and 100 (default = 95). The 'Scale' parameter can be used to scale individual pixel values (i.e., increase contrast). The scale can either be a numeric value (integer or floating point), or 'auto' ('auto' only works for 1-channel images, the scale is determined such that the brightest image pixel will have value 255). If no 'Scale' is set, the default is selected based on the channel type: images with uint8 pixel values are not scaled, images with floating point values are auto-scaled.
By specifying 'Codec': 'raw', the image data is NOT encoded into an image file format, but the returned data is a raw buffer of image bytes (copied row by row), which must be interpreted by the client according to the image size and pixel format description (the normal JSON description of the image).
Messages sent by the Nexus have a size limit, which could be exceeded when a very large image is read. In this case, the messages are automatically split into multiple smaller messages. Only the image data is distributed, all other data is retained in each message. In case of a multi-message response, the 'Img' element will contain additional elements 'ID', 'Seq' and 'Fragments'. 'ID' will be the same for each message belonging to the same image, and unique compared to all other image responses (currently ID is a counter increased with each image that is read, but it could also be e.g. a random string). 'Fragments' is the number of messages for this image, and 'Seq' is the number of the current fragment. Each fragment still contains an 'Img64' element, but these are only parts of the complete base64-encoded buffer. Each message is constructed to not exceed the message size limit. The complete image data can be retrieved by collecting the 'Img64' elements of all fragment messages with the same 'ID', and assembling them in the order of their 'Seq' number. This will result in the same data as a single message 'Img64' field (which can then be base64-decoded and treated as png/jpg data).
To subscribe to a channel and getting notifications (see The callback message) on channel updates the following message format can be used:
Subscribing to image/map channels uses the same mechanism as The read command.
If delays while processing the channel updates are likely, the following message format can be used to receive all unprocessed messages within a certain time interval (specified in milliseconds):
Subscribing to particularily busy channels using subscribe (see The subscribe command) will incurr a high networking overhead as every channel update is transmitted in its own callback (see The callback message). The following command will restrict the callback frequency to the specified interval (in milliseconds):
In cases where channel updates are supposed to be processed in larger batches rather than as individual messages, the following command will return all data since the last periodic callback as a single batch:
In order to cancel a previous subscription one needs to send:
To publish a channel in order to write data to it the following syntax is used:
As type the C++ typename of the desired type must be passed (e.g. int, mira::robot::RangeScan)
In order to cancel a previous publication one needs to send:
To write data to a formerly published channel the following syntax is used:
Timestamp is the time in nanoseconds since 00:00:00 1970/01/01 and is optional. If not provided Time::now() will be used. FrameID and SequenceID are also optional members of "Data".
To wait for a service to become available, the client can use the following message syntax:
The Timeout member is the timeout in milliseconds for the server to wait for the RPC call to become available. It is optional and by default is set to infinity.
The server will answer with a waitForService message when the service is ready or the timeout occurs: The waitForService message.
To issue a RPC method call the client can use the following message syntax:
The ID can be used to associate the server response with the call. The Args member is optional and if not supplied [] is used. The Timeout member is the timeout in milliseconds for the server to wait for the RPC call to finish. It is also optional and by default is set to infinity.
If the call is successful or if an error occurred the server will answer with a serviceResponse: The serviceResponse message.
To get all available channels from the server the client can use the following syntax:
The ID can be used to associate the server response with the call.
If the call is successful, the server will answer with a response message: The channelListResponse message.
To get all available authorities from the server the client can use the following syntax:
The ID can be used to associate the server response with the call.
If the call is successful, the server will answer with a response message: The authoritiesResponse message.
To access the transformation framework, one can use these methods to either receive continuous callbacks whenever a transformation changes, or to query for a certain transform at a certain time.
The subscribeTransform command will deliver continuous The transform message callbacks for every change in the transformation chain between /path/to/some/target/frame and /path/to/the/source/frame. The callbacks will be identified by the ID passed to this method. The Dimension parameter allows to select 2D or 3D transformation, it is optional and defaults to 2D.
When invoking this command, Nexus will perform an initial query of the transformation between these frames and deliver the result via the callback mechanism. This guarantees that even static transforms (e.g. published at framework creation) can be 'accessed' this way.
Similar to the subscribeTransform command, this command will query the transformation framework for the specified transformation, and deliver the result using the The transform message response with the specified ID. The Time parameter is optional, it allows querying the transform at a specific point in time (unix timestamp in nanoseconds). The Interpolate parameter is also optional, it defaults to true. Without interpolation, the transformation is defined by the transformation published closest to the query timestamp (or last transformation if no specific timestamp is given). With interpolation, it will be interpolated/extrapolated to the exact query timestamp (or 'now', without timestamp)
The server will acknowledge each command with a response message, reporting either success or failure:
Whenever data in a subscribed channel changes (or just once for a read command) the server will send the following message:
Whenever an exception occurs on the server side caused by a former client message the server sends this message:
Whenever a waitForService succeeds or fails, the server sends this message:
The Error member only exists in case of a timeout. Otherwise, the service is ready to receive calls when this message is sent.
Whenever a service call is ready the server sends this message:
The ID is the same ID as sent with the callService message. So the client can associate the result with the call. The response either contains the Error member if an error occurred on the server side while processing the call or the Result if the call was successful.
Whenever a transformation changes that was subscribed to using subscribeTransform, or is queried using getTransform, Nexus will send this message with the changed transform. The ID corresponds to the ID used in the subscribe or get command.
The Data field contains the JSON-serialized mira::Pose2/Pose3 which is the result of transforming the target frame into the source frame. The timestamp contains the point in time (unix timestamp in nanoseconds) when the transform was published or for which it was queried.
The server will respond to a The getChannelList command with the list of all known channels with the following syntax:
The server will respond to a The getAuthorities command with the list of all known authorities with the following syntax:
Checkin an authority and call a service:
Checkin an authority and subscribe to a channel:
Note: the previous example uses websocket for simplicity. This one uses websockets (note the subtle difference) for compatibility with async.
An implementation of an Authority wrapper in JavaScript is provided with the Nexus toolbox, in Nexus:etc/mira.js.
1.8.14