Skip to content

stream.hpp#

ROS/acres_sim/include/acres_sim/stream.hpp Generated

The game's local transports, without ROS: the binary sensor stream (Acres/Source/Acres/AcresSensorStream.h, -SensorStream=<port>), newline-delimited JSON over TCP (the RL / drive-by-wire bridge -RlPort=<port> and the simulator control channel -SimControl=<port>) and CAN frames over UDP (-RlCanUdp=<port>). The game listens on 127.0.0.1 only, and these clients refuse any other host.

Name Type Unit Default Description
kFrameHeaderBytes constexpr size_t 32 Size of a frame header, bytes.
kSubHeaderBytes constexpr size_t 16 Size of the LiDAR and camera sub-header (four uint32), bytes.
kCanEffFlag constexpr uint32_t 0x80000000u Linux struct can_frame flags and masks (linux/can.h).

frame_name#

Name of a frame type in the statistics ("hello", "clock", "ins", "lidar", "camera", "barrier", else the number).

Argument Description
type Frame type.

Returns: The name.

std::string frame_name(uint16_t type);

parse_frame_header#

Decodes a 32-byte frame header.

Argument Description
data kFrameHeaderBytes bytes.
out The header.

Returns: False when the magic is not "TSS1".

bool parse_frame_header(const uint8_t* data, FrameHeader& out);

write_frame_header#

Encodes a frame header (the fake games of the tests write frames with it).

Argument Description
header The header.
out kFrameHeaderBytes bytes.
void write_frame_header(const FrameHeader& header, uint8_t* out);

monotonic_s#

CLOCK_MONOTONIC in seconds (the game stamps frames with the same clock).

Returns: Seconds.

double monotonic_s();

require_loopback#

