Skip to main content

Velodrome transponder training timing

Project description

velotrain

velotrain reads raw transponder passing information from a set of up to 9 measurement points, filters the messages according to track configuration parameters and then emits valid timing measurements as JSON-encoded objects to MQTT.

Operation

The velodrome is divided into a closed loop of timing sectors by measurement points at each of the interesting offsets, for example:

  • Finish line
  • 200m Start
  • Pursuit B
  • Pursuit A

A rider is considered to be in a 'run' if their speed over any configured sector (eg Finish line to 200m start) is between configured values (default: 38 km/h to 90 km/h). Passings emitted for a rider in a run will include any available lap, half-lap, quarter-lap, 100 m, and 50 m splits. Rider passings slower or faster than the configured limits are considered isolated, and will be reported without splits.

Where possible, valid raw passings received out of order will be corrected and re-ordered before being emitted. In the case that an isolated raw passing violates the configured track ordering and speed limits, it may be reported out of order.

For a Protime active/passive dual loop configuration, riders will not be registered at all until they are moving faster than about 30 km/h, no matter what software limits have been configured.

Configuration

Track layout, system transponder ids and speed limits are configured using a metarace jsonconfig entry with the section 'velotrain' and the following keys:

  • authkey: (string) reset authorisation string, default: null
  • gate: (string) transponder ID for start gate, default: null
  • gatedelay: (string) trigger delay for start gate, default: '0.075' [1]
  • gatesrc: (string) channel start gate reports to eg 'C2', default: null
  • laplen: (float) lap length in metres, default: 250.0
  • maxspeed: (float) maximum sector speed in km/d, default: 90.0
  • minspeed: (float) minimum sector speed in km/h, default: 38.0
  • moto: (list) list of transponder IDs attached to motos, default: []
  • trig: (string) transponder ID of sync trigger messages, default: '255'
  • passlevel: (integer) minimum accepted passing level, default 40 [2]
  • uaddr: (string) UDP host listen address, default ''
  • uport: (integer) UDP host port, default: 2008
  • bcast: (string) broadcast address for timing LAN, default: '255.255.255.255'
  • basetopic: (string) base topic for telegraph interface, default: 'velotrain'
  • sync: (string) channel of synchronisation master unit, default: null
  • mingate: (float) minimum accepted speed in km/h over the start gate sector, default: 9.0
  • maxgate: (float) maximum accepted speed in km/h over the start gate sector, default: 22.5
  • dhi: (list) ['address', port] DHI port for Caprica scoreboard, default: null
  • dhiencoding: (string) text encoding for DHI messages, default: 'utf-8'
  • mpseq: (list) ordering of channels on the track, default: ['C1', 'C9', 'C4', 'C6', 'C3', 'C5', 'C7', 'C8', 'C2'] [3]
  • mps: (dict) mapping of channel IDs to measurement point configs, default: {} [4]

Configured measurement points divide the track into a closed loop of timing sectors, with a set of splits at each measurement point. Measurement point config entries have the following options, omitted keys receive a default value:

  • name: (string) visible name of the measurement point, default: channel ID
  • ip: (string) IP address of connected Protime decoder, default: null [4]
  • offset: (float) distance in metres from finish line to measurement point, default: null
  • half: (string) channel ID corresponding to a half lap before this unit, default: null
  • qtr: (string) channel ID corresponding to quarter lap before this unit, default: null
  • 200: (string) channel ID corresponding to 200 m before this unit, default: null
  • 100: (string) channel ID corresponding to 100 m before this unit, default: null
  • 50: (string) channel ID corresponding to 50 m before this unit, default: null

Notes:

  1. 0.075 seconds is LS transponder delay when triggered by start gate release
  2. Sets the 'level' option in all attached Protime decoder units
  3. Default channel ordering matches trackmeet, all configured units must appear once in this sequence, however the sequence may contain more channels than are configured.
  4. Measurement points require a non-null IP entry to be configured. For use with foreign timers, set the IP to be an empty string: ''. Refer to the sample velomon.json for an example setting

Telegraph (MQTT) Interface

The topics below are relative to the configured basetopic (default: 'velotrain'), from the perspective of the velotrain process. For all JSON encoded objects, invalid or unavailable properties will be reported as null.

