Time synchronization and triggering sensors

mnissov

Well-known member
I wanted to use a teensy board for triggering and synchronizing some different sensors.

Taking a simple example, I'll have two sensors: one high rate (~200 Hz) and one low rate (~20Hz). The simplest triggering, AFAIK, is generating a PWM at their respective frequencies. But I will also need a timestamp of each rising edge which I can use to stamp the signals. I figured I can build a system to work in the following way:
  • send one pulse in the beginning to synchronize start time of teeny with host computer unix stamp, i.e. estimate origin offset
  • begin triggering relevant sensors, sending a timestamp to host computer in the form of "micro-seconds since start"
  • apply origin offset in host computer: unixtime of teensy start + micro seconds since start = rising edge stamp in unixtime
the runtime of such an application is limited to ~10 minutes on the upper end, so assuming the teensy clock is ~10ppm, 6ms of shift is acceptable as all sensor stamps will shift uniformly.

Note, another couple of important aspects for the performance
  • Trigger signals should ideally start as close to at the same time as possible. If not possible it's okay if the offset between starting times is constant and known.
  • Trigger signals don't drift from each other, it's fine if they don't line up perfectly as some sensors rates won't allow this to happen, but they should be consistent with respect to one another.
  • Trigger signal duty cycle doesn't really matter, there is some minimum to be registered by the sensor (~10us) but assuming this prerequisite is fulfilled, the precise duration doesn't matter.


My uncertainties are:
  1. is this a reasonable way to go about doing this?
  2. how can I get the teensy clock time of the pwm rising edge?
  3. will i need to bitbang the pwm to accurately get the rising edge time
 
Triggering the sensors only? Not reading them?

200 and 20 Hz are very 'casual'

An interval timer could be used for the 200 Hz ( 5 ms ) and count every tenth and trigger the slower sensor.

How long after the trigger 'pulse' output does it need to be turned off?
 
Triggering the sensors only? Not reading them?
dont think reading is feasible, a barebones sensor setup could be IMU + camera.
I figure it would be difficult for the MCU to handle the bandwidth of both, not to mention that the number of sensors can very likely increase and I'd like one system which can accommodate both layouts, i.e. 1 IMU 1 camera and 1 IMU 2 cameras 3 radars etc.

200 and 20 Hz are very 'casual'
casual meaning slow? I agree, not very fast for PWM, but the sensors are things like IMU, camera, etc. IMU is by far the fastest and camera maxes out at maybe 30Hz for our purposes.

How long after the trigger 'pulse' output does it need to be turned off?
Depends on the sensor requirements, so I'll need to check to be 100% sure. I think the minimum duration is on the order of 10us, it can be any value above the lower constraint. And I can't imagine the lower constraint being greater than 0.5ms lets say.
 
How long after the trigger 'pulse' output does it need to be turned off?
Just checked to confirm, the sensors requirements seem to lie between 0.1us to 500us, depending on the sensor.
 
Hi again, just curious if you had any input pending the pulse duration information.

Not seeing it indicated - which Teensy? Assuming T_4.x it can set one or more outputs quickly and then do any needed delay in delayMicroseconds() or delayNanoseconds() as needed before changing the output state.

0.1 to 500 us is a big range. A short wait that works could perhaps wait to change the output(s), if a longer time is okay another interrupt could return to change the state so other work could be done.
 
Not seeing it indicated - which Teensy?
Either T4.0 or 4.1.

Assuming T_4.x it can set one or more outputs quickly and then do any needed delay in delayMicroseconds() or delayNanoseconds() as needed before changing the output state.
delay wouldn't work though right, as it's entirely possible a trigger will need to be sent during the "high" time of another group. E.g. if we're currently in the high time of the low rate class, it is very possible the high rate trigger time could come up while still being "high" for low rate.

0.1 to 500 us is a big range
commanded by the sensor and entirely out of our control.

A short wait that works could perhaps wait to change the output(s)
By this I assume you're referring to the delay method functioning for something short, e.g. the 0.5us duration.

if a longer time is okay another interrupt could return to change the state so other work could be done
To clarify, this would amount to
- digital write HIGH
- setting an interrupt to go off in 500us (is this even possible)
- in the interrupt, digital write LOW
 
Think I may have, more or less, solved the problem with `IntervalTimers`

Code:
#include <Arduino.h>

const int g_slow_output_pin = 0;           // pin number
const int g_slow_output_interval = 100000; // us
const int g_slow_output_high_time = 250;   // us
const int g_fast_output_pin = 1;           // pin number
const int g_fast_output_interval = 50000;  // us
const int g_fast_output_high_time = 10;    // us

IntervalTimer g_timer_slow;
IntervalTimer g_timer_slow_off;
IntervalTimer g_timer_fast;
IntervalTimer g_timer_fast_off;

elapsedMillis g_ms_since_start;
unsigned long int g_stamp_ms;

void turn_slow_output_off() {
  g_timer_slow_off.end();
  digitalWriteFast(g_slow_output_pin, LOW);
}
void slow_output_callback() {
  unsigned long stamp = g_ms_since_start;
  digitalWriteFast(g_slow_output_pin, HIGH);

  g_timer_slow_off.begin(turn_slow_output_off, g_slow_output_high_time);

  Serial.print("slow stamp [ms]: ");
  Serial.println(stamp);
}

void turn_fast_output_off() {
  g_timer_fast_off.end();
  digitalWriteFast(g_fast_output_pin, LOW);
}
void fast_output_callback() {
  unsigned long stamp = g_ms_since_start;
  digitalWriteFast(g_fast_output_pin, HIGH);

  g_timer_fast_off.begin(turn_fast_output_off, g_fast_output_high_time);

  Serial.print("fast stamp [ms]: ");
  Serial.println(stamp);
}

void setup() {
  Serial.begin(9600);

  pinMode(g_slow_output_pin, OUTPUT);
  pinMode(g_fast_output_pin, OUTPUT);

  g_timer_slow.begin(slow_output_callback, g_slow_output_interval);
  g_timer_fast.begin(fast_output_callback, g_fast_output_interval);
}
void loop() {}

but I'll give TimerTool a look, could perhaps make what I've done better/more readable

Edit: just a question I thought of, is there any major advantage to using something like TimerTool versus what I've done.
 
Last edited:
Think I may have, more or less, solved the problem with `IntervalTimers`

...
but I'll give TimerTool a look, could perhaps make what I've done better/more readable

Edit: just a question I thought of, is there any major advantage to using something like TimerTool versus what I've done.

That looks like what was envisioned here.

Too late last night to go beyond answering the question posted.

Now too early to except a quick glance.
 
Back
Top