User Tools

Site Tools


doc:crazyflie:client:cfzmq:index

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
doc:crazyflie:client:cfzmq:index [2015-06-05 11:26]
macke
doc:crazyflie:client:cfzmq:index [2021-06-24 16:41]
kimberly
Line 1: Line 1:
 +https://github.com/bitcraze/crazyflie-clients-python/pull/517
  
 +//This page is about the stand-alone console ZMQ server. For Crazyflie client GUI ZMQ input see [[doc:crazyflie:zmq:index|ZMQ input]].//
 +
 +====== ZMQ server ======
 +The [[http://zeromq.org/|ZMQ]] framework (actually ØMQ) is used to interconnect applications or parts of applications to other applications via a range of interfaces. It's really nice since there's lots of language support and it's easy to use.
 +
 +The application uses 4 ports for communicating:
 +  * 2000: Main command/response socket (server/client)
 +  * 2001: Logging data and events (publish)
 +  * 2002: Param events and values(publish)
 +  * 2003: Connection events (publish)
 +  * 2004: Control data (pull)
 +
 +All communication is done using JSON. To test the implementation we have a [[https://github.com/bitcraze/crazyflie-clients-python/blob/develop/examples/zmqsrvtest.py|test client]] that could be useful to have a look at. Each message sent contains a //version// field that should always be included.
 +
 +====== cfzmq ======
 +The client is run using the command line:
 +<code>
 +$ bin/cfzmq -h
 +usage: cfzmq [-h] [-u URL] [-d]
 +
 +optional arguments:
 +  -h, --help         show this help message and exit
 +  -u URL, --url URL  URL where ZMQ will accept connections
 +  -d, --debug        Enable debug output
 +</code>
 +
 +<WRAP group>
 +<WRAP half column>
 +The default URL is set to only allow local connections:
 +<code>
 +tcp://127.0.0.1
 +</code>
 +
 +</WRAP>
 +<WRAP half column>
 +The following commandline will allow remote control:
 +<code>
 +$bin/cfqmq --url "tcp://*"
 +</code>
 +</WRAP>
 +</WRAP>
 +
 +====== Command socket ======
 +The command messages are implemented as server/client, where each request to the server is answered with a response. Each message to the server contains version, command and fields related to the command, Each response from the server will contain version and status, where status 0 means everything was ok. This makes all the calls on this port synchronous, where the server will not reply until the action is completed or it fails.
 +
 +<WRAP group>
 +<WRAP half column>
 +Example command:
 +<code>
 +{
 +  "version": 1,
 +  "cmd": "command",
 +  "arg1": "some argument",
 +  "arg2": "some other argument"
 +}
 +</code>
 +</WRAP>
 +<WRAP half column>
 +Example response of **successful** command:
 +<code>
 +{
 +  "version": 1,
 +  "status": 0
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +
 +<WRAP group>
 +<WRAP half column>
 +For each command there's an enumerated set of statuses that will be used (see blow) and each message where status != 0 will contain the field //msg// detailing the error.
 +</WRAP>
 +<WRAP half column>
 +Example response of **unsuccessful** command:
 +<code>
 +{
 +  "version": 1,
 +  "status": 1,
 +  "msg": "Something went wrong..."
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +===== scan =====
 +The scan command will trigger a scanning of all of the available interfaces on the server (USB and Crazyradio) and return all the Crazyflies found. If no interfaces are available (no Crazyradio or Crazyflie) the command will return an empty list. Therefore there's no error conditions for this command, status will always be 0.
 +
 +<WRAP group>
 +<WRAP half column>
 +Example command:
 +<code>
 +{
 +  "version": 1,
 +  "cmd": "scan"
 +}
 +</code>
 +</WRAP>
 +<WRAP half column>
 +Example response:
 +<code>
 +{
 +  "version": 1,
 +  "status": 0,
 +  "interfaces":
 +    [
 +      {
 +        "uri": "radio://0/100/250K",
 +        "info": "This is a Crazyflie"
 +      },
 +      {
 +        "uri": "debug://0/0",
 +        "info": "Normal connection"
 +      }
 +    ]
 +}
 +
 +</code>
 +</WRAP>
 +</WRAP>
 +===== connect =====
 +The connect command will connect to the supplied URI, download the logging TOC and parameter TOC/values and return everything. There's a timeout on the server-side that will be hit if the server can't connect to a Crazyflie on the supplied URI (of if there's some other error).
 +
 +The log TOC will be found in the //log// dictionary, where the first level is group, the second level is name and the third is the attributes (see below). So the type of //altHold.target// will be found in //log->altHold->target->type//.
 +
 +The param TOC will be found in the //param// dictionary, where the first level is group, the second level is name and the third is the attributes (see blow). So the RO/RW attribute for //altHold.aslAlpha// will be found in //param->altHold->aslAlpha->access//.
 +
 +<WRAP group>
 +<WRAP half column>
 +Example command:
 +<code>
 +{
 +  "version": 1,
 +  "cmd": "connect",
 +  "uri": "radio://0/10/250K"
 +}
 +</code>
 +</WRAP>
 +<WRAP half column>
 +Example response of **successful** command:
 +<code>
 +{
 +  "version": 1,
 +  "status": 0,
 +  "log": {
 +    "acc": {
 +      "mag2": {"type": "float"}, 
 +      "x": {"type": "float"},
 +      "y": {"type": "float"}, 
 +      "z": {"type": "float"}, 
 +      "zw": {"type": "float"}
 +    }, 
 +    "altHold": {
 +      "err": {"type": "float"}, 
 +      "target": {"type": "float"}, 
 +      "vSpeed": {"type": "float"}, 
 +      "vSpeedASL": {"type": "float"}, 
 +      "vSpeedAcc": {"type": "float"}, 
 +      "zSpeed": {"type": "float"}
 +    }, 
 +    "baro": {
 +      "asl": {"type": "float"}, 
 +      "aslLong": {"type": "float"}, 
 +      "aslRaw": {"type": "float"}, 
 +      "pressure": {"type": "float"}, 
 +      "temp": {"type": "float"}
 +    }, 
 +    "gyro": {
 +      "x": {"type": "float"}, 
 +      "y": {"type": "float"}, 
 +      "z": {"type": "float"}
 +    }, 
 +    "mag": {
 +      "x": {"type": "float"}, 
 +      "y": {"type": "float"}, 
 +      "z": {"type": "float"}
 +    }, 
 +    "mag_raw": {
 +      "x": {"type": "int16_t"}, 
 +      "y": {"type": "int16_t"}, 
 +      "z": {"type": "int16_t"}
 +    }, 
 +    "motor": {
 +      "m1": {"type": "int32_t"}, 
 +      "m2": {"type": "int32_t"}, 
 +      "m3": {"type": "int32_t"}, 
 +      "m4": {"type": "int32_t"}
 +    }
 +}, 
 +"param": {
 +  "altHold": {
 +    "altHoldChangeSens": {
 +      "access": "RW", 
 +      "type": "float", 
 +      "value": "200.0"
 +    }, 
 +    "altHoldErrMax": {
 +      "access": "RW", 
 +      "type": "float", 
 +      "value": "1.0"
 +    }, 
 +    "aslAlpha": {
 +      "access": "RW", 
 +      "type": "float", 
 +      "value": "0.920000016689"
 +    }
 +  }
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +
 +<WRAP group>
 +<WRAP half column>
 +If no Crazyflie is found status 1 will be returned and an error message will be supplied from the driver.
 +</WRAP>
 +<WRAP half column>
 +Example response of **unsuccessful** command:
 +<code>
 +{
 +  "version": 1,
 +  "status": 1,
 +  "msg": "Too many packages lost"
 +}
 +
 +</code>
 +</WRAP>
 +</WRAP>
 +<WRAP group>
 +<WRAP half column>
 +For the log variables (found in //log//) the following attributes are set:
 +^  Field  ^  Type  ^  Comment  ^
 +| type    | string | (u)int8, (u)int16, (u)int32, float |
 +</WRAP>
 +<WRAP half column>
 +For the parameters (found in //param//) the following attributes are set:
 +^  Field  ^  Type  ^  Comment  ^
 +| access  | string | RO for read only parameters, RW for writable |
 +| type    | string | (u)int8_t, (u)int16_t, (u)int32_t, float |
 +| value    | string | String representation of the current parameter value |
 +</WRAP>
 +</WRAP>
 +===== log =====
 +Logging data from the Crazyflie is done by setting up log configurations that will push log data at a specified interval ([[doc:crazyflie:dev:arch:logparam|more info here]]). There are four command associated with log configurations: //create//, //start//, //stop// and //delete//. Create and delete handles if the log configuration is stored in the Crazyflie memory or not. Start and stop handles if the log data is actually being sent or not from the Crazyflie to the host. Before a log config can be started is has to be created, before it can be stopped it has to be started and before it can be deleted is has to be created. Note that log block are automatically started once they have been created.
 +
 +**Note**: When a host connects to a Crazyflie the log configurations are all deleted. So if you connect, set up log configurations, disconnect and then connect again the configurations will be deleted.
 +
 +Below is an example for creating a logging configuration and starting it. The configuration contains the two variables //pm.vbat// and //stabilizer.roll// that will be sent at 1 Hz. Data will be published to the [[doc:crazyflie:client:cfzmq:index#log_data|log data socket]].
 +
 +Each action for log configurations (create, start, stop, delete) will be broadcasted on the log data socket. Log data will also be boardcasted on the same socket.
 +
 +<WRAP group>
 +<WRAP half column>
 +First create the configuration:
 +<code>
 +{
 +  "version": 1,
 +  "cmd": "log",
 +  "action": "create",
 +  "name": "Test log block",
 +  "period": 1000,
 +  "variables": [
 +      "pm.vbat",
 +      "stabilizer.roll"
 +  ]
 +}
 +</code>
 +</WRAP>
 +<WRAP half column>
 +Example response:
 +<code>
 +{
 +  "version": 1,
 +  "status": 0
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +<WRAP group>
 +<WRAP half column>
 +Then start the configuration:
 +<code>
 +{
 +  "version": 1,
 +  "cmd": "log",
 +  "action": "start",
 +  "name": "Test log block"
 +}
 +</code>
 +</WRAP>
 +<WRAP half column>
 +Example response:
 +<code>
 +{
 +  "version": 1,
 +  "status": 0
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +
 +<WRAP group>
 +<WRAP half column>
 +The following attributes should be set in the request packet:
 +^  Field  ^  Type  ^  Comment  ^  Mandatory for  ^
 +| name    | string | Name of configuration | all |
 +| action  | string | create, start, stop, delete | all |
 +| period  | int | Period (in ms) for data to be sent | create |
 +| variables | list | List of variables "group.name" | create |
 +</WRAP>
 +<WRAP half column>
 +The following errors can be seen in the response packet:
 +^  Action  ^  Status  ^  Comment  ^
 +| create | 0x01     | One or more variables were not found in the TOC |
 +| create | 0x02     | The period is either too small/large of the configuration too large |
 +| create | 0x03     | Timeout was hit when performing action.
 +| start/stop/delete | 0x01     | Config name not found |
 +| start/stop/delete | 0x02     | Timeout was hit when performing action |
 +</WRAP>
 +</WRAP>
 +<WRAP center round info 80%>
 +The Python API supports logging variables using different types than what the variables is declared as in the firmware. I.e you can log a uint32_t as a uint8_t, retaining the 8 MSB ([[doc:crazyflie:dev:arch:logparam|more info here]]). This is still not implemented.
 +</WRAP>
 +===== param =====
 +During run-time it's possible to set parameters that are mapped directly to variables in the firmware ([[doc:crazyflie:dev:arch:logparam|more info here]]). Each parameter update is also published on the param socket.
 +
 +Below is an example command to set the //flightctrl.xmode// parameter.
 +
 +<WRAP group>
 +<WRAP half column>
 +Example command:
 +<code>
 +{
 +    "version": 1,
 +    "cmd": "param",
 +    "name": "flightctrl.xmode",
 +    "value": True
 +}
 +</code>
 +</WRAP>
 +<WRAP half column>
 +Example response of **successful** command:
 +<code>
 +{
 +    "version": 1,
 +    "status": 0,
 +    "name": "flightctrl.xmode", 
 +    "value": "1" 
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +<WRAP group>
 +<WRAP half column>
 +The following errors can be seen in the response packet:
 +^  Status  ^  Comment  ^
 +| 0x01     | The parameter was not found in the TOC |
 +| 0x02     | The parameter is RO and cannot be set |
 +| 0x03     | The timeout was reached |
 +</WRAP>
 +<WRAP half column>
 +Example response of **un-successful** command:
 +<code>
 +{
 +    "version": 1,
 +    "status": 1,
 +    "msg": "Could not find flightctrl.xmode in TOC" 
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +<WRAP group>
 +<WRAP half column>
 +The API accepts values as unsigned/signed/float/bool. Booleans are stored as uint8_t and will be converted
 +to a number (0 for false, 1 for true). The type should match the type that is in the TOC (i.e don't try to set a float for a uint_8 variable).
 +</WRAP>
 +<WRAP half column>
 +^  Field  ^  Type  ^  Comment  ^
 +| name    | string | Name of parameter (group.name) |
 +| value  | unsigned/signed/float/bool | When received a string is created from the value |
 +</WRAP>
 +</WRAP>
 +====== Log socket ======
 +This socket is used for sending log configuration events as well as log data. The events that are sent is for creating, starting, stopping and deleting a configuration. For every started configuration the log data will be sent over this socket. To control this see the [[doc:crazyflie:client:cfzmq:index#log|log configuration above]].
 +
 +Each message contains an //event// field (see below) and a //name// field referring to the log configuration name.
 +
 +<WRAP group>
 +<WRAP half column>
 +The following events are sent:
 +^  Event  ^  Comment  ^
 +| created    | When a configuration is created |
 +| started    | When a configuration is started |
 +| stopped    | When a configuration is stopped |
 +| deleted    | When a configuration is deleted |
 +| data  | Log data (see below) |
 +</WRAP>
 +<WRAP half column>
 +Example of a //started// event:
 +<code>
 +{
 +  "version": 1,
 +  "name": "Test log block",
 +  "event": "started"
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +
 +<WRAP group>
 +<WRAP half column>
 +The following fields is in the data event:
 +^  Field  ^  Type  ^  Comment  ^
 +| name | string     | Name of the config that triggered the data |
 +| timestamp | int   | Time since system start (in ms) |
 +| variables | dict  | Dictionary where the keys are variable names (group.name) and the values are the variable values |
 +</WRAP>
 +<WRAP half column>
 +Example of a data event:
 +<code>
 +{
 +  "version": 1,
 +  "name": "Test log block",
 +  "event": "data",
 +  "timestamp": 1004,
 +  "variables":
 +    {
 +      "pm.vbat": 3.5,
 +      "stabilizer.roll": -80.0
 +    }
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +====== Param socket ======
 +This socket is used to broadcast parameter updates done on the [[doc:crazyflie:client:cfzmq:index#command_socket|command socket]].
 +<WRAP group>
 +<WRAP half column>
 +For each update the variable name and value is sent.
 +</WRAP>
 +<WRAP half column>
 +<code>
 +{
 +    "version": 1,
 +    "name": "flightctrl.xmode", 
 +    "value": "1" 
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +
 +====== Connection socket ======
 +This socket is used to broadcast changes in the connection state as events. Connecting the Crazyflie is a synchronous call to the [[doc:crazyflie:client:cfzmq:index#command_socket|command socket]], but for instance a lost connection will be asynchronous and boardcasted on this socket.
 +
 +Each event has a name and uri, there might also be an optional message. Note that disconnected is always sent no matter the reason. So a requested disconnect will send a //disconnected// event, and a lost connection will send a //lost// event as well as a //disconnected// event.
 +
 +<WRAP group>
 +<WRAP half column>
 +There's a number of different events:
 +^  Event  ^  Comment  ^  Msg field  ^
 +| requested    | A connection has been requested | No |
 +| connected    | A Crazyflie has been connected and the TOCs has been downloaded | No |
 +| failed       | A connection request has failed | Yes |
 +| disconnected | A Crazyflie has been disconnected | No |
 +| lost         | An open connection has been lost | Yes |
 +</WRAP>
 +<WRAP half column>
 +Example of a lost connection:
 +<code>
 +{
 +    "version": 1,
 +    "event": "failed", 
 +    "uri": "radio://0/10/250K",
 +    "msg": "Too many packets lost!" 
 +}
 +</code>
 +</WRAP>
 +</WRAP>
 +====== Control socket ======
 +Control commands can be sent at any time after the Crazyflie has been connected and has the following scaling/format:
 +<WRAP group>
 +<WRAP half column>
 +<code>
 +{
 +  "version": 1,
 +  "roll": 0.0,
 +  "pitch": 0.0,
 +  "yaw": 0.0,
 +  "thrust": 0.0
 +}
 +</code>
 +</WRAP>
 +<WRAP half column>
 +^  Param  ^  Unit  ^  Limit  ^
 +| roll    | degrees| N/A     |
 +| pitch    | degrees| N/A     |
 +| yaw    | degrees/s| N/A     |
 +| thrust    | PWM | 20 000 - 60 000|
 +</WRAP>
 +</WRAP>
doc/crazyflie/client/cfzmq/index.txt · Last modified: 2021-06-24 16:42 by kimberly