2014 Eurobot fork
Dependencies: mbed-rtos mbed QEI
Processes/Motion/motion.cpp@85:b0858346d838, 2013-04-16 (annotated)
- Committer:
- madcowswe
- Date:
- Tue Apr 16 10:43:15 2013 +0000
- Revision:
- 85:b0858346d838
- Parent:
- 81:ef1ce4f5322b
- Child:
- 88:8850373c3f0d
diff
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
rsavitski | 24:50805ef8c499 | 1 | //////////////////////////////////////////////////////////////////////////////// |
rsavitski | 24:50805ef8c499 | 2 | // Motion control unit |
rsavitski | 24:50805ef8c499 | 3 | //////////////////////////////////////////////////////////////////////////////// |
rsavitski | 69:4b7bb92916da | 4 | // Takes current state and motion command (set via accessors) and actuates it via motor layer calls |
rsavitski | 24:50805ef8c499 | 5 | //////////////////////////////////////////////////////////////////////////////// |
rsavitski | 24:50805ef8c499 | 6 | |
rsavitski | 81:ef1ce4f5322b | 7 | //todo: check everything is properly initialised and not a race condition |
rsavitski | 81:ef1ce4f5322b | 8 | |
rsavitski | 24:50805ef8c499 | 9 | #include "motion.h" |
rsavitski | 57:d434ceab6892 | 10 | #include "math.h" |
rsavitski | 57:d434ceab6892 | 11 | #include "Kalman.h" |
rsavitski | 57:d434ceab6892 | 12 | #include "MotorControl.h" |
rsavitski | 57:d434ceab6892 | 13 | #include "supportfuncs.h" |
madcowswe | 66:f1d75e51398d | 14 | #include "AvoidDstSensor.h" |
rsavitski | 57:d434ceab6892 | 15 | |
rsavitski | 57:d434ceab6892 | 16 | namespace motion |
rsavitski | 57:d434ceab6892 | 17 | { |
rsavitski | 57:d434ceab6892 | 18 | // private function prototypes |
rsavitski | 57:d434ceab6892 | 19 | |
rsavitski | 57:d434ceab6892 | 20 | void setWaypointReached(); |
rsavitski | 57:d434ceab6892 | 21 | void clearMotionCmd(); |
rsavitski | 57:d434ceab6892 | 22 | void clearWaypoint(); |
rsavitski | 57:d434ceab6892 | 23 | } |
rsavitski | 38:c9058a401410 | 24 | |
rsavitski | 24:50805ef8c499 | 25 | namespace motion |
rsavitski | 24:50805ef8c499 | 26 | { |
rsavitski | 24:50805ef8c499 | 27 | |
rsavitski | 70:0da6ca845762 | 28 | volatile int collavoiden = 0; // TODO: kill oskar's code |
rsavitski | 70:0da6ca845762 | 29 | AvoidDstSensor ADS(P_FWD_DISTANCE_SENSOR); //TODO: kill oskar's hack |
madcowswe | 66:f1d75e51398d | 30 | |
rsavitski | 57:d434ceab6892 | 31 | // motion commands supported |
rsavitski | 57:d434ceab6892 | 32 | enum motion_type_t { motion_waypoint }; |
rsavitski | 57:d434ceab6892 | 33 | |
rsavitski | 57:d434ceab6892 | 34 | struct motion_cmd |
rsavitski | 57:d434ceab6892 | 35 | { |
rsavitski | 57:d434ceab6892 | 36 | motion_type_t motion_type; |
rsavitski | 57:d434ceab6892 | 37 | osThreadId setter_tid; |
rsavitski | 57:d434ceab6892 | 38 | |
rsavitski | 57:d434ceab6892 | 39 | bool motion_done; |
rsavitski | 57:d434ceab6892 | 40 | |
rsavitski | 57:d434ceab6892 | 41 | union |
rsavitski | 57:d434ceab6892 | 42 | { |
rsavitski | 57:d434ceab6892 | 43 | Waypoint *wp_ptr; |
rsavitski | 57:d434ceab6892 | 44 | }; |
rsavitski | 57:d434ceab6892 | 45 | |
rsavitski | 57:d434ceab6892 | 46 | }; |
rsavitski | 57:d434ceab6892 | 47 | |
rsavitski | 57:d434ceab6892 | 48 | // local copy of the current active motion |
rsavitski | 76:532d9bc1d2aa | 49 | motion_cmd current_motion = {motion_waypoint, 0, false, NULL}; |
rsavitski | 57:d434ceab6892 | 50 | |
rsavitski | 70:0da6ca845762 | 51 | Waypoint target_waypoint = {0,0,0,0,0}; //local wp copy, TODO: fix and make a shared local memory pool for any movement cmd to be copied to |
rsavitski | 70:0da6ca845762 | 52 | |
rsavitski | 39:44d3dea4adcc | 53 | Mutex waypoint_flag_mutex; |
rsavitski | 39:44d3dea4adcc | 54 | |
rsavitski | 57:d434ceab6892 | 55 | // local to waypoint motion handler |
rsavitski | 57:d434ceab6892 | 56 | bool wp_d_reached = false; |
rsavitski | 57:d434ceab6892 | 57 | bool wp_a_reached = false; |
rsavitski | 39:44d3dea4adcc | 58 | |
rsavitski | 39:44d3dea4adcc | 59 | |
rsavitski | 24:50805ef8c499 | 60 | void motionlayer(void const *dummy) |
rsavitski | 57:d434ceab6892 | 61 | { |
rsavitski | 57:d434ceab6892 | 62 | switch (current_motion.motion_type) |
rsavitski | 57:d434ceab6892 | 63 | { |
rsavitski | 57:d434ceab6892 | 64 | case motion_waypoint: |
rsavitski | 57:d434ceab6892 | 65 | waypoint_motion_handler(); |
rsavitski | 57:d434ceab6892 | 66 | break; |
rsavitski | 57:d434ceab6892 | 67 | default: |
rsavitski | 57:d434ceab6892 | 68 | break; |
rsavitski | 57:d434ceab6892 | 69 | } |
rsavitski | 57:d434ceab6892 | 70 | } |
rsavitski | 57:d434ceab6892 | 71 | |
rsavitski | 57:d434ceab6892 | 72 | void waypoint_motion_handler() |
rsavitski | 57:d434ceab6892 | 73 | { |
rsavitski | 39:44d3dea4adcc | 74 | // save target waypoint |
rsavitski | 70:0da6ca845762 | 75 | //Waypoint target_waypoint = *current_motion.wp_ptr; |
rsavitski | 70:0da6ca845762 | 76 | |
rsavitski | 24:50805ef8c499 | 77 | |
rsavitski | 24:50805ef8c499 | 78 | // get current state from Kalman |
rsavitski | 24:50805ef8c499 | 79 | State current_state = Kalman::getState(); |
rsavitski | 24:50805ef8c499 | 80 | |
rsavitski | 24:50805ef8c499 | 81 | float delta_x = target_waypoint.x - current_state.x; |
rsavitski | 24:50805ef8c499 | 82 | float delta_y = target_waypoint.y - current_state.y; |
rsavitski | 24:50805ef8c499 | 83 | |
madcowswe | 25:b16f1045108f | 84 | //printf("motion sees deltax: %f deltay %f\r\n", delta_x, delta_y); |
rsavitski | 24:50805ef8c499 | 85 | |
madcowswe | 25:b16f1045108f | 86 | float distance_err = hypot(delta_x, delta_y); |
madcowswe | 25:b16f1045108f | 87 | |
madcowswe | 25:b16f1045108f | 88 | float angle_err = constrainAngle(atan2(delta_y, delta_x) - current_state.theta); |
rsavitski | 24:50805ef8c499 | 89 | |
rsavitski | 57:d434ceab6892 | 90 | // reversing if close to target and more optimal than forward movement |
rsavitski | 52:bffe5f7c39a3 | 91 | bool reversing = false; |
rsavitski | 57:d434ceab6892 | 92 | if ((abs(angle_err) > PI/2) && (distance_err < 0.2)) //TODO: parameterise and tune 0.2 meters hardcoded |
rsavitski | 52:bffe5f7c39a3 | 93 | { |
rsavitski | 52:bffe5f7c39a3 | 94 | reversing = true; |
rsavitski | 52:bffe5f7c39a3 | 95 | angle_err = constrainAngle(angle_err + PI); |
rsavitski | 52:bffe5f7c39a3 | 96 | distance_err = -distance_err; |
rsavitski | 52:bffe5f7c39a3 | 97 | } |
rsavitski | 52:bffe5f7c39a3 | 98 | |
rsavitski | 52:bffe5f7c39a3 | 99 | float angle_err_saved = angle_err; // actuated angle error can be overriden by the final turning code, but forward speed envelope should be controlled with the atan angle |
rsavitski | 52:bffe5f7c39a3 | 100 | |
rsavitski | 30:791739422122 | 101 | // is the waypoint reached |
rsavitski | 81:ef1ce4f5322b | 102 | waypoint_flag_mutex.lock(); //TODO: consider refactoring, mutexes suck, switch to semaphore style or more contained mutexes (think of several producers as well); race conditions not checked atm either |
rsavitski | 57:d434ceab6892 | 103 | if (abs(distance_err) < ((wp_d_reached) ? target_waypoint.pos_threshold+0.02 : target_waypoint.pos_threshold)) |
rsavitski | 30:791739422122 | 104 | { |
rsavitski | 57:d434ceab6892 | 105 | wp_d_reached = true; |
rsavitski | 38:c9058a401410 | 106 | |
rsavitski | 52:bffe5f7c39a3 | 107 | angle_err = constrainAngle(target_waypoint.theta - current_state.theta); |
rsavitski | 38:c9058a401410 | 108 | |
rsavitski | 38:c9058a401410 | 109 | if (abs(angle_err) < target_waypoint.angle_threshold) |
madcowswe | 33:a49197572737 | 110 | { |
rsavitski | 57:d434ceab6892 | 111 | wp_a_reached = true; |
madcowswe | 33:a49197572737 | 112 | } |
rsavitski | 35:f8e7f0a72a3d | 113 | } |
rsavitski | 65:4709ff6c753c | 114 | // proper way would be to construct a function to evaluate the condition and pass the function pointer to a conditional setter function for reached flag |
rsavitski | 57:d434ceab6892 | 115 | if (wp_d_reached && wp_a_reached) |
rsavitski | 30:791739422122 | 116 | { |
rsavitski | 39:44d3dea4adcc | 117 | setWaypointReached(); |
rsavitski | 30:791739422122 | 118 | } |
rsavitski | 39:44d3dea4adcc | 119 | waypoint_flag_mutex.unlock(); |
rsavitski | 24:50805ef8c499 | 120 | |
rsavitski | 24:50805ef8c499 | 121 | // angular velocity controller |
rsavitski | 70:0da6ca845762 | 122 | const float p_gain_av = 1;//0.7; //TODO: tune |
rsavitski | 24:50805ef8c499 | 123 | |
rsavitski | 70:0da6ca845762 | 124 | const float max_av = 1;//0.5; // radians per sec //TODO: tune |
rsavitski | 24:50805ef8c499 | 125 | |
rsavitski | 24:50805ef8c499 | 126 | // angle error [-pi, pi] |
rsavitski | 24:50805ef8c499 | 127 | float angular_v = p_gain_av * angle_err; |
rsavitski | 24:50805ef8c499 | 128 | |
rsavitski | 24:50805ef8c499 | 129 | // constrain range |
rsavitski | 24:50805ef8c499 | 130 | if (angular_v > max_av) |
rsavitski | 24:50805ef8c499 | 131 | angular_v = max_av; |
rsavitski | 24:50805ef8c499 | 132 | else if (angular_v < -max_av) |
rsavitski | 24:50805ef8c499 | 133 | angular_v = -max_av; |
rsavitski | 24:50805ef8c499 | 134 | |
rsavitski | 24:50805ef8c499 | 135 | |
rsavitski | 24:50805ef8c499 | 136 | // forward velocity controller |
madcowswe | 85:b0858346d838 | 137 | const float p_gain_fv = 0.85;//0.7; //TODO: tune |
rsavitski | 24:50805ef8c499 | 138 | |
rsavitski | 70:0da6ca845762 | 139 | float max_fv = 0.3;//0.2; // meters per sec //TODO: tune |
rsavitski | 77:8d83a0c00e66 | 140 | float max_fv_reverse = 0.03; //TODO: tune |
madcowswe | 67:be3ea5450cc7 | 141 | const float angle_envelope_exponent = 32;//512; //8.0; //TODO: tune |
rsavitski | 24:50805ef8c499 | 142 | |
rsavitski | 24:50805ef8c499 | 143 | // control, distance_err in meters |
rsavitski | 24:50805ef8c499 | 144 | float forward_v = p_gain_fv * distance_err; |
rsavitski | 24:50805ef8c499 | 145 | |
rsavitski | 52:bffe5f7c39a3 | 146 | // if reversing, robot is less stable hence a different cap is used |
rsavitski | 52:bffe5f7c39a3 | 147 | if (reversing) |
rsavitski | 52:bffe5f7c39a3 | 148 | max_fv = max_fv_reverse; |
rsavitski | 52:bffe5f7c39a3 | 149 | |
rsavitski | 24:50805ef8c499 | 150 | // control the forward velocity envelope based on angular error |
rsavitski | 77:8d83a0c00e66 | 151 | max_fv = max_fv * pow(cos(angle_err_saved/2), /*angle_envelope_exponent*/target_waypoint.angle_exponent); //temp hack |
rsavitski | 24:50805ef8c499 | 152 | |
rsavitski | 24:50805ef8c499 | 153 | // constrain range |
rsavitski | 24:50805ef8c499 | 154 | if (forward_v > max_fv) |
rsavitski | 24:50805ef8c499 | 155 | forward_v = max_fv; |
rsavitski | 24:50805ef8c499 | 156 | else if (forward_v < -max_fv) |
rsavitski | 24:50805ef8c499 | 157 | forward_v = -max_fv; |
madcowswe | 25:b16f1045108f | 158 | |
madcowswe | 25:b16f1045108f | 159 | //printf("fwd: %f, omega: %f\r\n", forward_v, angular_v); |
rsavitski | 24:50805ef8c499 | 160 | |
rsavitski | 69:4b7bb92916da | 161 | //TODO: remove oskar's avoidance hack |
rsavitski | 69:4b7bb92916da | 162 | if(collavoiden) |
rsavitski | 69:4b7bb92916da | 163 | { |
madcowswe | 66:f1d75e51398d | 164 | float d = ADS.Distanceincm(); |
rsavitski | 69:4b7bb92916da | 165 | if(d > 10) |
rsavitski | 69:4b7bb92916da | 166 | { |
madcowswe | 72:7996aa8286ae | 167 | forward_v *= max(min((d-15)*(1.0f/25.0f),1.0f),-0.1f); |
madcowswe | 66:f1d75e51398d | 168 | } |
madcowswe | 66:f1d75e51398d | 169 | } |
rsavitski | 69:4b7bb92916da | 170 | // end of Oskar hack |
madcowswe | 66:f1d75e51398d | 171 | |
rsavitski | 30:791739422122 | 172 | // pass values to the motor control |
rsavitski | 24:50805ef8c499 | 173 | MotorControl::set_fwdcmd(forward_v); |
madcowswe | 25:b16f1045108f | 174 | MotorControl::set_omegacmd(angular_v); |
rsavitski | 24:50805ef8c499 | 175 | } |
rsavitski | 24:50805ef8c499 | 176 | |
rsavitski | 57:d434ceab6892 | 177 | |
rsavitski | 57:d434ceab6892 | 178 | bool checkMotionStatus() |
rsavitski | 57:d434ceab6892 | 179 | { |
rsavitski | 57:d434ceab6892 | 180 | return current_motion.motion_done; |
rsavitski | 57:d434ceab6892 | 181 | } |
rsavitski | 57:d434ceab6892 | 182 | |
rsavitski | 57:d434ceab6892 | 183 | |
rsavitski | 57:d434ceab6892 | 184 | void setNewWaypoint(osThreadId setter_tid_in, Waypoint *new_wp) |
rsavitski | 39:44d3dea4adcc | 185 | { |
rsavitski | 57:d434ceab6892 | 186 | clearMotionCmd(); |
rsavitski | 57:d434ceab6892 | 187 | |
rsavitski | 57:d434ceab6892 | 188 | current_motion.setter_tid = setter_tid_in; |
rsavitski | 57:d434ceab6892 | 189 | current_motion.motion_type = motion_waypoint; |
rsavitski | 57:d434ceab6892 | 190 | |
rsavitski | 70:0da6ca845762 | 191 | target_waypoint = *new_wp; |
rsavitski | 39:44d3dea4adcc | 192 | } |
rsavitski | 39:44d3dea4adcc | 193 | |
rsavitski | 57:d434ceab6892 | 194 | |
rsavitski | 39:44d3dea4adcc | 195 | void setWaypointReached() |
rsavitski | 39:44d3dea4adcc | 196 | { |
rsavitski | 57:d434ceab6892 | 197 | current_motion.motion_done = true; |
rsavitski | 57:d434ceab6892 | 198 | osSignalSet(current_motion.setter_tid,0x1); |
rsavitski | 39:44d3dea4adcc | 199 | } |
rsavitski | 39:44d3dea4adcc | 200 | |
rsavitski | 57:d434ceab6892 | 201 | |
rsavitski | 57:d434ceab6892 | 202 | void clearMotionCmd() |
rsavitski | 39:44d3dea4adcc | 203 | { |
rsavitski | 57:d434ceab6892 | 204 | current_motion.motion_done = false; |
rsavitski | 57:d434ceab6892 | 205 | osSignalClear(current_motion.setter_tid, 0x1); |
rsavitski | 57:d434ceab6892 | 206 | |
rsavitski | 57:d434ceab6892 | 207 | switch (current_motion.motion_type) |
rsavitski | 57:d434ceab6892 | 208 | { |
rsavitski | 57:d434ceab6892 | 209 | case motion_waypoint: |
rsavitski | 57:d434ceab6892 | 210 | clearWaypoint(); |
rsavitski | 57:d434ceab6892 | 211 | break; |
rsavitski | 57:d434ceab6892 | 212 | |
rsavitski | 57:d434ceab6892 | 213 | default: |
rsavitski | 57:d434ceab6892 | 214 | break; |
rsavitski | 57:d434ceab6892 | 215 | } |
rsavitski | 39:44d3dea4adcc | 216 | } |
rsavitski | 39:44d3dea4adcc | 217 | |
rsavitski | 57:d434ceab6892 | 218 | |
rsavitski | 57:d434ceab6892 | 219 | void clearWaypoint() |
rsavitski | 39:44d3dea4adcc | 220 | { |
rsavitski | 57:d434ceab6892 | 221 | wp_d_reached = false; |
rsavitski | 57:d434ceab6892 | 222 | wp_a_reached = false; |
rsavitski | 39:44d3dea4adcc | 223 | } |
rsavitski | 39:44d3dea4adcc | 224 | |
rsavitski | 24:50805ef8c499 | 225 | } //namespace |