passing (publish)

Issue filtered and accepted passing records. Passing records are JSON encoded objects with the following properties:

  • index : (integer) index of the passing record (reset to 0 each day)
  • date: (string) Date of the passing formatted YYYY-MM-DD
  • time: (string) Time of day of the passing formatted HH:MM:SS.dc
  • mpid: (integer) Measurement point ID 0 - 9
  • refid: (string) Transponder ID or system passing ID 'gate', 'moto' or 'marker'
  • env: (list) [temperature, humidity, pressure] where each value is a float value in units degrees Celsius, %rh, and hPa respectively
  • moto: (string) Proximity to moto in seconds if drafted
  • elap: (string) Elapsed time since last start gate or start of run formatted HH:MM:SS.dc
  • lap: (string) Time for the last full lap to the measurement point
  • half: (string) Time for the last half lap to the measurement point
  • qtr: (string) Time for the last quarter lap to the measurement point
  • 200: (string) Time for the last 200m to the measurement point
  • 100: (string) Time for the last 100m to the measurement point
  • 50: (string) Time for the last 50m to the measurement point
  • text: (string) Name of measurement point, or user-supplied text for markers

Example: A moto passing over the 100m split at about 4:18pm

Topic:		velotrain/passing
Payload:	{"index": 108, "date": "2022-07-06",
		 "time": "16:18:32.30", "mpid": 5,
		 "refid": "moto", "env": [16.3, 55.0, 1015.0],
		 "moto": "0.00", "elap": "2:10.51",
		 "lap": "22.95", "half": null, "qtr": null,
		 "200": "18.32", "100": "9.07", "50": "4.52",
		 "text": "100m Split"}

rawpass (publish)

Issue raw, unprocessed passing records as received from decoders. Raw passing records are JSON encoded objects with the following properties:

  • date: (string) Date of the raw passing formatted YYYY-MM-DD
  • time: (string) Time of day of the passing formatted HH:MM:SS.dc
  • rcv: (string) Time of day passing was received by host system, formatted HH:MM:SS.dc
  • mpid: (integer) Measurement point ID 0 - 9
  • refid: (string) Raw transponder ID
  • env: (list) [temperature, humidity, pressure] where each value is a float value in units degrees Celsius, %rh, and hPa respectively
  • name: (string) Name of measurement point

Example: The raw passing that might have generated the above moto passing

Topic:		velotrain/rawpass
Payload:	{"date": "2022-07-06", "env": [16.3, 55.0, 1015.0],
		 "refid": "125328", "mpid": 5,
		 "name": "100m Split", "time": "16:18:32.303",
		 "rcv": "16:18:32.459"}

status (publish)

Issue system and measurement point status records at the top of each minute. Status records are JSON encoded objects with the following properties:

  • date: (string) Date of the status record formatted YYYY-MM-DD
  • time: (string) Time of day status was issued formatted HH:MM:SS.dc
  • offset: (string) Rough offset of system clock to UTC
  • count: (integer) Count of passing records
  • env: (list) [temperature, humidity, pressure] where each value is a float value in units degrees Celsius, %rh, and hPa respectively
  • gate: (string) Time of day of last gate trigger HH:MM:SS.dc
  • units: (list) List of JSON encoded objects, each containing a measurement point status:
    • mpid: (integer) Measurement point ID
    • name: (string) Measurement point name
    • noise: (integer) Interference noise value 0 - 100. Values under 40 indicate normal operation. Larger values indicate interference.
    • offset: (string) Unit clock offset from system time in seconds formatted as [-]s.dcm

Example: Status update

Topic:		velotrain/status
Payload:	{"date": "2022-07-07", "time": "23:04:00.15",
		 "offset": "0.211", "env": [13.1, 62.0, 1013.0],
		 "count": 123, "gate": null,
		 "units": [
		  {"mpid": 1, "name": "Finish",
		   "noise": 20, "offset": "0.000"},
		  {"mpid": 2, "name": "Pursuit A",
		   "noise": 32, "offset": "0.025"},
		  {"mpid": 3, "name": "Pursuit B",
		   "noise": 15, "offset": "0.005"},
		  {"mpid": 4, "name": "200m Start",
		   "noise": 32, "offset": "0.005"},
		  {"mpid": 5, "name": "100m Split",
		   "noise": 14, "offset": "-0.008"},
		  {"mpid": 6, "name": "50m Split",
		   "noise": 27, "offset": "0.064"},
		  {"mpid": 8, "name": "150m Split",
		   "noise": 18, "offset": "-0.020"}
		 ]}

