Setup guide can be found here: https://wiki.imperialrocketry.com/en/Electronics/Guides/SetUpGuideBackend
The backend serves two purposes:
The backend is structured as shown in the diagram below and can be found here.
The serial manager handles the communication between the backend and a physical Ricardo board (typically a PickleRick) normally at 115200 Baud.
The serial manager first connects to the specified serial port, and triggers a reset of the connected board by setting DTR false, waiting for a second and then setting DTR to true. The serial manager then reads all boot messages sent over the serial port. If the verbose flag is set, it will print these boot messages to the current terminal window.
The serial manager checks the send queue for any queued RNP packets to send. It expects a json object on the send queue with the following structure.
{
"data":"7768792064696420796F75206465636F646520746869733F",
"clientid":"ip:application_identifer"
}
The data field contains a serialised RNP packet in hex format while the client ID field corresponds to a unique identifier for each client on the ground control network (GCN). The client id field has the structure of the client ip address followed by some unique application identifier. The application identifier does not have a strict format as the inclusion of ip address in the client id means the application identifier uniqueness needs only be ensured on the same system. It might be beneficial to create a formal format in the future however.
Once an entry is popped from the send queue, a unique packet identifier is generated and the client id is appended to the packet record mapped to this unique packet identifier as well as the time retrieved from the send queue.
The unique packet identifier is simply the number of packets sent since the backend was started, wrapping around at 65535 back to 1. The zero identifier is reserved to allow nodes on the network to send commands directly to the backend which are handled in the __localPacketHandler__method.
As serial is a stream protocol (i.e no defined packet start and ends) we use a COBS encoding scheme to mark the start and end of packets so communication over serial isn't directly human readable. The marker used is 0x00.
Once the data had been COBS encoded, it is sent over the serial port.
The serial manager also continually checks any new bytes in the serial receive buffer, specifically looking for the start packet marker (0x00) defined in the COBS scheme. Once a start packet marker is found, it reads the stream until the next start packet marker is received, and calls the __processReceivedPacket__ method. If a COBS decoding error is encountered (normally due to non COBS encoded data being sent over serial), the current packet buffer is printed to terminal with the following error message Decode Error, the following data could not be decoded….
From the decoded binary data the serial manager then attempt to deserialise the header of the received data and ensures that the packet payload matches the defined length in the header. The unique packet identifier, which should match the originally sent out command, is used to retrieve the client id of the client which originally requested the data. The packet data is then pushed to a receive queue depending on the client id. So for example if the client id is LOCAL:APP1, the corresponding receive queue would be ReceiveQueue:LOCAL:APP1.
To ensure the packet map does not grow unbounded, if no response is received for the packet timeout (default 2 minutes), the entry within the packet map is deleted.
If the received unique packet identifier does not match any entry within the packet map, the following error message [ERROR-BACKEND] unkown packet recieved is displayed on the terminal, with the header of the packet also being printed, and the packet is placed on the unknown packet receive queue to allow analysis of unknown packets.
The serial manager also includes a udp monitor option, allowing all serial communication to be captured and analysed in a program such as Wireshark. A Wireshark decoder has been written for RNP and can be found here.
Python multiprocessing queues are used to transfer data between processes.
Formatting of data on packets on each queue is as follows:
Send Queue:
{
"data":"7768792064696420796F75206465636F646520746869733F",
"clientid":"ip:application_identifer"
}
Receive Queue:
Response Packet
{
"data":"7768792064696420796F75206465636F646520746869733F",
"clientid":"ip:application_identifer",
"type":"response"
}
Logmessage:
{
"message":"RNP initalized",
"clientid":"ip:application_identifer",
"header":{} //json containing header object variables
}
The main interface to the backend is through the flask interface. The flask interface allows serving of basic webpages and allows external clients two main ways of interfacing with the rocket network, through REST APIs, or through SOCKETIO.
The REST APIs are intended for low computing power clients such as other microcontrollers which are being used to simply send commands to the rocket i.e The Big Red Button.
| Endpoint | Type | Description | Return |
| /packet | POST | Send a serialised packet, requires the following payload {"clientid":clientid,"data":packethex} . | None |
| /response | GET | Checks for a response for a specified client id, requires a clientid to be specified in the get request. | Response packet data as hex. |
| /telemetry | GET | Checks for telemetry data for a given task ID, requires a task_ID to be specified in the get request. | JSON of data |
SocketIO APIs are preferred for most external clients and interfaces, have a much better latency and remove the need to poll for a response. SocketIO client libraries exist for most devices and languages.
The following default namespaces are generated.
| Namespace | Description |
| /packet | Send a serialised packet, requires the following payload |
| /telemetry | Mission data such as sensor data are broadcast over this channel. The event name is the name of the data packer, and the payload is the decoded packet data as a json string |
| /system_events | System events are forwarded and broadcasted over this namespace |
| /data_task_request_handler | Interface to start/stop data tasks aswell as reconfigure them |
{
"clientid":clientid, //unique identifier of requesting client
"data": hexData //hex string of binary data to send in RNP format
}
{
"timestamp":time, //time received on backend,
"data": jsonData //decoded packet data as json
}
{
"SystemEvent":
{
"level":"", // info critical debug error warn
"name":"", //Ignition Command, Rocket Log, TVCArm Command
"msg":"",
"time":"",
"source":{
"application": application,
"ip" : ipaddr,
"rnp" : rnpHeader (optional)
}
}
dynamic packet handliing
human naming
broadcast
centralisation of frequently accessed data
inbuilt logging
config can be manually edited or interface using the front end
Generic web socket forwarder, allows usage of web sockets on any task id
built for grafana interfacing primarily, if ur writing ur own application use socket
Defined packet standard for updating the iclr public telemetry dashboard
