-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathservos.hpp
227 lines (210 loc) · 6.13 KB
/
servos.hpp
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include <string>
#include <map>
#include <gazebo/physics/physics.hh>
#include <gazebo/common/common.hh>
#include <gazebo/transport/transport.hh>
#include <queue>
class WindowFilter
{
public:
WindowFilter(unsigned int nb)
{
assert(nb!= 0);//so that we have no division by 0, and it makes no sense for a filter
nb_samples = nb;
startNb = 0;
sum = 0;
}
private:
unsigned int nb_samples;
unsigned int startNb;
public:
std::queue<double> q;
double sum;
void addMeasure(double m)
{
q.push(m);//push to the back
sum+= m;
if(startNb<nb_samples)
{
startNb++;
}
else
{
sum-= q.front();
q.pop();//pop from the front
}
}
double read()
{
//startNb is equal to nb_samples after the sart sequence
//std::cout << "sum " << sum << " ; nb " << startNb << " : ";
return sum / startNb;
}
double add_read(double val)
{
addMeasure(val);
return read();
}
};
class PowerFilter
{
public:
PowerFilter(unsigned int nb)
{
assert(nb!= 0);//so that we have no division by 0, and it makes no sense for a filter
nb_samples = nb;
startNb = 0;
prev = 0;
sum = 0;
}
private:
unsigned int nb_samples;
unsigned int startNb;
public:
std::queue<double> q;
double sum;
double prev;
void addMeasure(double m)
{
double sample = abs(prev - m);
q.push(sample);//push to the back
sum+= sample;
prev = m;//the last pushed at the back
if(startNb<nb_samples)
{
startNb++;
}
else
{
sum-= q.front();
q.pop();//pop from the front
}
}
double read()
{
//startNb is equal to nb_samples after the sart sequence
//std::cout << "sum " << sum << " ; nb " << startNb << " : ";
return sum / startNb;
}
double add_read(double val)
{
addMeasure(val);
return read();
}
};
enum class ServoType { PID, DC};
class DCModel
{
public:
DCModel();
//Input Control Parameter
double Voltage;//Applied Voltage V
//Motor Static Params
double Ra,La;//Resistance and inductance of the armature circuit
double Ki;//current constant
double Kv;//Voltage constant
double reduction;
//Motor State Params
double counterElF;//Counter Electromotive Force V
double current;//Armature current
double prevcurrent;
double didt;//current derivate
//Output result, to apply to the Joint
double torque;//Motor Torque
//input from the Physics engine
double speed;//Rotation (rad/s)
public:
void step(double dt);
void reset();
public:
void setParams(double r,double l, double ki, double kv); //on init
void control(double v); //input regulate
};
class Servo
{
public:
const double min_dt = 1.e-6;//microsecond - it does not make sense to go that far, error likeliness
const double max_dt = 5.e-3;//milisecond - it gets close to the time constants
public:
Servo();
void Set_ax12a();
void Advertise_ax12a(const std::string &servo_topic_path);
private:
bool safe_dt(double simtime,double &dt);
double prevtime;
public:
std::string name;
ServoType type;
gazebo::common::PID *pid; //Direct Axis Control PID
DCModel *dc;
gazebo::common::PID *pos_pid;
gazebo::common::PID *speed_pid;
gazebo::common::PID *torque_pid;
gazebo::transport::NodePtr node;
//Publishers
gazebo::transport::PublisherPtr pub_pos_target;
gazebo::transport::PublisherPtr pub_torque;
gazebo::transport::PublisherPtr pub_current;
gazebo::transport::PublisherPtr pub_posf;
gazebo::transport::PublisherPtr pub_speedf;
//boolean control
bool isPID_Pos;
bool isPID_Speed;
bool isPID_Torque;
bool isPublishing;
bool isLogging;
public:
//The DC model does not need this because it does not influence the model params
//relevant for regulation at servo level such as an encoder
ignition::math::Angle position;
//One unique target for all of Pos,Speed,Torque
//As they cannot be regulated simultaneously, switching the control set
//a new context for this target variable
double target;
double jitter;
public:
void run_step(double simtime, double batVoltage);
private:
WindowFilter speedFilter;
WindowFilter positionFilter;
PowerFilter jitterMeasure;
public:
void updatePosition(double pos);//input axis angle !must be called if pos_pid in use!
void updateSpeed(double o); //input Speed !must be called if speed_pid in use!
double getJitter(); //input Speed !must be called if speed_pid in use!
//-----------------
void SetPositionTarget(double target);
void SetSpeedTarget(double target);
void SetTorqueTarget(double target);
//-----------------
double getCurrent(); //output regulate, intermediate loop
double getTorque(); //output Result
};
class ServosController
{
public:
const int Mechanical_To_Electrical_Simulation_Factor = 1;//only makes sense when pid is active
public:
ServosController();
private:
gazebo::physics::ModelPtr model;
gazebo::common::BatteryPtr bat;
std::map<std::string,Servo*> servos;
bool isPID;
bool isDC;
bool isBLDC;
public:
std::string Name;
public:
void SetModel(gazebo::physics::ModelPtr l_model);
void SetBattery(gazebo::common::BatteryPtr v_bat);
void SetServo(const std::string &jointName, const std::string &servoName);
void SetPositionTarget(const std::string &jointName, double target);
void SetSpeedTarget(const std::string &jointName, double target);
void SetTorqueTarget(const std::string &jointName, double target);
void SetPid(const std::string &jointName);
void Set_ax12a(const std::string &jointName);
void Set_bldc_72(const std::string &jointName);
void update(double simtime = 0.0);
bool isTimeTicked(double period);
};