request (subscribe)

Receive requests for replay of passing records to the nominated serial, filtered according to the JSON encoded request object:

  • serial (string) optional request serial, appended to replay topic
  • index (list) optional [first, last] limit response to include passings from index first to index last.
  • time (list) optional [starttime, endtime] limit response to passings between starttime and endtime strings formatted HH:MM:SS.dc
  • mpid (list) optional [mpid, ...] include only the nominated mpids in replay
  • refid (list) optional [refid, ...] include only nominated transponder ids in response
  • marker (list) optional [marker, ...] include only passings following the nominated marker strings

Example: Request all passings, publish to default topic

Topic:		velotrain/request
Payload:	b''

Reply topic:	velotrain/replay
Payload:	[{"index":0, ...}, {"index":1, ...}, ...]

Request a replay of passing 254 to 'xxfd'

Topic:		velotrain/request
Payload:	{"serial": "xxfd", "index": 254}

Reply topic:	velotrain/replay/xxfd
Payload:	[{"index": 254, ... }]

Replay passings from transponder '123456' and start gate after midday before index 10000 and that occur following manual markers 'one' and 'two'

Topic:		velotrain/request
Payload:	{"refid": ["123456", "gate"],
		 "time": ["12:00:00", null],
		 "index": [null, 10000],
		 "marker": ["one", "two"]}

Reply topic:	velotrain/replay
Payload:	[{"index":12, "text":"one","mpid":0, ...}, ...]

replay[/serial] (publish)

Issues a JSON encoded list of passing objects, filtered according to a provided request.

marker (subscribe)

Insert the provided utf-8 encoded unicode payload as a manual marker passing. If the supplied payload is empty, 'marker' is used.

Example: Insert an emoticon '🤷' (U+1F937) at the current time of day

Topic:		velotrain/marker
Payload:	b'\xf0\x9f\xa4\xb7'

reset (subscribe)

Start a reset process, authorised by the provided utf-8 encoded authkey (config option 'authkey'). For a Tag Heuer Protime decoder network, this process may take up to three minutes to complete. For systems with foreign timers, this request will just clear passing records.

Example: Request reset process using authkey 'qwertyuiop'

Topic:		velotrain/reset
Payload:	b'qwertyuiop'

timer (subscribe)

Receive raw passing data from a foreign timing device. Foreign timing records are utf-8 encoded unicode strings in the format:

INDEX;SOURCE;CHANNEL;REFID;TOD

Where the fields are as follows:

  • INDEX: ignored
  • SOURCE: measurement point id as a metarace timing channel eg: 'C1', 'C2', 'C3', ... 'C9'
  • CHANNEL: ignored
  • REFID: transponder ID eg '123456'
  • TOD: time of day of passing as string eg: '1:23.456', 'now', '12:34:56.789'

Note: velotrain expects each attached decoder to be triggered from a reference clock at the top of each minute, and to report a passing with refid matching config option 'trig' (default: '255'). For systems that maintain synchronisation via a different mechanism, a fake top of minute trigger can be sent with the channel of the configured sync source (config key 'sync') at any time using the trig refid and a TOD of '0'.

Example: Insert a passing for transponder '123456' on mpid 3 at the current time

Payload: b';C3;;123456;now'

Fake a top-of-minute message to mpid 1, using the default trig:

Payload: b';C1;;255;0'

Insert a passing for transponder '123456' on mpid 4, 10.2345 seconds after 2 pm:

Payload: b';C4;;123456;14:00:10.2345'

Requirements

  • metarace (>= 2.0)
  • ypmeteo

Installation

$ pip3 install velotrain

To use as a systemd service, edit the provided unit file and copy to /etc/systemd/system, then enable with:

# systemctl enable velotrain
# systemctl start velotrain

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

velotrain-1.0.0.tar.gz (21.9 kB view hashes)

Uploaded Source

Built Distribution

velotrain-1.0.0-py3-none-any.whl (22.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page