forked from ArduPilot/ardupilot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
control_motordetect.cpp
174 lines (158 loc) · 5.59 KB
/
control_motordetect.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include "Sub.h"
#include "stdio.h"
/*
* control_motordetect.cpp - init and run calls for motordetect flightmode;
*
* This mode pulses all thrusters to detect if they need to be reversed.
* This still requires that the user has the correct frame selected and the motors
* are connected to the correct ESCs.
*
* For each motor:
* wait until vehicle is stopped for > 500ms
* apply throttle up for 500ms
* If results are good:
* save direction and try the next motor.
* else
* wait until vehicle is stopped for > 500ms
* apply throttle down for 500ms
* If results are good
* save direction and try the next motor.
* If results are bad
* Abort!
*/
namespace {
// controller states
enum test_state {
STANDBY,
SETTLING,
THRUSTING,
DETECTING,
DONE
};
enum direction {
UP = 1,
DOWN = -1
};
static uint32_t settling_timer;
static uint32_t thrusting_timer;
static uint8_t md_state;
static uint8_t current_motor;
static int16_t current_direction;
}
bool Sub::motordetect_init()
{
current_motor = 0;
md_state = STANDBY;
current_direction = UP;
return true;
}
void Sub::motordetect_run()
{
// if not armed set throttle to zero and exit immediately
if (!motors.armed()) {
motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
// Force all motors to stop
for(uint8_t i=0; i < AP_MOTORS_MAX_NUM_MOTORS; i++) {
if (motors.motor_is_enabled(i)) {
motors.output_test_num(i, 1500);
}
}
md_state = STANDBY;
return;
}
switch(md_state) {
// Motor detection is not running, set it up to start.
case STANDBY:
current_direction = UP;
current_motor = 0;
settling_timer = AP_HAL::millis();
md_state = SETTLING;
break;
// Wait until sub stays for 500ms not spinning and leveled.
case SETTLING:
// Force all motors to stop
for (uint8_t i=0; i <AP_MOTORS_MAX_NUM_MOTORS; i++) {
if (motors.motor_is_enabled(i)) {
motors.output_test_num(i, 1500);
}
}
// wait until gyro product is under a certain(experimental) threshold
if ((ahrs.get_gyro()*ahrs.get_gyro()) > 0.01) {
settling_timer = AP_HAL::millis();
}
// then wait 500ms more
if (AP_HAL::millis() > (settling_timer + 500)) {
md_state = THRUSTING;
thrusting_timer = AP_HAL::millis();
}
break;
// Thrusts motor for 500ms
case THRUSTING:
if (AP_HAL::millis() < (thrusting_timer + 500)) {
if (!motors.output_test_num(current_motor, 1500 + 300*current_direction)) {
md_state = DONE;
};
} else {
md_state = DETECTING;
}
break;
// Checks the result of thrusting the motor.
// Starts again at the other direction if unable to get a good reading.
// Fails if it is the second reading and it is still not good.
// Set things up to test the next motor if the reading is good.
case DETECTING:
{
// This logic results in a vector such as (1, -1, 0)
// TODO: make these thresholds parameters
Vector3f gyro = ahrs.get_gyro();
bool roll_up = gyro.x > 0.4;
bool roll_down = gyro.x < -0.4;
int roll = (int(roll_up) - int(roll_down))*current_direction;
bool pitch_up = gyro.y > 0.4;
bool pitch_down = gyro.y < -0.4;
int pitch = (int(pitch_up) - int(pitch_down))*current_direction;
bool yaw_up = gyro.z > 0.5;
bool yaw_down = gyro.z < -0.5;
int yaw = (+int(yaw_up) - int(yaw_down))*current_direction;
Vector3f directions(roll, pitch, yaw);
// Good read, not inverted
if (directions == motors.get_motor_angular_factors(current_motor)) {
gcs().send_text(MAV_SEVERITY_INFO, "Thruster %d is ok!", current_motor + 1);
}
// Good read, inverted
else if (-directions == motors.get_motor_angular_factors(current_motor)) {
gcs().send_text(MAV_SEVERITY_INFO, "Thruster %d is reversed! Saving it!", current_motor + 1);
motors.set_reversed(current_motor, true);
}
// Bad read!
else {
gcs().send_text(MAV_SEVERITY_INFO, "Bad thrust read, trying to push the other way...");
// If we got here, we couldn't identify anything that made sense.
// Let's try pushing the thruster the other way, maybe we are in too shallow waters or hit something
if (current_direction == DOWN) {
// The reading for the second direction was also bad, we failed.
gcs().send_text(MAV_SEVERITY_WARNING, "Failed! Please check Thruster %d and frame setup!", current_motor + 1);
md_state = DONE;
break;
}
current_direction = DOWN;
md_state = SETTLING;
break;
}
// If we got here, we have a decent motor reading
md_state = SETTLING;
// Test the next motor, if it exists
current_motor++;
current_direction = UP;
if (!motors.motor_is_enabled(current_motor)) {
md_state = DONE;
gcs().send_text(MAV_SEVERITY_WARNING, "Motor direction detection is complete.");
}
break;
}
case DONE:
control_mode = prev_control_mode;
arming.disarm(AP_Arming::Method::MOTORDETECTDONE);
break;
}
}