PsiSwarm Library  0.8
motors.cpp
1 /* University of York Robotics Laboratory PsiSwarm Library: Motor Functions 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: motors.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 Timeout time_based_action_timeout;
26 char brake_when_done = 0;
27 
29 {
30  motor_left_speed = speed;
31  motor_left_brake = 0;
32  IF_update_motors();
33 }
34 
36 {
37  motor_right_speed = speed;
38  motor_right_brake = 0;
39  IF_update_motors();
40 }
41 
43 {
44  motor_left_speed = 0;
45  motor_left_brake = 1;
46  IF_update_motors();
47 }
48 
50 {
51  motor_right_speed = 0;
52  motor_right_brake = 1;
53  IF_update_motors();
54 }
55 
57 {
58  motor_left_speed = 0;
59  motor_right_speed = 0;
60  motor_left_brake = 1;
61  motor_right_brake = 1;
62  IF_update_motors();
63 }
64 
66 {
67  motor_left_speed = 0;
68  motor_right_speed = 0;
69  motor_left_brake = 0;
70  motor_right_brake = 0;
71  IF_update_motors();
72 }
73 
74 void Motors::forward(float speed)
75 {
76  motor_left_speed = speed;
77  motor_right_speed = speed;
78  motor_left_brake = 0;
79  motor_right_brake = 0;
80  IF_update_motors();
81 }
82 
83 void Motors::backward(float speed)
84 {
85  motor_left_speed = -speed;
86  motor_right_speed = -speed;
87  motor_left_brake = 0;
88  motor_right_brake = 0;
89  IF_update_motors();
90 }
91 
92 void Motors::turn(float speed)
93 {
94  //A positive turn is clockwise
95  motor_left_speed = speed;
96  motor_right_speed = -speed;
97  motor_left_brake = 0;
98  motor_right_brake = 0;
99  IF_update_motors();
100 }
101 
102 //Forward for a set period of time
103 void Motors::time_based_forward(float speed, int microseconds, char brake)
104 {
105  //Check if a current time based action is running - if it is, throw a warning and cancel its timeout
106  IF_check_time_for_existing_time_based_action();
107 
108  //Start moving
109  forward(speed);
110  brake_when_done = brake;
111  time_based_action_timeout.attach_us(this,&Motors::IF_end_time_based_action,microseconds);
112 }
113 
114 //Turn for a set period of time
115 void Motors::time_based_turn(float speed, int microseconds, char brake)
116 {
117  //Check if a current time based action is running - if it is, throw a warning and cancel its timeout
118  IF_check_time_for_existing_time_based_action();
119 
120  //Start turning
121  turn(speed);
122  brake_when_done = brake;
123  time_based_action_timeout.attach_us(this,&Motors::IF_end_time_based_action,microseconds);
124 }
125 
126 //Returns the limit of degrees available to turn in given time
127 float Motors::get_maximum_turn_angle(int microseconds)
128 {
129  //We can turn at about 270 degrees per second at full speed
130  return (microseconds * 0.00027);
131 }
132 
133 //Return the time in microseconds that performing the turn will take
134 int Motors::get_time_based_turn_time(float speed, float degrees)
135 {
136  //Check sign of degrees
137  if(degrees < 0) degrees =- degrees;
138 
139  //Main calculation for turn time
140  float turn_time = degrees / ((290 * speed));
141 
142  //Add a hard offset of 4ms to account for start\stop time
143  if(degrees > 4) {
144  turn_time += 0.004;
145  } else turn_time += 0.002;
146 
147  // Add offset for slow speed
148  if(speed<0.31) {
149  float mul_fact = 0.31 - speed;
150  if(mul_fact < 0) mul_fact = 0;
151  mul_fact /= 2;
152  mul_fact += 1;
153  turn_time *= mul_fact;
154  }
155 
156  // Add offset for short turns
157  if(degrees < 360) {
158  float short_offset_multiplier = 1.0 + (0.9 / degrees);
159  turn_time *= short_offset_multiplier;
160  }
161 
162  // Convert to uS
163  turn_time *= 1000000;
164 
165  return (int) turn_time;
166 }
167 
168 //Turn the robot a set number of degrees [using time estimation to end turn]
169 int Motors::time_based_turn_degrees(float speed, float degrees, char brake)
170 {
171  if(speed < 0 || speed > 1 || degrees == 0) {
172  psi.debug("Invalid values to time based turn: speed=%f degrees=$f\n",speed,degrees);
173  return 0;
174  } else {
175  //Check if a current time based action is running - if it is, throw a warning and cancel its timeout
176  IF_check_time_for_existing_time_based_action();
177 
178  //Calculate turn time using get_time_based_turn_time
179  int turn_time = get_time_based_turn_time(speed,degrees);
180 
181  //Set correct turn direction (-degrees is a counter-clockwise turn)
182  if(degrees < 0) {
183  degrees=-degrees;
184  speed=-speed;
185  }
186 
187  //Start turning
188  turn(speed);
189 
190  brake_when_done = brake;
191  time_based_action_timeout.attach_us(this,&Motors::IF_end_time_based_action,turn_time);
192  return turn_time;
193  }
194 }
195 
196 //Check if a current time based action is running - if it is, throw a warning and cancel its timeout
197 void Motors::IF_check_time_for_existing_time_based_action()
198 {
199  if(time_based_motor_action == 1) {
200  time_based_action_timeout.detach();
201  psi.debug("WARNING: New time-based action called before previous action finished!\n");
202  } else time_based_motor_action = 1;
203 }
204 
205 void Motors::IF_end_time_based_action()
206 {
207  if(brake_when_done == 1)brake();
208  else stop();
209  time_based_motor_action = 0;
210 }
211 
212 void Motors::IF_update_motors()
213 {
214  if(motor_left_speed > 1.0) {
215  motor_left_speed = 1.0;
216  //Throw exception...
217  }
218  if(motor_right_speed > 1.0) {
219  motor_right_speed = 1.0;
220  //Throw exception...
221  }
222  if(motor_left_speed < -1.0) {
223  motor_left_speed = -1.0;
224  //Throw exception...
225  }
226  if(motor_right_speed < -1.0) {
227  motor_right_speed = -1.0;
228  //Throw exception...
229  }
230  if(motor_left_brake) {
231  motor_left_f.write(1);
232  motor_left_r.write(1);
233  if(motor_left_speed!=0) {
234  motor_left_speed = 0;
235  //Throw exception...
236  }
237  } else {
238  if(motor_left_speed >= 0) {
239  motor_left_f.write(0);
240  motor_left_r.write(IF_calibrated_left_speed(motor_left_speed));
241 
242  } else {
243  motor_left_r.write(0);
244  motor_left_f.write(IF_calibrated_left_speed(-motor_left_speed));
245  }
246  }
247  if(motor_right_brake) {
248  motor_right_f.write(1);
249  motor_right_r.write(1);
250  if(motor_right_speed!=0) {
251  motor_right_speed = 0;
252  //Throw exception...
253  }
254  } else {
255  if(motor_right_speed >= 0) {
256  motor_right_f.write(0);
257  motor_right_r.write(IF_calibrated_right_speed(motor_right_speed));
258  } else {
259  motor_right_r.write(0);
260  motor_right_f.write(IF_calibrated_right_speed(-motor_right_speed));
261  }
262  }
263 
264 }
265 
266 
267 float Motors::IF_calibrated_left_speed(float speed)
268 {
269  //Takes the input value, adds an offset if OFFSET_MOTORS enabled and weights the value if USE_MOTOR_CALIBRATION enabled
270  float adjusted = IF_calibrated_speed(speed);
271  if(use_motor_calibration) {
272  adjusted *= left_motor_calibration_value;
273  }
274  return adjusted;
275 }
276 
277 float Motors::IF_calibrated_right_speed(float speed)
278 {
279  //Takes the input value, adds an offset if OFFSET_MOTORS enabled and weights the value if USE_MOTOR_CALIBRATION enabled
280  float adjusted = IF_calibrated_speed(speed);
281  if(use_motor_calibration) {
282  adjusted *= right_motor_calibration_value;
283  }
284  return adjusted;
285 }
286 
287 float Motors::IF_calibrated_speed(float speed)
288 {
289  if(speed == 0) return 0;
290  //Converts an input value to take account of the stall speed of the motor; aims to produce a more linear speed
291  float adjusted = speed;
292  if(OFFSET_MOTORS) {
293  adjusted*=0.8f;
294  adjusted+=0.2;
295  }
296  return adjusted;
297 }
298 
300 {
301  // Motor PWM outputs work optimally at 25kHz frequency
302  motor_left_f.period_us(40);
303  motor_right_f.period_us(40);
304  motor_left_r.period_us(40);
305  motor_right_r.period_us(40);
306  motor_left_speed = 0;
307  motor_right_speed = 0;
308  motor_left_brake = 0;
309  motor_right_brake = 0;
310  IF_update_motors();
311 }
void time_based_turn(float speed, int microseconds, char brake)
Definition: motors.cpp:115
void init_motors(void)
Definition: motors.cpp:299
void brake_right_motor(void)
Definition: motors.cpp:49
void brake(void)
Definition: motors.cpp:56
void turn(float speed)
Definition: motors.cpp:92
void time_based_forward(float speed, int microseconds, char brake)
Definition: motors.cpp:103
void set_left_motor_speed(float speed)
Definition: motors.cpp:28
void backward(float speed)
Definition: motors.cpp:83
void stop(void)
Definition: motors.cpp:65
void brake_left_motor(void)
Definition: motors.cpp:42
void debug(const char *format,...)
Definition: psiswarm.cpp:325
void set_right_motor_speed(float speed)
Definition: motors.cpp:35
void forward(float speed)
Definition: motors.cpp:74