32
32
33
33
// Settings
34
34
#define PEDAL_INPUT_TIMEOUT 0.2
35
+ #define MAX_MS_WITHOUT_CADENCE 5000
35
36
#define MIN_MS_WITHOUT_POWER 500
36
37
#define FILTER_SAMPLES 5
37
38
#define RPM_FILTER_SAMPLES 8
@@ -42,6 +43,7 @@ static THD_WORKING_AREA(pas_thread_wa, 1024);
42
43
43
44
// Private variables
44
45
static volatile pas_config config ;
46
+ static volatile float sub_scaling = 1.0 ;
45
47
static volatile float output_current_rel = 0.0 ;
46
48
static volatile float ms_without_power = 0.0 ;
47
49
static volatile float max_pulse_period = 0.0 ;
@@ -51,7 +53,14 @@ static volatile float pedal_rpm = 0;
51
53
static volatile bool primary_output = false;
52
54
static volatile bool stop_now = true;
53
55
static volatile bool is_running = false;
56
+ static volatile float torque_ratio = 0.0 ;
54
57
58
+ /**
59
+ * Configure and initialize PAS application
60
+ *
61
+ * @param conf
62
+ * App config
63
+ */
55
64
void app_pas_configure (pas_config * conf ) {
56
65
config = * conf ;
57
66
ms_without_power = 0.0 ;
@@ -63,10 +72,7 @@ void app_pas_configure(pas_config *conf) {
63
72
// if pedal spins at x3 the end rpm, assume its beyond limits
64
73
min_pedal_period = 1.0 / ((config .pedal_rpm_end * 3.0 / 60.0 ));
65
74
66
- if (config .invert_pedal_direction == true )
67
- direction_conf = -1.0 ;
68
- else
69
- direction_conf = 1.0 ;
75
+ (config .invert_pedal_direction ) ? (direction_conf = -1.0 ) : (direction_conf = 1.0 );
70
76
}
71
77
72
78
/**
@@ -101,19 +107,24 @@ void app_pas_stop(void) {
101
107
}
102
108
}
103
109
110
+ void app_pas_set_current_sub_scaling (float current_sub_scaling ) {
111
+ sub_scaling = current_sub_scaling ;
112
+ }
113
+
104
114
float app_pas_get_current_target_rel (void ) {
105
115
return output_current_rel ;
106
116
}
107
117
108
118
void pas_event_handler (void ) {
109
119
#ifdef HW_PAS1_PORT
110
120
const int8_t QEM [] = {0 ,-1 ,1 ,2 ,1 ,0 ,2 ,-1 ,-1 ,2 ,0 ,1 ,2 ,1 ,-1 ,0 }; // Quadrature Encoder Matrix
111
- float direction_qem ;
121
+ int8_t direction_qem ;
112
122
uint8_t new_state ;
113
123
static uint8_t old_state = 0 ;
114
124
static float old_timestamp = 0 ;
115
125
static float inactivity_time = 0 ;
116
126
static float period_filtered = 0 ;
127
+ static int32_t correct_direction_counter = 0 ;
117
128
118
129
uint8_t PAS1_level = palReadPad (HW_PAS1_PORT , HW_PAS1_PIN );
119
130
uint8_t PAS2_level = palReadPad (HW_PAS2_PORT , HW_PAS2_PIN );
@@ -122,10 +133,19 @@ void pas_event_handler(void) {
122
133
direction_qem = (float ) QEM [old_state * 4 + new_state ];
123
134
old_state = new_state ;
124
135
136
+ // Require several quadrature events in the right direction to prevent vibrations from
137
+ // engging PAS
138
+ int8_t direction = (direction_conf * direction_qem );
139
+
140
+ switch (direction ) {
141
+ case 1 : correct_direction_counter ++ ; break ;
142
+ case -1 :correct_direction_counter = 0 ; break ;
143
+ }
144
+
125
145
const float timestamp = (float )chVTGetSystemTimeX () / (float )CH_CFG_ST_FREQUENCY ;
126
146
127
147
// sensors are poorly placed, so use only one rising edge as reference
128
- if (new_state == 3 ) {
148
+ if ( ( new_state == 3 ) && ( correct_direction_counter >= 4 ) ) {
129
149
float period = (timestamp - old_timestamp ) * (float )config .magnets ;
130
150
old_timestamp = timestamp ;
131
151
@@ -135,7 +155,7 @@ void pas_event_handler(void) {
135
155
return ;
136
156
}
137
157
pedal_rpm = 60.0 / period_filtered ;
138
- pedal_rpm *= (direction_conf * direction_qem );
158
+ pedal_rpm *= (direction_conf * ( float ) direction_qem );
139
159
inactivity_time = 0.0 ;
140
160
}
141
161
else {
@@ -177,7 +197,7 @@ static THD_FUNCTION(pas_thread, arg) {
177
197
return ;
178
198
}
179
199
180
- pas_event_handler (); // this should happen inside an ISR instead of being polled
200
+ pas_event_handler (); // this could happen inside an ISR instead of being polled
181
201
182
202
// For safe start when fault codes occur
183
203
if (mc_interface_get_fault () != FAULT_CODE_NONE ) {
@@ -188,28 +208,50 @@ static THD_FUNCTION(pas_thread, arg) {
188
208
continue ;
189
209
}
190
210
191
- // Map the rpm to assist level
192
211
switch (config .ctrl_type ) {
193
212
case PAS_CTRL_TYPE_NONE :
194
213
output = 0.0 ;
195
214
break ;
196
215
case PAS_CTRL_TYPE_CADENCE :
216
+ // Map pedal rpm to assist level
217
+
197
218
// NOTE: If the limits are the same a numerical instability is approached, so in that case
198
219
// just use on/off control (which is what setting the limits to the same value essentially means).
199
220
if (config .pedal_rpm_end > (config .pedal_rpm_start + 1.0 )) {
200
- output = utils_map (pedal_rpm , config .pedal_rpm_start , config .pedal_rpm_end , 0.0 , config .current_scaling );
201
- utils_truncate_number (& output , 0.0 , config .current_scaling );
221
+ output = utils_map (pedal_rpm , config .pedal_rpm_start , config .pedal_rpm_end , 0.0 , config .current_scaling * sub_scaling );
222
+ utils_truncate_number (& output , 0.0 , config .current_scaling * sub_scaling );
202
223
} else {
203
224
if (pedal_rpm > config .pedal_rpm_end ) {
204
- output = config .current_scaling ;
225
+ output = config .current_scaling * sub_scaling ;
205
226
} else {
206
227
output = 0.0 ;
207
228
}
208
229
}
209
230
break ;
210
- case PAS_CTRL_TYPE_CONSTANT_TORQUE :
211
- output = pedal_rpm > config .pedal_rpm_start ? config .current_scaling : 0 ;
212
- break ;
231
+
232
+ #ifdef HW_HAS_PAS_TORQUE_SENSOR
233
+ case PAS_CTRL_TYPE_TORQUE :
234
+ {
235
+ torque_ratio = hw_get_PAS_torque ();
236
+ output = torque_ratio * config .current_scaling * sub_scaling ;
237
+ utils_truncate_number (& output , 0.0 , config .current_scaling * sub_scaling );
238
+ }
239
+ /* fall through */
240
+ case PAS_CTRL_TYPE_TORQUE_WITH_CADENCE_TIMEOUT :
241
+ {
242
+ // disable assistance if torque has been sensed for >5sec without any pedal movement. Prevents
243
+ // motor overtemps when the rider is just resting on the pedals
244
+ static float ms_without_cadence_or_torque = 0.0 ;
245
+ if (output == 0.0 || pedal_rpm > 0 ) {
246
+ ms_without_cadence_or_torque = 0.0 ;
247
+ } else {
248
+ ms_without_cadence_or_torque += (1000.0 * (float )sleep_time ) / (float )CH_CFG_ST_FREQUENCY ;
249
+ if (ms_without_cadence_or_torque > MAX_MS_WITHOUT_CADENCE ) {
250
+ output = 0.0 ;
251
+ }
252
+ }
253
+ }
254
+ #endif
213
255
default :
214
256
break ;
215
257
}
@@ -222,7 +264,7 @@ static THD_FUNCTION(pas_thread, arg) {
222
264
if (ramp_time > 0.01 ) {
223
265
const float ramp_step = (float )ST2MS (chVTTimeElapsedSinceX (last_time )) / (ramp_time * 1000.0 );
224
266
utils_step_towards (& output_ramp , output , ramp_step );
225
- utils_truncate_number (& output_ramp , 0.0 , config .current_scaling );
267
+ utils_truncate_number (& output_ramp , 0.0 , config .current_scaling * sub_scaling );
226
268
227
269
last_time = chVTGetSystemTimeX ();
228
270
output = output_ramp ;
0 commit comments