Skip to main content
Version: 3.2.1

Output Specification

Output Data Specification

The Protobuf data specification for all output messages can be found and downloaded from these links:

  1. output.proto
  2. point_cloud.proto

Streaming Data (TCP and Websocket)

This is a live data stream that can be parsed and processed by external applications. The Websocket Endpoints are detailed below:

Communication ProtocolTCP (Websocket)
Data EncodingProtobuf 3
Output Port5050
Protobuf MessageOutputMessage
Communication ProtocolTCP (Websocket)
Data EncodingProtobuf 3
Output Port5051
Protobuf MessagePointResult

Output Message

This is the main message that carries all the output results sent by SENSR in runtime mode. To reduce bandwidth usage, SENSR does not fill all the fields at all times. Each message has a defined output frequency described below.

Type: Continuous Stream (every frame)

FieldUnitTypeNote
timestamp-TimestampTimestamp when streaming message is sent.
stream-StreamMessageSENSR perception result stream message.
event-EventMessageSENSR event message (Zone, Losing, SystemHealth)
custom-CustomMessageSENSR additional result message (Field of Regard)

Stream Message

This message includes output results of SENSR. Each field will be filled based on the rates below:

objects : every frame
zones : every 10 sec.
health : every 1 sec.

The fields has_objects for objects and has_zones for zones act as a flag to indicate if a specific output result has been published or not. For the health message, its presence describes if the message has been published or not.

Type: Continuous Stream

FieldUnitTypeNote
objects-ObjectObject list in the latest frame.
has_objects-boolA flag to check objects field is valid or not
zones-ZoneConfigEvent zone configuration.
has_zones-boolA flag to check zones field is valid or not
health-SystemHealthSystem health in the latest frame.
static_object-ObjectStatic object list in the latest frame.
Object

Object is the standard object tracking output. Note that points and history are optional fields. You can receive these optional fields by setting a specific configuration(“common.output.publish_point_cloud”).

Type: Continuous Stream (every frame)

FieldUnitTypeNote
id-int32ID of the object.
label-enum0 = None 1 = Car 2 = Pedestrian 3 = Cyclist, 4 = Misc
confidence-float0 to 1 probability of the object classification.
bbox-BoundingBoxBounding box of the object.
velocitym/sVector3XYZ velocity of the object.
tracking_status-enum0 = NONE, 1 = VALIDATING, 2 = INVALIDATING, 3 = TRACKING, 4 = DRIFTING, 5 = EXPIRED
(VALIDATING : Check validity in early stage of tracking
INVALIDATING : Short term prediction when tracking is lost in VALIDATING status
TRACKING : Stable tracking (RECOMMENDED VALUE TO USE FOR TRACKING, IGNORE THE REST)
DRIFTING: Short term prediction when tracking is lost in TRACKING status
EXPIRED: Expired tracking)
yaw_rate-floatThe yaw value difference of the object between the previous frame and the current frame is divided by the time delta. (radian)
last_observed_timestamp-DurationLast updated time offset relative to first_cloud_arrival_timestamp
retro_reflective-boolA flag to show if the object is classified as retro reflective.
pointsmetersbytesList of sequential 3 float value set (XYZ).
history-HistoryHistory of the object.
prediction-PredictionPrediction of the object.
zone_ids-int32List of zone occupied by the object.
intensities-bytesSequential 1 float value set

Python Sample Code using SENSR SDK

Get point, bbox, prediction

if message.HasField('stream') and message.stream.has_objects:
for obj in message.stream.objects:
float_size = ctypes.sizeof(ctypes.c_float)
object_point_num = len(obj.points) // (float_size * 3) # Each point is 3 floats (x,y,z)

intensity_np = np.frombuffer(obj.intensities, np.float32)

if len(intensity_np) != 0:
min_intensity = np.min(intensity_np)
median_intensity = np.median(intensity_np)
max_intensity = np.max(intensity_np)
else:
min_intensity = 0.0
median_intensity = 0.0
max_intensity = 0.0

