-
Notifications
You must be signed in to change notification settings - Fork 0
/
servo_dec.c
201 lines (174 loc) · 4.61 KB
/
servo_dec.c
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
/*
Copyright 2016 - 2019 Benjamin Vedder [email protected]
This file is part of the VESC firmware.
The VESC firmware is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The VESC firmware is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "servo_dec.h"
#include "stm32f4xx_conf.h"
#include "ch.h"
#include "hal.h"
#include "hw.h"
#include "utils.h"
/*
* Settings
*/
#define SERVO_NUM 1
#define TIMER_FREQ 1000000
// Private variables
static volatile systime_t last_update_time;
static volatile float servo_pos[SERVO_NUM];
static volatile float pulse_start = 1.0;
static volatile float pulse_end = 2.0;
static volatile float last_len_received[SERVO_NUM];
static volatile bool use_median_filter = false;
static volatile bool is_running = false;
// Function pointers
static void(*done_func)(void) = 0;
static void icuwidthcb(ICUDriver *icup) {
last_len_received[0] = ((float)icuGetWidthX(icup) / ((float)TIMER_FREQ / 1000.0));
float len = last_len_received[0] - pulse_start;
const float len_set = (pulse_end - pulse_start);
if (len > len_set) {
if (len < (len_set * 1.5)) {
len = len_set;
} else {
// Too long pulse. Most likely something is wrong.
len = -1.0;
}
} else if (len < 0.0) {
if ((len + pulse_start) > (pulse_start * 0.8)) {
len = 0.0;
} else {
// Too short pulse. Most likely something is wrong.
len = -1.0;
}
}
if (len >= 0.0) {
if (use_median_filter) {
float c = (len * 2.0 - len_set) / len_set;
static float c1 = 0.5;
static float c2 = 0.5;
float med = utils_middle_of_3(c, c1, c2);
c2 = c1;
c1 = c;
servo_pos[0] = med;
} else {
servo_pos[0] = (len * 2.0 - len_set) / len_set;
}
last_update_time = chVTGetSystemTime();
if (done_func) {
done_func();
}
}
}
static void icuperiodcb(ICUDriver *icup) {
(void)icup;
}
static ICUConfig icucfg = {
ICU_INPUT_ACTIVE_HIGH,
TIMER_FREQ,
icuwidthcb,
icuperiodcb,
NULL,
HW_ICU_CHANNEL,
0
};
/**
* Initialize the serve decoding driver.
*
* @param d_func
* A function that should be called every time the servo signals have been
* decoded. Can be NULL.
*/
void servodec_init(void (*d_func)(void)) {
icuStart(&HW_ICU_DEV, &icucfg);
palSetPadMode(HW_ICU_GPIO, HW_ICU_PIN, PAL_MODE_ALTERNATE(HW_ICU_GPIO_AF));
icuStartCapture(&HW_ICU_DEV);
icuEnableNotifications(&HW_ICU_DEV);
for (int i = 0;i < SERVO_NUM;i++) {
servo_pos[i] = 0.0;
last_len_received[i] = 0.0;
}
// Set our function pointer
done_func = d_func;
is_running = true;
}
/**
* Stop the servo decoding driver
*/
void servodec_stop(void) {
if (is_running) {
icuStop(&HW_ICU_DEV);
palSetPadMode(HW_ICU_GPIO, HW_ICU_PIN, PAL_MODE_INPUT);
pulse_start = 1.0;
pulse_end = 2.0;
use_median_filter = false;
done_func = 0;
}
is_running = false;
}
/**
* Change the limits of how the servo pulses should be decoded.
*
* @param start
* The amount of milliseconds the pulse starts at (default is 1.0)
*
* @param end
* he amount of milliseconds the pulse ends at (default is 2.0)
*/
void servodec_set_pulse_options(float start, float end, bool median_filter) {
pulse_start = start;
pulse_end = end;
use_median_filter = median_filter;
}
/**
* Get a decoded servo value.
*
* @param servo_num
* The servo index. If it is out of range, 0.0 will be returned.
*
* @return
* The servo value in the range [-1.0 1.0].
*/
float servodec_get_servo(int servo_num) {
if (servo_num < SERVO_NUM) {
return servo_pos[servo_num];
} else {
return 0.0;
}
}
/**
* Get the amount of milliseconds that has passed since
* the last time servo positions were received.
*
* @return
* The amount of milliseconds that have passed since an update.
*/
uint32_t servodec_get_time_since_update(void) {
return chVTTimeElapsedSinceX(last_update_time) / (CH_CFG_ST_FREQUENCY / 1000);
}
/**
* Get the length of the last received pulse.
*
* @param servo_num
* The servo index. If it is out of range, 0.0 will be returned.
*
* @return
* The length of the last received pulse.
*/
float servodec_get_last_pulse_len(int servo_num) {
if (servo_num < SERVO_NUM) {
return last_len_received[servo_num];
} else {
return 0.0;
}
}