-
Notifications
You must be signed in to change notification settings - Fork 0
/
odom_broadcaster.cpp
258 lines (213 loc) · 6.65 KB
/
odom_broadcaster.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
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/*
odom_broadcaster.cpp
Authors: Cesar Abraham Acevedo Ruiz and Juan Angel Gonzales Aguirre
Description: This code is for computing odometry information from acelerometer information of the "acc" topic in the
linearAcceleration_and_angularVelocity.cpp node, and orientation information of the "AIkits/imu" topic in the AIkit_republisher.cpp
node. It also aplies a moving average filter to the acceleration, and a diferential band in order to determine when to integrate,
in order to reduce the risk of "drift" in operation.
*/
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>
#include <sensor_msgs/Imu.h>
#include <new>
#include <iostream>
#define NODERATE 50
#define NUM 2
//Moving average filter declaration
using namespace std;
struct movingAverage
{
private:
float aux1, aux2;
bool initializedQ = false;
public:
int numberOfSamples;
float accumulative = 0;
float * pointerToSamples;
bool initialize()
{
if(!initializedQ)
{
pointerToSamples = new (nothrow) float [numberOfSamples];
if (pointerToSamples == nullptr)
{
return false;
}
else
{
initializedQ = true;
for (float * i = &pointerToSamples[0]; i != &pointerToSamples[numberOfSamples] ; ++i)
{
*i = 0;
}
return true;
}
}
}
float mean(float actualSample)
{
//First; move the data and append the new sample to the begining of the array
accumulative = 0;
accumulative += actualSample;
for (float * i = &pointerToSamples[0]; i != &pointerToSamples[numberOfSamples] ; ++i)
{
accumulative += *i;
*i = *(i+1);
}
*(pointerToSamples + numberOfSamples-1) = actualSample;
return accumulative/numberOfSamples;
}
void printArray()
{
for (float * i = &pointerToSamples[0]; i != &pointerToSamples[numberOfSamples] ; ++i)
{
cout << *i << endl;
}
}
};
//Moving average code ends
//orientation variable
double imuOrientation[4] = {0,0,0,1};
//angular velocity variable
double w = 0;
//acceleration variables
double accx[NUM] = {};
double accy[NUM] = {};
double accxl[NUM] = {};
double accyl[NUM] = {};
//number of samples for the moving average filter
int numberOfSamplesForMean = 20;
//declaring movingAverage objects
movingAverage mean1,
mean2,
mean3,
mean4;
//OPTIONAL: This virtual low pass filter can be used instead of the moving average, if computational resources are low
void lowPassFilter(double dt,double rc)
{
double a = dt/(rc + dt);
accxl[0] = accxl[1];//a*accx[0];
accxl[1] = a*accx[1] + (1-a)*accxl[0];
accyl[0] = accyl[1];//a*accy[0];
accyl[1] = a*accy[1] + (1-a)*accyl[0];
}
//Receiving orientation data
void imuCallback(const sensorsMsgs::Imu::ConstPtr& msg)
{
imuOrientation[0] = msg->orientation.x;
imuOrientation[1] = msg->orientation.y;
imuOrientation[2] = msg->orientation.z;
imuOrientation[3] = msg->orientation.w;
}
//Receiving acceleration data
void accelerationCallback(const geometry_msgs::Vector3::ConstPtr& values)
{
geometry_msgs::Vector3 acc;
acc.x = values->x;
acc.y = values->y;
acc.z = values->z;
accx[0] = accx[1];
accy[0] = accy[1];
accx[1] = acc.x;
accy[1] = acc.y;
}
//receiving angular velocity data
void angularVelocityCallback(const geometry_msgs::Vector3::ConstPtr& values)
{
w = values->z;
}
int main(int argc, char** argv){
ros::init(argc, argv, "odometry_publisher");
ros::NodeHandle n;
ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);
ros::Subscriber acc1_sub = n.subscribe("acc",10,accelerationCallback);
ros::Subscriber ang1_sub = n.subscribe("ang",10,accelerationCallback);
ros::Subscriber imu1_sub = n.subscribe("AIkits/imu",10,imuCallback);
//initialization of variables for pose calculation
double x = 0.0;
double y = 0.0;
double th = 0.0;
double vx = 0;
double vy = 0;
double vth = 0;
//time variables for integration
ros::Time current_time, last_time;
current_time = ros::Time::now();
last_time = ros::Time::now();
mean1.numberOfSamples = numberOfSamplesForMean;
mean1.initialize();
mean2.numberOfSamples = numberOfSamplesForMean;
mean2.initialize();
mean3.numberOfSamples = numberOfSamplesForMean;
mean3.initialize();
mean4.numberOfSamples = numberOfSamplesForMean;
mean4.initialize();
ros::Rate r(NODERATE);
while(n.ok()){
ros::spinOnce(); // check for incoming messages
current_time = ros::Time::now();
//TODO: Revisar si las ruedas se están moviendo, si es asi: integrar
double dt = (current_time - last_time).toSec();
//lowPassFilter(dt,1);//filtering using low pass filter
//filtering using moving average
accxl[1] = mean1.mean(accx[1]);
accyl[1] = mean2.mean(accy[1]);
double delta_vx = 0;
double delta_vy = 0;
//determination of whether to integrate or not
if(accxl[1]<0.02 && accxl[1]>-0.02)
{
delta_vx = 0;
}
else
{
delta_vx = accxl[1]*dt;
}
if(accyl[1]<0.02 && accyl[1]>-0.02)
{
delta_vy = 0;
}
else
{
delta_vy = accyl[1]*dt;
}
vx += delta_vx;
vy += delta_vx;
//second integration
double delta_x = vx * dt;
double delta_y = vy * dt;
x += delta_x;
y += delta_y;
geometry_msgs::Quaternion odom_quat(imuOrientation[0],imuOrientation[1],imuOrientation[2],imuOrientation[3]);
//first, we'll publish the transform over tf
geometry_msgs::TransformStamped odom_trans;
odom_trans.header.stamp = current_time;
odom_trans.header.frame_id = "odom";
odom_trans.child_frame_id = "base_link";
odom_trans.transform.translation.x = x;
odom_trans.transform.translation.y = y;
odom_trans.transform.translation.z = 0.0;
odom_trans.transform.rotation = odom_quat;
//send the transform
odom_broadcaster.sendTransform(odom_trans);
//next, we'll publish the odometry message over ROS
nav_msgs::Odometry odom;
odom.header.stamp = current_time;
odom.header.frame_id = "odom";
//set the position
odom.pose.pose.position.x = x;
odom.pose.pose.position.y = y;
odom.pose.pose.position.z = 0.0;
odom.pose.pose.orientation = odom_quat;
//set the velocity
odom.child_frame_id = "base_link";
odom.twist.twist.linear.x = vx;
odom.twist.twist.linear.y = vy;
odom.twist.twist.angular.z = w;
//publish the message
odom_pub.publish(odom);
last_time = current_time;
r.sleep();
}
}