2 * Copyright Droids Corporation (2009)
3 * Olivier MATZ <zer0@droids-corp.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Revision : $Id: sensor.c,v 1.8 2009-11-08 17:24:33 zer0 Exp $
26 #include <aversive/error.h>
29 #include <scheduler.h>
35 #include <control_system_manager.h>
36 #include <trajectory_manager.h>
37 #include <vect_base.h>
40 #include <obstacle_avoidance.h>
41 #include <blocking_detection_manager.h>
42 #include <robot_system.h>
43 #include <position_manager.h>
59 int16_t (*filter)(struct adc_infos *, int16_t);
62 /* reach 90% of the value in 4 samples */
63 int16_t rii_light(struct adc_infos *adc, int16_t val)
65 adc->prev_val = val + (int32_t)adc->prev_val / 2;
66 return adc->prev_val / 2;
69 /* reach 90% of the value in 8 samples */
70 int16_t rii_medium(struct adc_infos *adc, int16_t val)
72 adc->prev_val = val + ((int32_t)adc->prev_val * 3) / 4;
73 return adc->prev_val / 4;
76 /* reach 90% of the value in 16 samples */
77 int16_t rii_strong(struct adc_infos *adc, int16_t val)
79 adc->prev_val = val + ((int32_t)adc->prev_val * 7) / 8;
80 return adc->prev_val / 8;
84 #define ADC_CONF(x) ( ADC_REF_AVCC | ADC_MODE_INT | MUX_ADC##x )
86 /* define which ADC to poll, see in sensor.h */
87 static struct adc_infos adc_infos[ADC_MAX] = {
88 [ADC_CSENSE1] = { .config = ADC_CONF(0), .filter = rii_medium },
89 [ADC_CSENSE2] = { .config = ADC_CONF(1), .filter = rii_medium },
90 [ADC_CSENSE3] = { .config = ADC_CONF(2), .filter = rii_medium },
91 [ADC_CSENSE4] = { .config = ADC_CONF(3), .filter = rii_medium },
92 [ADC_BATTERY1] = { .config = ADC_CONF(8), .filter = rii_strong },
93 [ADC_BATTERY2] = { .config = ADC_CONF(9), .filter = rii_strong },
95 /* add adc on "cap" pins if needed */
96 /* [ADC_CAP1] = { .config = ADC_CONF(10) }, */
97 /* [ADC_CAP2] = { .config = ADC_CONF(11) }, */
98 /* [ADC_CAP3] = { .config = ADC_CONF(12) }, */
99 /* [ADC_CAP4] = { .config = ADC_CONF(13) }, */
102 static void adc_event(int16_t result);
104 /* called every 10 ms, see init below */
105 static void do_adc(void *dummy)
107 /* launch first conversion */
108 adc_launch(adc_infos[0].config);
111 static void adc_event(int16_t result)
113 static uint8_t i = 0;
115 /* filter value if needed */
116 if (adc_infos[i].filter)
117 adc_infos[i].value = adc_infos[i].filter(&adc_infos[i],
120 adc_infos[i].value = result;
126 adc_launch(adc_infos[i].config);
128 #endif /* !HOST_VERSION */
130 int16_t sensor_get_adc(uint8_t i)
139 tmp = adc_infos[i].value;
145 /************ boolean sensors */
148 struct sensor_filter {
160 static struct sensor_filter sensor_filter[SENSOR_MAX] = {
161 [S_CAP1] = { 1, 0, 0, 1, 0, 0 }, /* 0 */
162 [S_CAP2] = { 1, 0, 0, 1, 0, 0 }, /* 1 */
163 [S_LFRONT] = { 1, 0, 0, 1, 0, 1 }, /* 2 */
164 [S_RFRONT] = { 1, 0, 0, 1, 0, 1 }, /* 3 */
165 [S_START_SWITCH] = { 10, 0, 3, 7, 0, 0 }, /* 4 */
166 [S_DISP_LEFT] = { 1, 0, 0, 1, 0, 1 }, /* 5 */
167 [S_RCOB_WHITE] = { 1, 0, 0, 1, 0, 0 }, /* 6 */
168 [S_LCOB_WHITE] = { 1, 0, 0, 1, 0, 0 }, /* 7 */
169 [S_RESERVED1] = { 10, 0, 3, 7, 0, 0 }, /* 8 */
170 [S_RESERVED2] = { 10, 0, 3, 7, 0, 0 }, /* 9 */
171 [S_RESERVED3] = { 1, 0, 0, 1, 0, 0 }, /* 10 */
172 [S_RESERVED4] = { 1, 0, 0, 1, 0, 0 }, /* 11 */
173 [S_RESERVED5] = { 1, 0, 0, 1, 0, 0 }, /* 12 */
174 [S_RESERVED6] = { 1, 0, 0, 1, 0, 0 }, /* 13 */
175 [S_RESERVED7] = { 1, 0, 0, 1, 0, 0 }, /* 14 */
176 [S_RESERVED8] = { 1, 0, 0, 1, 0, 0 }, /* 15 */
178 #endif /* !HOST_VERSION */
180 /* value of filtered sensors */
181 static uint16_t sensor_filtered = 0;
184 * 0-3: PORTK 2->5 (cap1 -> cap4) (adc10 -> adc13)
185 * 4-5: PORTL 0->1 (cap5 -> cap6)
186 * 6-7: PORTE 3->4 (cap7 -> cap8)
190 uint16_t sensor_get_all(void)
195 tmp = sensor_filtered;
200 uint8_t sensor_get(uint8_t i)
205 uint16_t tmp = sensor_get_all();
206 return (tmp & _BV(i));
211 /* get the physical value of pins */
212 static uint16_t sensor_read(void)
215 tmp |= (uint16_t)((PINK & (_BV(2)|_BV(3)|_BV(4)|_BV(5))) >> 2) << 0;
216 tmp |= (uint16_t)((PINL & (_BV(0)|_BV(1))) >> 0) << 4;
217 tmp |= (uint16_t)((PINE & (_BV(3)|_BV(4))) >> 3) << 6;
218 /* add reserved sensors here */
222 /* called every 10 ms, see init below */
223 static void do_boolean_sensors(void *dummy)
227 uint16_t sensor = sensor_read();
230 for (i=0; i<SENSOR_MAX; i++) {
231 if ((1 << i) & sensor) {
232 if (sensor_filter[i].cpt < sensor_filter[i].filter)
233 sensor_filter[i].cpt++;
234 if (sensor_filter[i].cpt >= sensor_filter[i].thres_on)
235 sensor_filter[i].prev = 1;
238 if (sensor_filter[i].cpt > 0)
239 sensor_filter[i].cpt--;
240 if (sensor_filter[i].cpt <= sensor_filter[i].thres_off)
241 sensor_filter[i].prev = 0;
244 if (sensor_filter[i].prev) {
249 sensor_filtered = tmp;
252 #endif /* !HOST_VERSION */
254 /* virtual obstacle */
256 #define DISABLE_CPT_MAX 200
257 static uint8_t disable = 0; /* used to disable obstacle detection
258 * during some time */
260 /* called every 10 ms */
262 sensor_obstacle_update(void)
267 DEBUG(E_USER_STRAT, "re-enable sensor");
271 void sensor_obstacle_disable(void)
273 DEBUG(E_USER_STRAT, "disable sensor");
274 disable = DISABLE_CPT_MAX;
277 void sensor_obstacle_enable(void)
282 uint8_t sensor_obstacle_is_disabled(void)
288 /************ global sensor init */
289 #define BACKGROUND_ADC 0
292 /* called every 10 ms, see init below */
293 static void do_sensors(void *dummy)
297 do_boolean_sensors(NULL);
298 sensor_obstacle_update();
302 void sensor_init(void)
309 adc_register_event(adc_event);
311 scheduler_add_periodical_event_priority(do_sensors, NULL,
312 10000L / SCHEDULER_UNIT,