Resolves a simulator host and refuses anything that is not a loopback address (the simulator's sockets are local-only; so are its clients, never an address another machine could own).

Argument Description
host Host name or IPv4 address.

Returns: The dotted IPv4 loopback address. Throws: std::invalid_argument for a non-loopback or unresolvable host.

std::string require_loopback(const std::string& host);

connect_tcp#

Connects a TCP socket to a loopback address.

Argument Description
address Dotted IPv4 address from require_loopback.
port TCP port.
timeout_s Connect timeout, s.

Returns: The socket, or -1.

int connect_tcp(const std::string& address, int port, double timeout_s);

send_all#

Sends every byte (MSG_NOSIGNAL).

Argument Description
fd Socket.
data Bytes.
bytes Their count.

Returns: False when the connection broke.

bool send_all(int fd, const void* data, size_t bytes);

recv_exact#

Receives exactly bytes bytes, waking every 0.2 s to check stop.

Argument Description
fd Socket.
data Destination.
bytes Count.
stop Abort flag.

Returns: False on end of stream, error or stop.

bool recv_exact(int fd, void* data, size_t bytes, const std::atomic<bool>& stop);

read_frame#

Reads one frame (header, sub-header of LiDAR and camera frames, payload).

Argument Description
fd Stream socket.
out The frame.
stop Abort flag.

Returns: False on end of stream, error, stop or a bad magic (the caller reconnects).

bool read_frame(int fd, Frame& out, const std::atomic<bool>& stop);

write_can_frame#

Encodes a frame as the 16-byte Linux struct can_frame (uint32 can_id, uint8 dlc, 3 pad bytes, 8 data bytes).

Argument Description
frame The frame.
out 16 bytes.
void write_can_frame(const CanFrame& frame, uint8_t* out);

read_can_frame#

Decodes a 16-byte struct can_frame.

Argument Description
data 16 bytes.

Returns: The frame.

CanFrame read_can_frame(const uint8_t* data);

FrameType#

enum FrameType : uint16_t

Stream frame types (header offset 4, FAcresSensorStream::EFrame).

Value Description
kFrameHello UTF-8 JSON: agent, vehicle, sensor layout and mounts (FAcresSensorRecorder::StreamHello)
kFrameClock float64 the vehicle's own physics time, s; header stamp = world time; every physics step
kFrameIns kInsFields float64 in the order of InsField
kFrameLidar uint32 columns, rings, point step, 0; then columns x rings x (x, y, z, intensity) float32
kFrameCamera uint32 width, height, encoding (1 = bgr8), row step; then the pixels
kFrameBarrier uint64 step: everything the stream carries for that lockstep step came before it

InsField#

enum InsField : int

Index of each float64 of an INS payload (FAcresSensorStream::EIns): base_footprint as the INS reports it, with its errors, and the simulator's exact values (Truth*).

Value Description
kUtmE UTM easting, northing, m; ellipsoidal height of the fix, m
kUtmN
kUtmH
kUtmQx grid heading as a quaternion (x grid east, y grid north, z up), xyzw
kUtmQy
kUtmQz
kUtmQw
kVelX velocity in the body frame (x forward, y left, z up), m/s
kVelY
kVelZ
kGyroX angular rate, body FLU, rad/s
kGyroY
kGyroZ
kAccelX specific force, body FLU, m/s2 (+9.81 up at rest)
kAccelY
kAccelZ
kLat latitude, longitude, deg; ellipsoidal height, m
kLon
kHeight
kCovE fix position covariance diagonal (east, north, up), m2
kCovN
kCovU
kEnuQx attitude, body FLU -> grid ENU, xyzw
kEnuQy
kEnuQz
kEnuQw
kEnuX position in the simulator's grid ENU frame, m
kEnuY
kEnuZ
kFixStatus sensor_msgs/NavSatStatus status (2 = RTK fix), -1 without georeference
kGridRotationDeg UTM grid azimuth of the simulator's grid north, deg
kUtmZone
kTruthX truth: base_footprint position, grid ENU m, and body FLU -> ENU attitude, xyzw
kTruthY
kTruthZ
kTruthQx
kTruthQy
kTruthQz
kTruthQw
kTruthSpeed truth: forward speed of base_footprint, m/s
kInsFields

FrameHeader#

struct FrameHeader

A decoded frame header (little-endian on the wire).

Frame#

struct Frame

One received frame. LiDAR and camera frames keep their 16-byte sub-header apart, so the pixels and points land in payload directly and move into the ROS message without another copy.

JsonLineClient#

class JsonLineClient

Client of a newline-delimited JSON server of the game on 127.0.0.1 (the RL / drive-by-wire bridge or the simulator control channel): one reader thread that connects (and reconnects forever, every retry_s), parses every line and hands it to the callback; send() from any thread.

Name Type Unit Default Description
LineCallback using std::function&lt;void(Json&)> Line callback: the parsed object (lines that are not JSON are skipped).
ConnectCallback using std::function&lt;void(bool)> Connection callback: true when connected, false when the connection closed.

JsonLineClient::JsonLineClient#

Argument Description
address Dotted loopback address (require_loopback).
port TCP port.
on_line Called on the reader thread for every line.
on_connect Called on the reader thread when the connection opens or closes (may be empty).
retry_s Reconnect interval, s.
JsonLineClient(std::string address, int port, LineCallback on_line, ConnectCallback on_connect = ;, double retry_s = 1.0);

JsonLineClient::~JsonLineClient#

Stops the thread and closes the socket.

~JsonLineClient();

JsonLineClient::start#

Starts the reader thread.

void start();

JsonLineClient::stop#

Stops the reader thread (joins it).

void stop();

JsonLineClient::send_line#

Writes one line (the text plus "\n"). Any thread.

Argument Description
line The JSON text, without the newline.

Returns: False without a connection or when the write failed.

bool send_line(const std::string& line);

JsonLineClient::connected#

True while connected.

bool connected() const ;

JsonLineClient::generation#

Connections opened so far (changes on every reconnect).

uint64_t generation() const ;

JsonLineClient::lines_on_connection#

Lines received on the current connection.

uint64_t lines_on_connection() const ;

JsonLineClient::port#

The port.

int port() const ;

CanFrame#

struct CanFrame

A CAN frame as struct can_frame carries it.

UdpCanClient#

class UdpCanClient

CAN frames over UDP to the game's -RlCanUdp=<port> on 127.0.0.1: a socket connected to the game's port (so only its datagrams are received), one reader thread, send() from any thread.

Name Type Unit Default Description
FrameCallback using Called on the reader thread for every frame the game sends.

UdpCanClient::UdpCanClient#

Argument Description
address Dotted loopback address.
port The game's CAN UDP port.
on_frame Frame callback.
UdpCanClient(std::string address, int port, FrameCallback on_frame);

UdpCanClient::~UdpCanClient#

Stops the thread, closes the socket.

~UdpCanClient();

UdpCanClient::start#

Opens the socket and starts the reader thread.

Returns: False when the socket could not be opened.

bool start();

UdpCanClient::stop#

Stops the reader thread.

void stop();

UdpCanClient::send#

Sends one frame.

Argument Description
frame The frame.

Returns: False when the datagram could not be sent (e.g. the game is not running).

bool send(const CanFrame& frame);

UdpCanClient::set_keepalive#

A frame sent at start and then every period_s of wall time, so the game (which learns its UDP peer from the first datagram it receives) finds this client again after a restart. Call before start().

Argument Description
frame The frame (the game must ignore it).
period_s Interval, s.
void set_keepalive(const CanFrame& frame, double period_s) ;