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