sPyNNaker neural_modelling 7.3.1
Loading...
Searching...
No Matches
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
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
33typedef struct {
35 uint32_t key;
37 int speed;
40 uint32_t sample_time;
42 uint32_t update_time;
44 uint32_t delay_time;
50
56
58#define N_COUNTERS 6
59
69
71#define NEURON_ID_MASK 0x7FF
72
73// Globals
75static uint32_t time;
77static int *counters;
79static int *last_speed;
81static uint32_t key;
83static int speed;
85static uint32_t sample_time;
87static uint32_t update_time;
89static uint32_t delay_time;
91static int delta_threshold;
95static uint32_t simulation_ticks;
97static uint32_t infinite_run;
98
105
113
114// ----------------------------------------------------------------------
115
119static 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
134static 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
169static 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
193static void timer_callback(UNUSED uint unused0, UNUSED uint unused1) {
194 time++;
195
196 log_debug("Timer tick %d", time);
197
200 log_info("Simulation complete.\n");
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
240static 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
268static 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
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
291static 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
304static 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
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
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
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
337void c_main(void) {
338 // Initialise
339 uint32_t timer_period = 0;
340 if (!initialize(&timer_period)) {
341 log_error("Error in initialisation - exiting!");
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
358
359 // Start the time at "-1" so that the first tick will be 0
360 time = UINT32_MAX;
362}
#define use(x)
uint32_t * address_t
data_specification_metadata_t * data_specification_get_data_address(void)
bool data_specification_read_header(data_specification_metadata_t *ds_regions)
void log_error(const char *message,...)
void log_debug(const char *message,...)
void log_info(const char *message,...)
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.
RTE_SWERR
void rt_error(uint code,...)
void simulation_handle_pause_resume(resume_callback_t callback)
void simulation_set_provenance_function(prov_callback_t provenance_function, address_t provenance_data_address)
bool simulation_is_finished(void)
void simulation_ready_to_read(void)
void simulation_run(void)
bool simulation_initialise(address_t address, uint32_t expected_application_magic_number, uint32_t *timer_period, uint32_t *simulation_ticks_pointer, uint32_t *infinite_run_pointer, uint32_t *time_pointer, int sdp_packet_callback_priority, int dma_transfer_complete_priority)
MCPL_PACKET_RECEIVED
MC_PACKET_RECEIVED
TIMER_TICK
#define NULL
WITH_PAYLOAD
void spin1_callback_on(uint event_id, callback_t cback, int priority)
unsigned int uint