-
Notifications
You must be signed in to change notification settings - Fork 19
/
sync.c
137 lines (120 loc) · 3.97 KB
/
sync.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <kilolib.h>
// Nominal period with which to blink; approximately 2 seconds. This will be
// be the period of every robot once the swarm has synchronized.
#define PERIOD 50
// Affects the size of the reset time adjustment for every discrepancy
// with a neighbor. A larger value means smaller adjustments. As a rule of thumb
// this value should increase with the average number of neighbors each robot has.
#define RESET_TIME_ADJUSTMENT_DIVIDER 120
// A cap on the absolute value of the reset time adjustment.
#define RESET_TIME_ADJUSTMENT_MAX 30
uint32_t reset_time = 0;
uint32_t last_reset = 0;
int reset_time_adjustment = 0;
message_t message;
void setup()
{
// Set the message.
message.type = NORMAL;
message.data[0] = 0;
message.crc = message_crc(&message);
// Introduce a random delay so the robots don't become instantly
// synchronized by the run signal.
set_color(RGB(1, 0, 0));
delay(10 * rand_hard());
set_color(RGB(0, 0, 0));
}
void loop()
{
if (kilo_ticks >= reset_time)
{
reset_time_adjustment = (reset_time_adjustment / RESET_TIME_ADJUSTMENT_DIVIDER);
// Apply a cap to the absolute value of the reset time adjustment.
if (reset_time_adjustment < - RESET_TIME_ADJUSTMENT_MAX)
{
reset_time_adjustment = - RESET_TIME_ADJUSTMENT_MAX;
}
else if (reset_time_adjustment > RESET_TIME_ADJUSTMENT_MAX)
{
reset_time_adjustment = RESET_TIME_ADJUSTMENT_MAX;
}
last_reset = kilo_ticks;
reset_time = kilo_ticks + PERIOD + reset_time_adjustment;
reset_time_adjustment = 0;
// Set the LED white and turn the motors on.
set_color(RGB(1, 1, 1));
set_motors(150, 150);
}
// After 1 clock tick, turn the LED and motors off.
else if (kilo_ticks > (last_reset + 1))
{
set_color(RGB(0, 0, 0));
set_motors(0, 0);
}
// Only send the current time if it can fit in 1 byte (8 bits), which
// corresponds to a maximum of 2^8 - 1 = 255. Otherwise, set the message
// CRC to 0 so neighbors ignore the message.
if ((kilo_ticks - last_reset) < 255)
{
message.data[0] = kilo_ticks - last_reset;
message.crc = message_crc(&message);
}
else
{
message.crc = 0;
}
}
message_t *message_tx()
{
return &message;
}
void message_rx(message_t *m, distance_measurement_t *d)
{
int my_timer = kilo_ticks - last_reset;
int rx_timer = m->data[0];
int timer_discrepancy = my_timer - rx_timer;
// Reset time adjustment due to this message - to be combined with the
// overall reset time adjustment.
int rx_reset_time_adjustment = 0;
if (timer_discrepancy > 0)
{
// The neighbor is trailing behind: move the reset time forward
// (reset later).
if (timer_discrepancy < (PERIOD / 2))
{
rx_reset_time_adjustment = timer_discrepancy;
}
// The neighbor is running ahead: move the reset time backward
// (reset sooner).
else
{
rx_reset_time_adjustment = - (PERIOD - timer_discrepancy) % PERIOD;
}
}
else if (timer_discrepancy < 0)
{
// The neighbor is running ahead: move the reset time backward
// (reset sooner).
if (- timer_discrepancy < (PERIOD / 2))
{
rx_reset_time_adjustment = timer_discrepancy;
}
// The neighbor is trailing behind: move the reset time forward
// (reset later).
else
{
rx_reset_time_adjustment = (PERIOD + timer_discrepancy) % PERIOD;
}
}
// Combine the reset time adjustment due to this message with the overall
// reset time adjustment.
reset_time_adjustment = reset_time_adjustment + rx_reset_time_adjustment;
}
int main()
{
kilo_init();
kilo_message_rx = message_rx;
kilo_message_tx = message_tx;
kilo_start(setup, loop);
return 0;
}