print('Obj ({0}): point no. {1}'.format(obj.id, object_point_num))
print('Obj ({0}): point intensity [min, median, max] is [{1}, {2}, {3}]'.format(obj.id, min_intensity, median_intensity, max_intensity))
print('Obj ({0}): velocity {1}'.format(obj.id, obj.velocity))
print('Obj ({0}): bbox {1}'.format(obj.id, obj.bbox))
print('Obj ({0}): tracking status {1}'.format(obj.id, sensr_type.TrackingStatus.Name(int(obj.tracking_status))))
print('Obj ({0}): Object type {1}'.format(obj.id, sensr_type.LabelType.Name(int(obj.label))))
print('Obj ({0}): prediction {1}'.format(obj.id, obj.prediction))

Get the velocity value and position angle of the objects

import math
for obj in message.stream.objects:

Velocity = math.sqrt(math.pow(obj.velocity.x,2)+math.pow(obj.velocity.y,2))
Angle = math.atan2(obj.velocity.y,obj.velocity.x)

Zone Config

This is a low frequency message to communicate the event zone shapes and locations for you who do not want to use the REST API.

Type: Continuous Stream (low frequency, 1 per 10 seconds or slower)

FieldUnutData typeNote
id-int32Zone id
name-stringZone name
pbox-PolygonBoxArray of X,Y,Z
type-Enumeration0 = None 1 = Event

Event Message

This message will be filled whenever SENSR detects events. There are 3 types of events. zone, losing, system. Before parsing each field, you need to check the size of each field. The size 0 means no event related to that field.

Type: Trigger on event

FieldUnitTypeNote
zone-ZoneEventEvent list related to zone.
losing-LosingEventEvent when SENSR lose tracking.
health-SystemHealthEvent when SENSR has trouble inside.
ZoneEvent

This is an event triggered message. This message gets sent when an object interacts with a zone. Four interactions are: Enter Zone, Exit Zone, Loitering(more than X seconds in a zone) and Velocity(speed above X m/s in a zone).

Type: Trigger on event

FieldUnitData typeNote
timestamp-TimeStampEvent trigger time.
id-int32Zone id
type-Enumeration0 = None, 1 = Entry, 2 = Exit, 3 = Loitering, 4 = Exceed speed
object-ZoneEvent_ObjectObject information

Python Sample Code using SENSR SDK

Get trigger message of the zone

for zone in message.event.zone:
if zone.type == sensr_output.ZoneEvent.Type.ENTRY:
print('Entering zone ({0}): obj {1}'.format(zone.id, zone.object.id))

elif zone.type == sensr_output.ZoneEvent.Type.EXIT:
print('Exiting zone ({0}): obj {1}'.format(zone.id, zone.object.id))

Object in ZoneEvent

ZoneEvent saves an object of this type.

FieldUnitData typeNote
id-int32
positionmetersVector3 (float)Object location at time of trigger
heading-FloatYaw (0.0-2.0Pi)
velocitym/sVector3 (float)m/s + direction (optional) Filled in case of overspeed events.

LosingEvent

SENSR will send this message when an object is no longer detected.

Type: Trigger on event

FieldUnitData typeNote
timestamp-TimeStamp
id-int32Object id
positionmetersVector3 (float)Last known location of object
heading-floatYaw (0.0-2.0Pi)
Custom Message

This message includes additional information of SENSR.

Type: Continuous Stream

FieldUnitData typeNote
bg_learning_progress-floatBackground learning progress (0.0 - 1.0)
profiling-ProfilingResultSetProfiling result of current frame

System Health

This is part of the Health Monitoring System. This is both a continuous low frequency stream (acting as a heartbeat) and an event trigger stream.

Type: Continuous Stream + Trigger on event

FieldUnitData typeNote
master-Enumeration0 = None 1 = OK 2 = Storage Shortage 3 = SlowDown Error 4 = Internal Error
nodes-map<string, NodeHealth>Each algo node health

Python Sample Code using SENSR SDK

Get system health informantion

    if message.stream.HasField('health'):
system_health = message.stream.health
print(‘System health: {0}.format(system_health.master))

