-
Notifications
You must be signed in to change notification settings - Fork 3
/
05.motor.ino
146 lines (118 loc) · 4.1 KB
/
05.motor.ino
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
const unsigned int MOTOR_POLE_PAIRS = 15;
const unsigned int MOTOR_VOLTAGE_LIMIT = 9;
const unsigned int MOTOR_VOLTAGE_LIMIT_FOR_ALIGNMENT = 3;
BLDCMotor motor = BLDCMotor(MOTOR_POLE_PAIRS);
unsigned int lastMotorRequestMillis = 0;
float lastMotorRequestVoltage = 0;
// ZEA: Zero electrical angle
float zea;
void setRequestVoltage(float v) {
lastMotorRequestVoltage = v;
lastMotorRequestMillis = millis();
}
float voltageMultiplierByVelo() {
float mapIn[] = { -21, 0, 21 };
float mapOut[] = { 2, 1, 2 };
float mapResult = multiMap<float>(lastVelo, mapIn, mapOut, 3);
return mapResult;
}
float zeaOffsetByVelo() {
float mapIn[] = { -5, 0, 5 };
float mapOut[] = { .8, 0, -.8 };
float mapResult = multiMap<float>(lastVelo, mapIn, mapOut, 3);
if (mapResult > .8) mapResult = .8;
if (mapResult < -.8) mapResult = -.8;
return mapResult * motor.sensor_direction;
}
void motorSetup() {
motor.linkSensor(&sensor);
motor.linkDriver(&driver);
motor.target = 0;
motor.voltage_limit = MOTOR_VOLTAGE_LIMIT;
motor.voltage_sensor_align = MOTOR_VOLTAGE_LIMIT_FOR_ALIGNMENT;
motor.velocity_limit = 60;
motor.controller = MotionControlType::torque;
motor.torque_controller = TorqueControlType::voltage;
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
motor.motion_downsample = 1;
motor.init();
sensorLinearizer();
motor.initFOC();
zea = motor.zero_electric_angle;
}
void motorLoop() {
// If motor disabled, just update the sensor value
// to make the steering wheel still usable without force feedback.
if (motor.enabled == false) {
sensor.update();
return;
}
// Safety:
// Stop the motor if not receive any request after 500ms
// since last command.
if (millis() - lastMotorRequestMillis > 500) {
lastMotorRequestVoltage = 0;
}
// Normal FOC routine.
motor.zero_electric_angle = zea + zeaOffsetByVelo();
motor.target = lastMotorRequestVoltage * voltageMultiplierByVelo();
motor.loopFOC();
motor.move();
}
// call this after motor.init() and before motor.initFOC()
void sensorLinearizer() {
float elAngle = _3PI_2;
const int transition = 500;
float rp[MOTOR_POLE_PAIRS];
// collect raw positions for each home pole pair
for (int i = 0; i < MOTOR_POLE_PAIRS; i++) {
motor.setPhaseVoltage(MOTOR_VOLTAGE_LIMIT_FOR_ALIGNMENT, 0, elAngle);
_delay(700);
sensor.update();
rp[i] = float(currentRawPosition);
for (int j = 0; j < transition; j++) {
elAngle = elAngle + (_2PI / transition);
motor.setPhaseVoltage(MOTOR_VOLTAGE_LIMIT_FOR_ALIGNMENT, 0, elAngle);
sensor.update();
_delay(1);
}
}
// sort raw positions, ascending
int rpArraySize = sizeof(rp) / sizeof(rp[0]);
KickSort<float>::insertionSort(rp, rpArraySize);
// calculating the corrected positions
float cp[MOTOR_POLE_PAIRS];
float regulerDistance = float(SENSOR_PPR) / float(MOTOR_POLE_PAIRS);
for (int i = 0; i < MOTOR_POLE_PAIRS; i++) {
if (i == 0) cp[i] = rp[i];
else {
float correctedPos = cp[i - 1] + regulerDistance;
if (correctedPos < 0) correctedPos += float(SENSOR_PPR);
else if (correctedPos >= float(SENSOR_PPR)) correctedPos -= float(SENSOR_PPR);
cp[i] = correctedPos;
}
}
float rp2[MOTOR_POLE_PAIRS + 2];
float cp2[MOTOR_POLE_PAIRS + 2];
// add last position to the front so it's connecting to the first position when rotating over
rp2[0] = rp[MOTOR_POLE_PAIRS - 1] - float(SENSOR_PPR);
cp2[0] = cp[MOTOR_POLE_PAIRS - 1] - float(SENSOR_PPR);
// copy existing data
for (int i = 0; i < MOTOR_POLE_PAIRS; i++) {
rp2[i + 1] = rp[i];
cp2[i + 1] = cp[i];
}
// add first position to the end so it's connecting to the last position when rotating over
rp2[MOTOR_POLE_PAIRS + 1] = float(SENSOR_PPR) + rp[0];
cp2[MOTOR_POLE_PAIRS + 1] = float(SENSOR_PPR) + cp[0];
// map all the possible positions
for (int i = 0; i < SENSOR_PPR; i++) {
float pf = multiMap<float>(i, rp2, cp2, MOTOR_POLE_PAIRS + 2);
int p = int(round(pf));
if (p < 0) p += SENSOR_PPR;
else if (p >= SENSOR_PPR) p -= SENSOR_PPR;
linearized[i] = p;
}
overRotation = 0;
linearizationDone = true;
}