PsiSwarm Library  0.8
psiswarm.cpp
1 /* University of York Robotics Laboratory PsiSwarm Library: PsiSwarm C++ Core Source File
2  *
3  * Copyright 2016 University of York
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
7  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS
8  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9  * See the License for the specific language governing permissions and limitations under the License.
10  *
11  * File: psiswarm.cpp
12  *
13  * (C) Dept. Electronics & Computer Science, University of York
14  * James Hilder, Alan Millard, Alexander Horsfield, Homero Elizondo, Jon Timmis
15  *
16  * PsiSwarm Library Version: 0.8
17  *
18  * October 2016
19  *
20  *
21  */
22 
23 #include "psiswarm.h"
24 
25 //Setup class instances
26 Display display; //Connects to i2c(p28,p27), reset(p29), backlight(p30)
27 Motors motors;
28 Eprom eprom;
29 Led led;
30 Sensors sensors;
31 SerialControl serial;
32 Sound sound;
33 Setup i2c_setup;
34 Demo demo;
35 Animations animations;
36 Basic basic;
37 Colour colour;
38 
39 //Setup MBED connections to PsiSwarm Robot
40 Serial pc(USBTX,USBRX);
41 I2C primary_i2c (p9, p10);
42 InterruptIn gpio_interrupt (p12);
43 Serial bt(p13, p14);
44 AnalogIn vin_current(p15);
45 AnalogIn vin_battery(p16);
46 AnalogIn vin_dc(p17);
47 PwmOut motor_left_f (p21);
48 PwmOut motor_left_r (p22);
49 PwmOut motor_right_f(p23);
50 PwmOut motor_right_r(p24);
51 PwmOut center_led_red(p25);
52 PwmOut center_led_green(p26);
53 DigitalOut mbed_led1(LED1);
54 DigitalOut mbed_led2(LED2);
55 DigitalOut mbed_led3(LED3);
56 DigitalOut mbed_led4(LED4);
57 
58 
59 float center_led_brightness;
60 float backlight_brightness;
61 
62 Ticker event_handler;
63 Timer uptime;
64 Timeout pause_usercode_timeout;
65 Ticker ultrasonic_ticker;
66 Timeout ultrasonic_timeout;
67 int timer_minute_count;
68 Ticker timer_ticker;
69 
70 float firmware_version;
71 float pcb_version;
72 float serial_number;
73 
74 char has_compass=0;
75 char has_side_ir=1;
76 char has_base_ir=1;
77 char has_base_colour_sensor=0;
78 char has_top_colour_sensor=0;
79 char has_wheel_encoders=0;
80 char has_audio_pic=0;
81 char has_ultrasonic_sensor=0;
82 char has_temperature_sensor=0;
83 char has_recharging_circuit=0;
84 char has_433_radio=0;
85 
86 char robot_id;
87 char previous_robot_id;
88 
89 char wheel_encoder_byte;
90 char previous_wheel_encoder_byte;
91 signed int left_encoder;
92 signed int right_encoder;
93 
94 char time_based_motor_action = 0;
95 
96 char testing_voltage_regulators_flag = 1;
97 char power_good_motor_left = 2;
98 char power_good_motor_right = 2;
99 char power_good_infrared = 2;
100 char status_dc_in = 2;
101 char status_charging = 2;
102 
103 char switch_byte;
104 char previous_switch_byte;
105 
106 
107 char use_motor_calibration = USE_MOTOR_CALIBRATION;
108 char motor_calibration_set;
109 float left_motor_calibration_value = 1.0;
110 float right_motor_calibration_value = 1.0;
111 
112 char debug_mode = DEBUG_MODE;
113 char debug_output = DEBUG_OUTPUT_STREAM;
114 
115 char firmware_bytes[21];
116 
117 int base_colour_sensor_raw_values [4];
118 int top_colour_sensor_raw_values [4];
119 
120 char waiting_for_ultrasonic = 0;
121 int ultrasonic_distance = 0;
122 char ultrasonic_distance_updated = 0;
123 
124 
125 float line_position = 0;
126 char line_found = 0;
127 
128 unsigned short background_ir_values [8];
129 unsigned short illuminated_ir_values [8];
130 float reflected_ir_distances [8];
131 char ir_values_stored = 0;
132 unsigned short background_base_ir_values [5];
133 unsigned short illuminated_base_ir_values [5];
134 char base_ir_values_stored = 0;
135 
136 float motor_left_speed;
137 float motor_right_speed;
138 char motor_left_brake;
139 char motor_right_brake;
140 
141 char demo_on = 0;
142 char event = 0;
143 char change_id_event = 0;
144 char encoder_event = 0;
145 char switch_event = 0;
146 char user_code_running = 0;
147 char user_code_restore_mode = 0;
148 char system_warnings = 0;
149 
150 
151 vector<string> basic_filenames; //filenames are stored in a vector string
152 char psi_basic_file_count = 0;
153 char use_flash_basic = 0;
154 char file_transfer_mode = 0;
155 
156 int ir_pulse_delay = DEFAULT_IR_PULSE_DELAY;
157 int base_ir_pulse_delay = DEFAULT_BASE_IR_PULSE_DELAY;
158 
159 
160 
161 
170 {
171  firmware_version=0;
172  timer_minute_count = 0;
173  timer_ticker.attach(this,&Psiswarm::IF_update_minutes, 300);
174  uptime.start();
175  primary_i2c.frequency(400000);
176  serial.setup_serial_interfaces();
177  debug("PsiSwarm Robot Library %1.2f\n\n",SOFTWARE_VERSION_CODE);
178  debug("- Setting up serial interface\n");
179  debug("- Reading firmware: ");
180  if(eprom.read_firmware() == 1) {
181  debug("Version %3.2f\n",firmware_version);
182  IF_get_hardware_description();
183  if(use_motor_calibration){
184  if(!motor_calibration_set){
185  if(firmware_version < 1.1){
186  debug("- WARNING: This firmware is incompatible with motor calibration");
187  debug("- WARNING: Please update the firmware to use this feature.");
188  use_motor_calibration = 0;
189  }
190  else {
191  debug("- WARNING: Motor calibration values have not been stored in firmware");
192  debug("- WARNING: Run calibration routine to use this feature.");
193  use_motor_calibration = 0;
194  }
195  }
196  else {
197  debug("- Motor calibration in use [LEFT:%0.4f RIGHT:%0.4f]",left_motor_calibration_value,right_motor_calibration_value);
198  }
199  }
200  } else {
201  debug("INVALID\n");
202  debug("- WARNING: Check firmware to enable robot features");
203  }
204  if(ENABLE_BASIC == 1) {
205  basic.read_list_of_file_names();
206  if(psi_basic_file_count == 0) {
207  debug("- No PsiBasic files found\n");
208  } else use_flash_basic = 1;
209  }
210  debug("- Setting up PIC microcontroller\n");
211  // IF_check_pic_firmware();
212  debug("- Setting up LED drivers\n");
213  led.IF_init_leds();
214  if(i2c_setup.IF_setup_led_expansion_ic() != 0) {
215  debug("- WARNING: No I2C acknowledge for LED driver\n");
216  system_warnings += 1;
217  }
218  debug("- Setting up motor drivers\n");
219  motors.init_motors();
220  debug("- Setting up GPIO expansion\n");
221  reset_encoders();
222  i2c_setup.IF_setup_gpio_expansion_ic();
223  if(has_temperature_sensor) {
224  debug("- Setting up temperature sensor\n");
225  i2c_setup.IF_setup_temperature_sensor();
226  }
227  if(has_base_colour_sensor) {
228  debug("- Setting up base colour sensor\n");
229  colour.IF_check_base_colour_sensor();
230  }
231  if(has_ultrasonic_sensor) {
232  debug("- Setting up ultrasonic sensor\n");
233  //enable_ultrasonic_ticker();
234  }
235 
236  debug("- Robot ID: %d\n",robot_id);
237  char switchstate = i2c_setup.IF_get_switch_state();
238  debug("- Switch State : %d\n",switchstate);
239  debug("- Battery Voltage: %1.3fV\n",sensors.get_battery_voltage());
240  debug("- DC Voltage : %1.3fV\n",sensors.get_dc_voltage());
241  debug("- Current Draw : %1.3fA\n",sensors.get_current());
242  if(has_temperature_sensor){
243  debug("- Temperature : %1.3fC\n",sensors.get_temperature());
244  }
245  char demo_on = 0;
246  if(ENABLE_DEMO == 1 && switchstate > 0) demo_on=1;
247  display.init_display(demo_on);
248  event_handler.attach_us(this,&Psiswarm::IF_handle_events, 1000);
249  if(demo_on > 0) {
250  debug("- Demo mode button is pressed\n");
251  wait(1.0);
252  demo_on = i2c_setup.IF_get_switch_state();
253  if(demo_on > 0) demo.start_demo_mode();
254  display.init_display(0);
255  }
256 }
257 
258 void Psiswarm::IF_update_minutes()
259 {
260  uptime.reset();
261  timer_minute_count += 5;
262 }
263 
264 void Psiswarm::IF_handle_events()
265 {
266  // This is the main 'operating system' thread that handles events from robot stimuli
267  // By default it is run every 1ms and checks if there are events to handle
268  if(event > 0) {
269  // There are some events to handle. We don't handle all events in every loop to keep the system responsive, instead they are priorised.
270  if(encoder_event == 1) {
271  // The encoders have changed; update the encoder values
272  IF_update_encoders();
273  encoder_event = 0;
274  event--;
275  } else {
276  if(switch_event == 1) {
277  IF_update_switch();
278  switch_event = 0;
279  event--;
280  }
281  if(change_id_event == 1) {
282  // The user ID for the robot has been changed
283  IF_update_user_id();
284  change_id_event = 0;
285  event--;
286  }
287  }
288  }
289 }
290 
291 void Psiswarm::IF_update_encoders()
292 {
293  char rwep = previous_wheel_encoder_byte >> 2;
294  char rwe = wheel_encoder_byte >> 2;
295  char lwep = previous_wheel_encoder_byte % 4;
296  char lwe = wheel_encoder_byte % 4;
297  //pc.printf("L:%d P:%d R:%d P:%d \n",lwe,lwep,rwe,rwep);
298  if(lwe == 0 && lwep==1) left_encoder++;
299  if(lwe == 0 && lwep==2) left_encoder--;
300  if(rwe == 0 && rwep==1) right_encoder++;
301  if(rwe == 0 && rwep==2) right_encoder--;
302  if(left_encoder % 100 == 0) pc.printf("L:%d\n",left_encoder);
303 }
304 
305 void Psiswarm::IF_update_user_id()
306 {
307 }
308 
309 void Psiswarm::IF_update_switch()
310 {
311  // The user switch has changed state
312  // In this implementation we will only act on positive changes (rising edges)
313  // Subtracting new_state from (new_state & old_state) gives the positive changes
314  char positive_change = switch_byte - (switch_byte & previous_switch_byte);
315  if(demo_on) demo.demo_handle_switch_event(positive_change);
316  else handle_switch_event(positive_change);
317 }
318 
320 {
321  left_encoder = 0;
322  right_encoder = 0;
323 }
324 
325 void Psiswarm::debug(const char* format, ...)
326 {
327  char buffer[256];
328  if (debug_mode) {
329  va_list vl;
330  va_start(vl, format);
331  vsprintf(buffer,format,vl);
332  if(debug_output & 2) bt.printf("%s", buffer);
333  if(debug_output & 1) pc.printf("%s", buffer);
334  if(debug_output & 4) display.debug_page(buffer,strlen(buffer));
335  va_end(vl);
336  }
337 }
338 
340 {
341  return uptime.read() + (timer_minute_count * 60);
342 }
343 
344 void Psiswarm::pause_user_code(float period)
345 {
346  user_code_restore_mode = user_code_running;
347  user_code_running = 0;
348  pause_usercode_timeout.attach(this,&Psiswarm::IF_end_pause_user_code, period);
349 }
350 
351 void Psiswarm::IF_end_pause_user_code()
352 {
353  user_code_running = user_code_restore_mode;
354 }
355 
356 void Psiswarm::IF_get_hardware_description()
357 {
358  debug("- Robot serial number %1.2f\n",serial_number);
359  debug("- PCB version %1.2f\n",pcb_version);
360  debug("- Hardware: ");
361  if(has_compass) debug("COMPASS, ");
362  if(has_side_ir) debug("SIDE IR, ");
363  if(has_base_ir) debug("BASE IR, ");
364  if(has_base_colour_sensor) debug("BASE COLOUR, ");
365  if(has_top_colour_sensor) debug("TOP COLOUR, ");
366  if(has_wheel_encoders) debug("WHEEL ENC., ");
367  if(has_audio_pic) debug("AUDIO, ");
368  if(has_ultrasonic_sensor) debug("ULTRASONIC, ");
369  if(has_temperature_sensor) debug("TEMPERATURE, ");
370  if(has_recharging_circuit) debug("RECHARGING, ");
371  if(has_433_radio) debug("433 RADIO.");
372  debug("\n");
373 }
Definition: sound.h:32
Definition: demo.h:36
Definition: colour.h:30
float get_uptime(void)
Definition: psiswarm.cpp:339
Definition: motors.h:46
void init_motors(void)
Definition: motors.cpp:299
char read_firmware(void)
Definition: eprom.cpp:88
void init(void)
Definition: psiswarm.cpp:169
void setup_serial_interfaces(void)
Definition: serial.cpp:54
float get_dc_voltage(void)
Definition: sensors.cpp:101
float get_current(void)
Definition: sensors.cpp:93
Definition: led.h:42
float get_battery_voltage(void)
Definition: sensors.cpp:87
float get_temperature(void)
Definition: sensors.cpp:77
void read_list_of_file_names(void)
Definition: basic.cpp:26
void pause_user_code(float period)
Definition: psiswarm.cpp:344
Definition: eprom.h:41
void debug(const char *format,...)
Definition: psiswarm.cpp:325
void reset_encoders(void)
Definition: psiswarm.cpp:319
void start_demo_mode(void)
Definition: demo.cpp:80
Definition: basic.h:29