if len(system_health.nodes) > 0:
for node_key in syste_health.nodes:
node_health = system_health.nodes[node_key]
print('Node ({0}) health: {1}'.format(node_key, health.status))

if len(node_health.sensors) > 0:
for sensor_key in node_health.sensors:
Sensor_health = node_health.sensors[sensor_key]
print('Sensor ({0}) health {1}'.format(sensor_key, sensor_health))
else:
print(‘ No sensors are connected’)
else:
print(‘No nodes are connected’)

Node Health

This is part of the System Health message.

FieldUnitData typeNote
status-Enumeration0 = None, 1 = OK, 2 = ROS Error, 3 = Lost Connection, 4 = Invalid GPU Config
sensors-map<string, Enumeration>0 = sensor dead
1 = sensor alive
2 = sensor erroneous(Sensor is obstructed.)
3 = sensor tilted
4 = sensor suspended(Sensor points are not transmitted temporarily.)

Shared Data Types

Bounding Box

This is part of the Object message.

FieldUnitTypeNote
positionmetersVector3XYZ position of the bounding box. Position is defined as (Center X, Center Y, Bottom Z).
sizemetersVector3XYZ size of the bounding box.
yawradiansfloatBounding box rotation angle along the Z axis.
Polygon box

This is part of the Zone Config message.

FieldUnitData typeNote
points-Vector2 (float)Shape of zone in 2D
min_zmetersfloatBase point in z axis
max_zmetersfloatHeight of zone
History

This is part of the Object message.

FieldUnitData typeNote
states-History.StateList of history state
History.State

This is part of the Object message.

FieldUnitData typeNote
positionsmetersVector3 (float)object’s tracked XYZ position.
timestamp-Timestamptimestamp of the tracked XYZ position.
ReplayInfo

Replay detail information.

FieldUnitData typeNote
current_index-int32Current playing frame index in replay
RecordingInfo

Recording detail information.

FieldUnitData typeNote
saving_progress-floatProgress of saving file(0.0 - 1.0)

Point Result

Point Result

This is an optional message. If a user wants to get raw point clouds, the user can use this. To get this, the user needs to enable a specific configuration(“common.output.publish_point_cloud” = 2) in advance. This message increases lots of burden in transfer bandwidth.

Type: Continuous Stream (low frequency, 1 per 10 seconds or slower)

FieldUnitData typeNote
points-PointCloud
uid-stringdeprecated
PointCloud
FieldUnitTypeNote
points-enum0 = None, 1 = Ground, 2 = Background, 3 = Raw
uri-stringAddress of point cloud.

Python Sample Code using SENSR SDK

Get Point Cloud

for point_cloud in message.points:
float_size = ctypes.sizeof(ctypes.c_float)
num_points = len(point_cloud.points) // (float_size * 3) # Each point is 3 floats (x,y,z)

intensity_np = np.frombuffer(point_cloud.intensities, np.float32)

if len(intensity_np) != 0:
min_intensity = np.min(intensity_np)
median_intensity = np.median(intensity_np)
max_intensity = np.max(intensity_np)
else:
min_intensity = 0.0
median_intensity = 0.0
max_intensity = 0.0

if point_cloud.type == sensr_pcloud.PointResult.PointCloud.Type.RAW:
print('Topic ({0}) no. of points - {1}. Min and max intensity is [{2}, {3}]'.format(point_cloud.id, num_points, min_intensity, max_intensity))
print('Intensity [min, median, max] is [{0}, {1}, {2}]'.format(min_intensity, median_intensity, max_intensity))
elif point_cloud.type == sensr_pcloud.PointResult.PointCloud.Type.GROUND:
print('Ground points no. of points - {0}.'.format(num_points))
print('Intensity [min, median, max] is [{0}, {1}, {2}]'.format(min_intensity, median_intensity, max_intensity))
elif point_cloud.type == sensr_pcloud.PointResult.PointCloud.Type.BACKGROUND:
print('Environment points no. of points - {0}'.format(num_points))
print('Point intensity [min, median, max] is [{0}, {1}, {2}]'.format(min_intensity, median_intensity, max_intensity))
Logo
If you need access, please contact