sPyNNaker neural_modelling  7.4.2
robot_motor_control.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 The University of Manchester
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
21 
22 #include <common/neuron-typedefs.h>
23 #include <common/in_spikes.h>
24 
25 #include <data_specification.h>
26 #include <debug.h>
27 #include <simulation.h>
28 #include <stdbool.h>
29 
30 // ----------------------------------------------------------------------
31 
33 typedef struct {
35  uint32_t key;
37  int speed;
40  uint32_t sample_time;
42  uint32_t update_time;
44  uint32_t delay_time;
50 
55 };
56 
58 #define N_COUNTERS 6
59 
61 typedef enum {
62  MOTION_FORWARD = 0x01,
63  MOTION_BACK = 0x02,
64  MOTION_RIGHT = 0x03,
65  MOTION_LEFT = 0x04,
67  MOTION_C_CLOCKWISE = 0x06
69 
71 #define NEURON_ID_MASK 0x7FF
72 
73 // Globals
75 static uint32_t time;
77 static int *counters;
79 static int *last_speed;
81 static uint32_t key;
83 static int speed;
85 static uint32_t sample_time;
87 static uint32_t update_time;
89 static uint32_t delay_time;
91 static int delta_threshold;
95 static uint32_t simulation_ticks;
97 static uint32_t infinite_run;
98 
104 };
105 
108  MC = -1,
109  SDP = 0,
110  DMA = 1,
111  TIMER = 2,
112 };
113 
114 // ----------------------------------------------------------------------
115 
119 static inline void send_to_motor(uint32_t direction, uint32_t the_speed) {
120  uint32_t direction_key = direction | key;
121  while (!spin1_send_mc_packet(direction_key, the_speed, WITH_PAYLOAD)) {
122  spin1_delay_us(1);
123  }
124  if (delay_time > 0) {
125  spin1_delay_us(delay_time);
126  }
127 }
128 
134 static inline void do_motion(
135  direction_t direction_index, direction_t opposite_index,
136  const char *direction, const char *opposite) {
137  int direction_count = counters[direction_index - 1];
138  int opposite_count = counters[opposite_index - 1];
139  int delta = direction_count - opposite_count;
140  log_debug("%s = %d, %s = %d, delta = %d, threshold = %u",
141  direction, direction_count, opposite, opposite_count, delta,
143 
144  if (delta >= delta_threshold) {
145  log_debug("Moving %s", direction);
146  last_speed[direction_index - 1] = speed;
147  last_speed[opposite_index - 1] = 0;
148  send_to_motor(direction_index, speed);
149  } else if (delta <= -delta_threshold) {
150  log_debug("Moving %s", direction);
151  last_speed[direction_index - 1] = 0;
152  last_speed[opposite_index - 1] = speed;
153  send_to_motor(opposite_index, speed);
154  } else if (!continue_if_not_different) {
155  log_debug("Motion is indeterminate in %s-%s direction",
156  direction, opposite);
157  last_speed[direction_index - 1] = 0;
158  last_speed[opposite_index - 1] = 0;
159  send_to_motor(direction_index, 0);
160  }
161 }
162 
169 static inline void do_update(
170  direction_t direction_index, direction_t opposite_index,
171  const char *direction, const char *opposite) {
172  int direction_speed = last_speed[direction_index - 1];
173  int opposite_speed = last_speed[opposite_index - 1];
174  int delta = direction_speed - opposite_speed;
175  if (delta > 0) {
176  log_debug("Resending %s = %d", direction, direction_speed);
177  send_to_motor(direction_index, direction_speed);
178  } else if (delta < 0) {
179  log_debug("Resending %s = %d", opposite, opposite_speed);
180  send_to_motor(opposite_index, opposite_speed);
181  } else {
182  log_debug("Resending No Motion in the %s-%s direction", direction,
183  opposite);
184  send_to_motor(direction_index, 0);
185  }
186 }
187 
188 // Callbacks
193 static void timer_callback(UNUSED uint unused0, UNUSED uint unused1) {
194  time++;
195 
196  log_debug("Timer tick %d", time);
197 
198  if (simulation_is_finished()) {
199  simulation_handle_pause_resume(NULL);
200  log_info("Simulation complete.\n");
201  simulation_ready_to_read();
202  }
203 
204  // Process the incoming spikes
205  spike_t s;
206  uint32_t nid;
207  while (in_spikes_get_next_spike(&s)) {
208  nid = (s & NEURON_ID_MASK);
209 
210  if (nid < N_COUNTERS) {
211  counters[nid]++;
212  } else {
213  log_debug("Received spike from unknown neuron %d", nid);
214  }
215  }
216 
217  // Work out if there is any motion
218  if (time % sample_time == 0) {
219  // Do motion in pairs
220  do_motion(MOTION_FORWARD, MOTION_BACK, "Forwards", "Backwards");
221  do_motion(MOTION_LEFT, MOTION_RIGHT, "Left", "Right");
223  "Anti-clockwise");
224 
225  // Reset the counters
226  for (uint32_t i = 0; i < N_COUNTERS; i++) {
227  counters[i] = 0;
228  }
229  } else if ((time % update_time) == 0) {
230  // Do updates in pairs
231  do_update(MOTION_FORWARD, MOTION_BACK, "Forwards", "Backwards");
232  do_update(MOTION_LEFT, MOTION_RIGHT, "Left", "Right");
234  "Anti-clockwise");
235  }
236 }
237 
240 static void read_parameters(motor_control_config_t *config_region) {
241  log_info("Reading parameters from 0x%.8x", config_region);
242  key = config_region->key;
243  speed = config_region->speed;
244  sample_time = config_region->sample_time;
245  update_time = config_region->update_time;
246  delay_time = config_region->delay_time;
247  delta_threshold = config_region->delta_threshold;
249 
250  // Allocate the space for the schedule
251  counters = spin1_malloc(N_COUNTERS * sizeof(int));
252  last_speed = spin1_malloc(N_COUNTERS * sizeof(int));
253 
254  for (uint32_t i = 0; i < N_COUNTERS; i++) {
255  counters[i] = 0;
256  last_speed[i] = 0;
257  }
258 
259  log_info("Key = %d, speed = %d, sample_time = %d, update_time = %d,"
260  " delay_time = %d, delta_threshold = %d, continue_if_not_different = %d",
263 }
264 
268 static void incoming_spike_callback(uint key, UNUSED uint payload) {
269  log_debug("Received spike %x at time %d\n", key, time);
270 
271  // If there was space to add spike to incoming spike queue
273 }
274 
278 static void incoming_spike_callback_payload(uint key, uint payload) {
279  use(payload);
280 
281  log_debug("Received spike %x at time %d\n", key, time);
282 
283  // If there was space to add spike to incoming spike queue
284  for (uint count = 0; count < payload; count ++){
286  }
287 }
288 
291 static void c_main_store_provenance_data(address_t provenance_region) {
292  log_debug("writing other provenance data");
293  struct robot_motor_control_provenance *prov = (void *) provenance_region;
294 
295  // store the data into the provenance data region
297 
298  log_debug("finished other provenance data");
299 }
300 
304 static bool initialize(uint32_t *timer_period) {
305  log_info("initialise: started");
306 
307  // Get the address this core's DTCM data starts at from SRAM
308  data_specification_metadata_t *ds_regions =
309  data_specification_get_data_address();
310 
311  // Read the header
312  if (!data_specification_read_header(ds_regions)) {
313  return false;
314  }
315 
316  // Get the timing details and set up the simulation interface
317  if (!simulation_initialise(
318  data_specification_get_region(SYSTEM_REGION, ds_regions),
319  APPLICATION_NAME_HASH, timer_period, &simulation_ticks,
320  &infinite_run, &time, SDP, DMA)) {
321  return false;
322  }
323 
324  simulation_set_provenance_function(
326  data_specification_get_region(PROVENANCE_DATA_REGION, ds_regions));
327 
328  // Get the parameters
329  read_parameters(data_specification_get_region(PARAMS_REGION, ds_regions));
330 
331  log_info("initialise: completed successfully");
332 
333  return true;
334 }
335 
337 void c_main(void) {
338  // Initialise
339  uint32_t timer_period = 0;
340  if (!initialize(&timer_period)) {
341  log_error("Error in initialisation - exiting!");
342  rt_error(RTE_SWERR);
343  }
344 
345  // Initialise the incoming spike buffer
347  return;
348  }
349 
350  // Set timer_callback
351  spin1_set_timer_tick(timer_period);
352 
353  // Register callbacks
354  spin1_callback_on(MC_PACKET_RECEIVED, incoming_spike_callback, MC);
355  spin1_callback_on(
356  MCPL_PACKET_RECEIVED, incoming_spike_callback_payload, MC);
357  spin1_callback_on(TIMER_TICK, timer_callback, TIMER);
358 
359  // Start the time at "-1" so that the first tick will be 0
360  time = UINT32_MAX;
361  simulation_run();
362 }
static uint32_t timer_period
Used for configuring the timer hardware.
Functions for immediate handling of incoming spikes.
static bool in_spikes_get_next_spike(spike_t *spike)
Retrieves a spike from the input spike buffer.
Definition: in_spikes.h:66
static bool in_spikes_initialize_spike_buffer(uint32_t size)
This function initialises the input spike buffer.
Definition: in_spikes.h:51
static counter_t in_spikes_get_n_buffer_overflows(void)
Get the number of times that the input spike buffer overflowed.
Definition: in_spikes.h:80
static bool in_spikes_add_spike(spike_t spike)
Adds a spike to the input spike buffer.
Definition: in_spikes.h:59
Data type definitions for SpiNNaker Neuron-modelling.
uint32_t spike_t
The type of a spike.
#define NEURON_ID_MASK
Mask for selecting the neuron ID from a spike.
static int delta_threshold
The size of change required to matter.
static void c_main_store_provenance_data(address_t provenance_region)
Callback to store provenance data (format: neuron_provenance).
static uint32_t simulation_ticks
Current simulation stop/pause time.
static int speed
The standard motor speed, set by configuration.
static uint32_t delay_time
Inter-message delay time, in μs.
static bool initialize(uint32_t *timer_period)
Read all application configuration.
static int * counters
Accumulators for each motor direction.
uint32_t continue_if_not_different
Whether we should continue moving if there is no change.
static void do_update(direction_t direction_index, direction_t opposite_index, const char *direction, const char *opposite)
Commands the robot's motors to continue a motion started by do_motion()
static void incoming_spike_callback_payload(uint key, uint payload)
Add incoming spike message (in FIQ) to circular buffer.
static bool continue_if_not_different
Whether we should continue moving if there is no change.
static uint32_t key
The (base) key to use to send to the motor.
robot_motor_control_regions_e
DSG regions in use.
@ PARAMS_REGION
Configuration region for this application.
@ PROVENANCE_DATA_REGION
Provenance region for this application.
@ SYSTEM_REGION
General simulation API control area.
int delta_threshold
The size of change required to matter.
static uint32_t update_time
Time interval between updates, in ticks.
uint32_t delay_time
Outgoing inter-message delay time, in μs.
static void incoming_spike_callback(uint key, uint payload)
Add incoming spike message (in FIQ) to circular buffer.
static void do_motion(direction_t direction_index, direction_t opposite_index, const char *direction, const char *opposite)
Commands the robot's motors to start doing a motion.
static void send_to_motor(uint32_t direction, uint32_t the_speed)
Send a SpiNNaker multicast-with-payload message to the motor hardware.
static uint32_t infinite_run
True if the simulation is running continuously.
void c_main(void)
Entry point.
static void read_parameters(motor_control_config_t *config_region)
Reads the configuration.
static void timer_callback(uint unused0, uint unused1)
Regular 1ms callback. Takes spikes from circular buffer and converts to motor activity level.
uint32_t key
The (base) key to use to send to the motor.
static uint32_t sample_time
Time interval between samples, in ticks.
int speed
The standard motor speed scaling factor.
robot_motor_control_callback_priorities
values for the priority for each callback
@ TIMER
Timer interrupt processing is lowest priority.
@ DMA
DMA complete handling is medium priority.
@ MC
Multicast message reception is FIQ.
@ SDP
SDP handling is highest normal priority.
static int * last_speed
The last speeds for each motor direction.
uint32_t n_input_buffer_overflows
A count of the times that the synaptic input circular buffers overflowed.
static uint32_t time
The simulation time.
direction_t
The "directions" that the motors can move in.
@ MOTION_FORWARD
Forwards.
@ MOTION_BACK
Backwards.
@ MOTION_C_CLOCKWISE
Rotate counterclockwise on the spot.
@ MOTION_RIGHT
To the right.
@ MOTION_CLOCKWISE
Rotate clockwise on the spot.
@ MOTION_LEFT
To the left.
#define N_COUNTERS
Number of counters.
uint32_t update_time
Time interval between motor speed updates, in ticks.
The structure of our configuration region in SDRAM.
The provenance information written on application shutdown.