TrackMan 4 and 3e Radar HTTP Api¶
Overview¶
This document describes the message format and functionalities included in the TrackMan 4 over an IP connection.
The communication with the TrackMan 3e device consists of multiple layers, all over a network connection.
Here's a list ordered by time to show what is needed to receive a shot:
The different parts of the flow are described below.
Connection¶
WiFi Access Point¶
The TrackMan 4 exposes itself as a WiFi Access Point. The SSID will be 'Tm4
RJ45¶
The TrackMan4 also includes a RJ45 connection. Whenever a connection is detected through this, the wifi access point will be disabled.
USB¶
The 3rd way of connecting to the TrackMan 4 is by USB. On windows, a driver is required (delivered with TPS). It creates a LAN over USB, and is a link-local network. The ip address of the device is 169.254.0.1.
Device Discovery¶
To be able to communicate with the TrackMan device at hand, the client application must know where to connect to.
There are two ways to connect to a TrackMan device
IP Address¶
If the usage scenario is by connecting to the TrackMan through LAN, it is possible to connect directly by ip address. It can be accessed on 172.30.20.1.
We do recommend this approach to be a fallback value, as the next approach will deliver the URLs to the services exposed automatically.
UPnP¶
To be able to discover the unit, UPnP is used.
To find the unit, a SSDP search request with the search parameter "urn:schemas-upnp-org:device:TrackMan:1" must be sent. The device responds to the search request, and replies with a packet which contains a URL to an xml metadata file.
The complete specifications for the UPnP protocol can be found here: http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
The device xml has 3 custom fields:
Field | Description | Example |
---|---|---|
webSocket | Complete URL to the websocket | ws://172.30.20.1/ws |
api | Complete URL to the REST API base | http://172.30.20.1/api/ |
cameraApi | Complete URI to the camera REST API base | http://172.30.20.1/api/camera/ |
If you are experiencing issues finding the trackman unit using upnp, I'd recommend you to try with the hard coded ip address and then use the upnp descriptor which is located at http://ip-address:2869.
Usually problems arise when the current network has been declined home sharing (windows will pop up and ask about this when you first connect to a network).
Connection Protocol¶
The sequence diagram below describes the protocol clients has to use in order to be ready for receiving data. The specific example does the following:
- Status
- Login
- Connect to WebSocket
- Subscribe to events
- Get Target Image
Please return to this page once you've read the sections 'Receiving data', 'Device Control' and 'Target selection'.
Receiving data¶
This section describes how to receive and process data (events) through the websocket protocol.
For most client applications, this is the most important part. To receive events through the HTTP protocol, WebSockets (http://en.wikipedia.org/wiki/WebSocket) has been selected as the protocol. WebSockets provides for bi-directional, full-duplex communication. Although this is intended for web browsers, libraries are available for most programming languages. The protocol implemented is the RFC 6455 (also called version 13). More specifically, it is the Tornado websocket server that runs under the hood.
For websocket client implementations for your programming language, please see http://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations
The URL to the WebSocket is in the format: ws://{device-ip}:{port}/ws
The communication is based on a topic-based Publish/Subscribe pattern.
When subscribing to events on the WebSocket, they come in the following JSON format (envelope):
{
"Id": "<guid>",
"Type": "string",
"SubType": "string",
"Payload": object
}
SubType is which sport it belongs to (Golf, Tennis, Cricket, Baseball, Soccer). Can also be null/empty
Id is the Id of the stroke, in form of a GUID. Can be null or empty if the message is not related to a stroke.
Payload is the body of the message.
Events all clients receive¶
There is a few events which will be sent to all clients whether or not they subscribe actively to them.
Ping¶
Whenever a ping message is received, the client must respond with a 'Pong'. If no response from client is received within 1 minute, the connection is presumed dead. The Ping message is sent in a 10s interval.
The client must respond with the following message:
{
"Type": "Pong"
}
Acknowledge¶
When sending a Subscribe or AuthToken message, an Acknowledge message is sent from the server.
{
"Type": "Acknowledge",
"Subtype": "Subscribe/AuthToken",
"Id": <same id as the client sent the request with>,
"Payload": null
}
SessionOpened¶
Whenever another client takes control of the device, a message containing the user who logged in is broadcasted.
See SessionStatus for data format.
See Login for further information about the login/logout procedure
SessionClosed¶
Whenever someone releases their session, this message is broadcasted. This means that the device is currently not controlled by anyone.
When someone takes over control of the TrackMan, the SessionClosed message is followed up with a SessionOpened immediately.
See SessionStatus for data format.
See Login for further information about the login/logout procedure
Subscribeable events¶
To be able to receive data, the application will have to tell the device which topics it is interested in. This is done by sending a JSON string array with the topics of interest to the device through the websocket connection.
For example, if only TrackerState and Measurement events are of interest, a message with the following content is sent to the device:
{
"Type": "Subscribe",
"Payload": {
"MessageList": [
"TrackerState",
"Measurement"
]
}
}
When the message is parsed by the server, an acknowledge message is returned. When this acknowledge message is received by the client, this is the point from where events will be sent to the client.
A shortcut to subscribe to all events, is to send an array with "ALL" as the only entry.
The type can be one of those described in the next sections.
System events¶
SystemState¶
This event is fired whenever the device changes its internal state. See more in the 'State Manager' section
State | Description |
---|---|
Idle | No clients are connected. Camera is enabled |
Active | Client(s) are connected, but tracking has not started. |
Measuring | Ready for measuring strokes. Leveling is disabled |
Error | An error occurred. Will try to auto-recover and go to Idle |
ActiveError | An error occurred in Active |
MeasuringError | An error occurred in Measuring |
Initializing | System is booting up |
InitializeFailed | Initialization failed |
FirmwareUpdate | System is firmware updating |
Recovery | System is in recovery mode |
Setup¶
Every time setup changes, a message is sent with the Setup as payload
See Setup for more details.
Measurement events¶
The next events are related to hitting a shot. The sequence diagram below describes the typical order of the events. It asserts that the client application has already set up a connection to the device. See 'Connection Protocol' for setting up a connection.
Data¶
When receiving data from the TrackMan device, the format of the data is:
- All distances and positions are relative to teeposition. This value can be set through Setup.
- X: Distance from Tee Position in the direction towards the target
- Y: Height above the Tee Position
- Z: Side distance (right of target is positive, left is negative)
- Times are relative to impact
- Distances are in meter
- Velocities are in m/s
- Angles are in degrees
- Rotation is in rounds per minute
TrackerState¶
Is fired whenever the radar's state changes. The payload can be the following:
State | Description |
---|---|
Undefined | Tracking has not started |
Idle | Tracking has started, but no ball or club has been detected |
ClubDetected | Tracking has started, and a club swing has been detected |
BallDetected | Club swing and ball flight has been detected |
TrackConfirmed | Club swing and ball flight has been confirmed as a valid stroke |
TrackLost | Sensor has lost sight of the ball |
PostProcessing | Sensor has lost sight of the ball, and tracking has stopped. Sensor is processing data |
SaveData | Processing data has completed. Sensor is saving data (If the sensor is saving raw TrackMan Datafiles) |
TrackComplete | The stroke has been recorded and the sensor is ready to start tracking again |
TrackAborted | The user has aborted tracking |
Error | The sensor encountered an error |
LiveTrajectory¶
iveTrajectory points is sent during ballflight. This makes it possible
for the application to draw the trajectory while the ball is in the air. When the Measurement is complete, the entire ballflight is included in the message. When indoor, no LiveTrajectory is sent.
{
"PositionList": [{
"Time": 4.713003917103088,
"Position": [
87.0794747679434,
1.1742605685259568,
2.6939850593137447]
}
]
}
Name | Type | Units | Description |
---|---|---|---|
Time | Float | sec | Time relative to impact |
Position[0] | Float | meter | X Position (length) |
Position[1] | Float | meter | Y Position (height above ground) |
Position[2] | Float | meter | Z Position (side) |
Measurement¶
This event is sent both on LaunchData and on Measurement.
The kind can be deferred from the property 'Kind', where it is either LaunchData or Measurement.
LaunchData is a subset of the entire measurement, which only includes information about the launch.
See
Measurement is the entire stroke, including launchdata, club trajectory and ball trajectory. This is sent every time a stroke has been recorded.
The measurement is divided into groups:
- LaunchData
These values occur at root level of the json document. See LaunchData in appendix for example.
Name | Unit |
---|---|
AttackAngle | Degrees |
LaunchDirection | Degrees |
BallSpeed | Meters per second |
ClubPath | Degrees |
ClubSpeed | Meters per second |
Dynamic Loft | Degrees |
FaceAngle | Degrees |
FaceToPath | Degrees |
LaunchAngle | Degrees |
SmashFactor | - |
SpinAxis | Degrees |
SpinLoft | Degrees |
SpinRate | Rotations per minute |
SwingDirection | Degrees |
SwingPlane | Degrees |
MaxHeight | Meter |
Carry | Meter |
Total | Meter |
CarrySide | Meter |
TotalSide | Meter |
LandingAngle | Degrees |
HangTime | Seconds |
LastData | Meter |
Id | GUID |
Time | ISO 8601 |
PlayerDexterity | Right/Left |
TeePosition | Meter[] |
At root level is also an Array 'ReducedAccuracy' which contains the keys that can be treated as less precise (previously called 'estimated'). This could for example be SpinRate if hit indoors.
A value can be non-existent, which means that this value isn't available (prev. 'undefined').
- ClubTrajectory
The club trajectory described as two polynomial functions, one pre impact, and one post impact.
Name | Description |
---|---|
Kind | PreImpact/PostImpact |
XFit | X axis club trajectory coefficients |
YFit | Y axis club trajectory coefficients |
ZFit | Z axis club trajectory coefficients |
TimeInterval | A time interval describing the start and stop time of the polynomial function |
"ClubTrajectory": [{
"Kind": "PreImpact",
"XFit": [0.000226317, 38.1319, 93.6552, -5500.09],
"YFit": [0.00032103, -1.83515, 570.607, 2931.78],
"ZFit": [0.000186321, -4.12277, 355.105, 2288.41],
"TimeInterval": [-0.0297984, 0]
},
{
"Kind": "PostImpact",
"XFit": [-0.00171824, 29.3421, -3.58136, -2174.91],
"YFit": [0.00201059, -2.44864, 365.501, -1568.83],
"ZFit": [0.0014101, -3.83067, 232.392, -827.619],
"TimeInterval": [0, 0.0641536]
}
]
In the above example, the club trajectory is defined as a 4th order polynomial function for each dimension, but can be more or less. A time interval is included to define the start and stop points for the function evaluation. This makes it possible to choose the resolution of the data by sampling with different rates.
- BallTrajectory
The ball trajectory including bounce and roll, described as a range of polynomial functions.
Included in each trajectory is the following:
Name | Description |
---|---|
Kind | Flight/Bounce/Roll |
XFit | X axis trajectory coefficients |
YFit | Y axis trajectory coefficients |
ZFit | Z axis trajectory coefficients |
TimeInterval | The time interval to carry flat |
ValidTimeInterval | In which range the polynomial fit is valid (if actual landing position is below carry flat) |
BallTrajectory also has 2 extra properties
Name | Description |
---|---|
SpinRateFit | Spin rate coefficients. Can be used to calculate the spin rate of the ball at a Given time (e.g. when the ball collides with a tree in a virtual world, or for R&D) MeasuredTimeInterval In which time range the ball was measured. For an indoor shot (the example below) the range will be very short as it hits a net. |
"BallTrajectory": [{
"Kind": "Flight",
"XFit": [0, 49.6871, -10.4263, 2.03132, -0.258481, 0.0190915, -0.000592701],
"YFit": [0, 18.3099, -1.07625, -0.841425, 0.145222, -0.0116018, 0.000356448],
"ZFit": [0, -5.31845, 1.18702, -0.237235, 0.0309843, -0.00235727, 0.0000760416],
"SpinRateFit": [6352.85, -206.671, 14.4589, -0.714878, -0.0357263],
"TimeInterval": [0, 6.20732],
"MeasuredTimeInterval": [0, 0.0875008],
"ValidTimeInterval": [0, 6.20732]
},
{
"Kind": "Bounce",
"XFit": [133.118, 3.04932, -0.0322144],
"YFit": [-223.126, 66.4877, -4.92026],
"ZFit": [-13.6366, -0.30226, 0.00319321],
"TimeInterval": [6.20732, 7.30669],
"ValidTimeInterval": [6.20732, 7.30669]
},
{
"Kind": "Bounce",
"XFit": [133.598, 2.9376, -0.0259689],
"YFit": [-278.48, 74.0295, -4.91555],
"ZFit": [-13.6842, -0.291186, 0.00257413],
"TimeInterval": [7.30669, 7.75362],
"ValidTimeInterval": [7.30669, 7.75362]
},
{
"Kind": "Roll",
"XFit": [144.907, 1.27772],
"YFit": [0],
"ZFit": [-14.8052, -0.126652],
"TimeInterval": [7.75362, 8.87122],
"ValidTimeInterval": [7.75362, 8.87122]
}
]
In the example above the number of polynomial coefficients for each trajectory varies, so be aware of that.