-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathArmJoint.cpp
More file actions
127 lines (103 loc) · 3.79 KB
/
Copy pathArmJoint.cpp
File metadata and controls
127 lines (103 loc) · 3.79 KB
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
/**
* @file ArmJoint.cpp
* @author David Sharpe (ds0196@uah.edu)
* @brief
*
*/
#include "ArmJoint.h"
ArmJoint::ArmJoint(AS5047P* setEncoder, float setZeroAngle, float setMinAngle, float setMaxAngle, int setGearRatio, bool setInverted) {
encoder = setEncoder;
zeroAngle = setZeroAngle;
gearRatio = setGearRatio;
inverted = setInverted;
targetAngle = 0;
targetVelocity = 0;
setpointType = SETPOINT_ANGLE;
lastEncoderAngle = 0;
lastEncoderReadTime = 0;
minAngle = setMinAngle;
maxAngle = setMaxAngle;
goalTime = 0;
}
float ArmJoint::readAngle() {
AS5047P_Types::ERROR_t errorInfo;
lastEncoderAngle = clamp_angle(encoder->readAngleDegree(true, &errorInfo, true, true, true));
if (errorInfo.noError()) {
lastEncoderReadTime = millis();
lastEffectiveAngle = clamp_angle(lastEncoderAngle - zeroAngle);
}
return lastEffectiveAngle;
}
void ArmJoint::readREVVelocity(int rpm) {
rpm *= -1;
lastREVVelocity = rpm;
lastREVReadTime = millis();
// Convert motor RPM to joint deg/s
// Lowest gear ratio is 468, largest is 5000
// Meaning, in practice, values range from 6.0 to 128.2
lastDegSVelocity = (float(rpm) * 6.0) / float(gearRatio);
}
double ArmJoint::pid(double pTargetAngle) {
double error = clamp_angle(pTargetAngle - lastEffectiveAngle);
if (abs(error) < PRECISION)
return 0; // Stop if +/- 1 degree
error = (error / 360.0) * static_cast<double>(gearRatio); // Convert to motor rotations from gearbox degrees
integral += error * (dt / 1000.0);
double derivative = (error - prevError) / (dt / 1000.0);
prevError = error;
return kP * error + kI * integral + kD * derivative;
// const double degPerSec = error / (double(goalTime - long(millis())) / 1000.0); // After gearbox
// double motorRPM = (degPerSec * 60.0 / 360.0) * double(gearRatio); // Before gearbox
}
float ArmJoint::updateIKMotion() {
if (static_cast<long>(millis()) - lastEncoderReadTime > dt)
return 0; // Don't move if encoder data is too old
// Calculate motor RPM required to achieve either absolute angle setpoint or velocity setpoint
float motorRPM = 0;
if (setpointType == SETPOINT_ANGLE) {
double pidTargetAngle = targetAngle; // Will come from S-curve
motorRPM = pid(targetAngle);
} else {
if (targetVelocity == 0)
return 0;
// Perform bounds checking -- joint shall not exceed min/max angles within one second
float projectedAngle = lastEffectiveAngle + targetVelocity;
if (lastEffectiveAngle > maxAngle || lastEffectiveAngle < minAngle) {
targetVelocity = 0;
} else if (projectedAngle < minAngle) {
targetVelocity = minAngle - lastEffectiveAngle;
} else if (projectedAngle > maxAngle) {
targetVelocity = maxAngle - lastEffectiveAngle;
}
// Convert deg/sec to motor RPM
motorRPM = (targetVelocity * 60.0 / 360.0) * float(gearRatio);
}
if (motorRPM == 0)
return 0;
motorRPM = clamp_velocity(motorRPM); // Bound motor RPM within MIN_SPEED and MAX_SPEED
if (inverted)
motorRPM *= -1;
return -1 * motorRPM; // Motors turn in the opposite direction of our joint angle convention
}
float clamp_angle(float angle) {
angle = fmod(angle, 360.0);
if (angle < 0) {
angle += 360;
}
if (angle > 180) {
angle -= 360;
}
return angle;
}
float clamp_velocity(float velocity) {
if (velocity > MAX_SPEED) {
return MAX_SPEED;
} else if (velocity < -MAX_SPEED) {
return -MAX_SPEED;
} else if (velocity > 0 && velocity < MIN_SPEED) {
return MIN_SPEED;
} else if (velocity < 0 && velocity > -MIN_SPEED) {
return -MIN_SPEED;
}
return velocity;
}