2 * This file is part of MCL library.
4 * MCL library is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation, either version 3 of the License,
7 * or (at your option) any later version.
9 * MCL library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with MCL library. If not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) 2007 - 2009 Czech Technical University in Prague
19 * Authors: Michal Sojka <sojkam1@fel.cvut.cz>
24 #include "mcl_laser.h"
29 #ifdef MATLAB_MEX_FILE
30 #define S_FUNCTION_LEVEL 2
31 #define S_FUNCTION_NAME sf_mcl
36 static void mcl_laser_reset(struct mcl_model *mcl)
38 struct mcl_laser *l = mcl_to_laser(mcl);
39 struct mcl_laser_state *parts = l->parts;
42 /* particles initialization */
43 for (i=0; i<mcl->count; i++) {
44 /* generate particles with noises. They have the same
45 * starting weight, as we consider that any of the
46 * particles could be the right one.
48 parts[i].x = (rand()&0xffff)/65535.0*l->width;
49 parts[i].y = (rand()&0xffff)/65535.0*l->height;
50 parts[i].angle = (rand() % 360)/360.0*(2.0*M_PI);
51 parts[i].beacon = 0 /* rand() % BEACON_CNT */;
56 static void mcl_laser_set_estimated(struct mcl_model *mcl, void *new_estimated)
58 struct mcl_laser *l = mcl_to_laser(mcl);
59 struct mcl_laser_state *parts = l->parts;
60 /* struct mcl_robot_pos *estimated = mcl->estimated; */
61 struct mcl_robot_pos *new_est = new_estimated;
63 struct mcl_laser_state p;
66 p.angle = new_est->angle;
69 l->estimated = *new_est;
70 for (i=0; i<BEACON_CNT; i++) {
75 for (i=0; i<mcl->count; i++) {
76 parts[i] = p; /* TODO: Add some noise here */
81 static void mcl_laser_predict(struct mcl_model *mcl, void *delta)
83 struct mcl_laser *l = mcl_to_laser(mcl);
84 struct mcl_laser_state *parts = l->parts;
85 struct mcl_robot_odo *d = delta;
86 struct mcl_robot_pos *estimated = mcl->estimated;
89 double xdiff, ydiff, a;
91 /* move the particles with noises */
92 for (i=0; i<mcl->count; i++) {
93 double a = parts[i].angle;
94 xdiff = d->dx*cos(a) - d->dy*sin(a);
95 ydiff = d->dy*cos(a) + d->dx*sin(a);
97 parts[i].x += xdiff + l->pred_dnoise*gaussian_random();
98 parts[i].y += ydiff + l->pred_dnoise*gaussian_random();
99 parts[i].angle += d->dangle + l->pred_anoise*gaussian_random();
100 /* if (drand48() < l->beacon_miss) parts[i].beacon++; */
101 /* if (drand48() < l->false_beacon) parts[i].beacon--; */
102 /* if (parts[i].beacon >= BEACON_CNT) */
103 /* parts[i].beacon = 0; */
104 /* if (parts[i].beacon < 0) */
105 /* parts[i].beacon = BEACON_CNT-1; */
107 /* printf("%3d: x=%g y=%g a=%g b=%d\n", */
108 /* i, parts[i].x, parts[i].y, parts[i].angle, parts[i].beacon); */
111 /* Update the last estimated position without noise */
112 a = estimated->angle;
113 estimated->x += d->dx*cos(a) - d->dy*sin(a);
114 estimated->y += d->dx*sin(a) + d->dy*cos(a);
115 estimated->angle += d->dangle;
118 static inline double gaussian(double val, double sigma)
120 return exp(-0.5 * (val*val / (sigma*sigma)));
124 static void mcl_laser_update(struct mcl_model *mcl, void *measurement)
126 struct mcl_laser *l = mcl_to_laser(mcl);
127 struct mcl_laser_state * __restrict parts = l->parts;
128 const struct mcl_laser_state * __restrict best = &parts[0];
129 const struct mcl_laser_measurement *angles = measurement;
135 mcl_weight_t wmax = 0;
136 /* evaluate the weights of each particle */
137 for (i=0; i<mcl->count; i++) {
138 struct mcl_laser_state *part = &parts[i];
139 if (part->x < 0 || part->x > l->width ||
140 part->y < 0 || part->y > l->height) {
141 /* We cannot be out of the playground */
146 mcl_pos2ang(part, theta, BEACON_CNT, l->beacon_color);
147 for (im=0; im<angles->count; im++) {
149 for (it=0; it < BEACON_CNT; it++) {
150 diff = fabs(theta[it] - angles->val[im]);
151 if (diff > M_PI) diff = 2*M_PI-diff;
152 p += gaussian(diff, l->aeval_sigma);
154 part->w[part->beacon] = p;
157 part->beacon %= BEACON_CNT;
160 for (it=0; it < BEACON_CNT; it++) {
161 mcl->weight[i] *= part->w[it];
164 if (mcl->weight[i] > wmax) {
165 wmax = mcl->weight[i];
170 l->estimated.x = best->x;
171 l->estimated.y = best->y;
172 l->estimated.angle = best->angle;
177 static inline double rnd()
179 return 1 - drand48(); /* exclude zero */
183 * Resample the particles. Mystic alg. 1 from "Improved particle
184 * filter for nonlinear problems".
186 * @note It already contains normalization so it is not neccessary to
187 * call mcl_normalize().
189 * @param mcl the MCL model
191 static void mcl_laser_resample(struct mcl_model *mcl)
193 struct mcl_laser *l = mcl_to_laser(mcl);
194 struct mcl_laser_state *parts = l->parts;
195 struct mcl_laser_state *resampled = l->resampled;
196 mcl_weight_t *Q = l->Q, *T=l->T, *weight = mcl->weight;
201 /* Q is shifted one element to the left sice the initial zero
202 * is never accessed. */
204 for (i = 1; i < mcl->count; i++)
205 Q[i] = Q[i-1] + weight[i];
207 /* We normalize here since Q should be in cache now and we
208 * also save one pass as compared to standalone
209 * mcl_normalize(). */
210 sum = Q[mcl->count-1];
213 for (i = 0; i < mcl->count; i++)
216 /* We do not store the last element of T since it is always
217 * one and during resample loop this element is never
220 for (i = 1; i < mcl->count; i++)
221 T[i] = T[i-1] - log(rnd());
222 sum = T[mcl->count-1] - log(rnd());
223 for (i = 0; i < mcl->count; i++)
226 for (i = 0, j = 0; i < mcl->count; ) {
228 resampled[i] = parts[j];
235 /* Swap resampled and non-resampled particles */
236 l->parts = resampled;
237 l->resampled = parts;
240 void mcl_laser_done(struct mcl_model *mcl)
242 struct mcl_laser *l = mcl_to_laser(mcl);
252 struct mcl_model *mcl_laser_init(struct mcl_laser *l, unsigned count)
254 struct mcl_model *mcl = &l->mcl;
256 mcl_init(mcl, count, &l->estimated);
259 l->parts = malloc(count*sizeof(struct mcl_laser_state));
260 l->resampled = malloc(count*sizeof(struct mcl_laser_state));
261 l->Q = malloc(count*sizeof(*l->Q));
262 l->T = malloc(count*sizeof(*l->T));
265 /* Initialize method pointers */
266 mcl->reset = mcl_laser_reset;
267 mcl->set_estimated = mcl_laser_set_estimated;
268 mcl->predict = mcl_laser_predict;
269 mcl->update = mcl_laser_update;
270 mcl->resample = mcl_laser_resample;
271 mcl->done = mcl_laser_done;
273 mcl_laser_reset(mcl);
277 double mcl_beacon_angle(const struct mcl_laser_state *part,
282 const struct beacon_pos *beacon;
284 if (color == BEACON_RED) {
285 head = part->angle + M_PI;
289 beacon = beacon_green;
292 head = (head < 0) ? 2*M_PI + head : head;
296 theta = atan2(beacon[i].y-part->y, beacon[i].x-part->x);
297 /* normalize angles */
298 if (theta < 0) theta = 2*M_PI + theta;
299 theta = (theta-head < 0) ?
300 2*M_PI+theta-head : theta-head;
305 * Convert the position to angles between robot's head and reflectors
306 * (angles sense is counter-clockwise)
308 * @param part MCL particle
309 * @param theta Returned angles to reflectors
310 * @param color beacon color
311 * @param cnt beacon count
313 void mcl_pos2ang(const struct mcl_laser_state *part,
315 unsigned char cnt, unsigned char color)
318 struct mcl_laser_state p = *part;
319 for (i=0; i<BEACON_CNT; i++) {
321 theta[i] = mcl_beacon_angle(&p, color);