Я хочу обнаружить удар мяча о ракетку для настольного тенниса.
В настоящее время я использую пьезо-диски, плотно закрепленные в деревянном корпусе ракетки.
Однако помимо правильного определения удара датчик также обнаруживает внезапные ускорения ракетки. Например, очень часто делают быстрое движение назад непосредственно перед ударом по мячу.
Мой подход очень наивен: я считываю АЦП как можно быстрее, и если среднее значение последних 10 измерений достигает порогового значения, я считаю влияние обнаруженным. (Я пробовал другие числа, кроме 10.)
Вопросы:
Я думаю, вам нужно подключить датчик к осциллографу и сравнить сигнал напряжения во время движений руки и во время удара мяча или сбросить данные АЦП и построить их (как упоминал @Harry Svensson). Если у вас нет хороших данных, то вы просто угадываете правильный алгоритм.
Я думаю, что удар по мячу будет иметь очень быстрое время нарастания напряжения, тогда как движения рук будут медленными. Если данные подтверждают это, вы можете поставить операционный усилитель, сконфигурированный как дифференциатор, перед АЦП. Его выход будет зависеть от скорости изменения пьезосигнала, а не от фактического уровня.
Диаграмма выше взята из хорошего учебника по схеме дифференциатора на http://www.electronics-tutorials.ws/opamp/opamp_7.html .
По сути, чем быстрее нарастает (или падает) сигнал пьезоэлектрического напряжения, тем больше будет отклонение Vout. Затем ваш код просто ищет превышение порога, такого как ваш нынешний алгоритм.
Имейте в виду, что максимальное отклонение напряжения может быть положительным или отрицательным во время удара мяча в зависимости от того, как вы сориентировали свой пьезоэлемент. Ваш анализ необработанных данных датчика покажет это.
Если ваш MCU достаточно быстр, вы можете делать это даже в цифровом виде в режиме реального времени. По сути, вам просто нужно посмотреть разницу между сэмплами и триггером, когда вы увидите большую разницу.
Такого рода вещи могут быть сделаны с дискриминацией событий .
Дискриминатор событий принимает сигналы с надлежащей амплитудой и частотным составом.
Чтобы выполнить это в простом микроконтроллере со средними возможностями (скажем, 16 МГц или лучше):
Забудьте об A2D и подайте свой пьезосигнал на аналоговый компаратор. Затем выход компаратора подключается к входному контакту, сконфигурированному как прерывание.
После поступления 1-го импульса запустите таймер и продолжайте считать входные импульсы. Как только будет обнаружено желаемое количество импульсов или истечет время таймера, выйдите из цикла.
Если вы получаете желаемое количество отсчетов, а таймер находится ниже некоторого отсчета, то сигнал имеет слишком высокую частоту и может быть отброшен.
Если время таймера истекло, а счетчик все еще слишком мал, значит, сигнал имеет слишком низкую частоту и может быть отброшен.
В противном случае сигнал можно считать событием .
Конечно, вы можете сделать все это с вашими данными A2d, просто потребуется процессор с большей мощностью.
« Каковы правильные настройки? » Посмотрите на отскок мяча с помощью прицела, подключенного к выходу компаратора. Определите количество импульсов, наиболее характерных для одного отскока мячика для пинг-понга, а также минимальное и максимальное время, соответствующее частоте.
Удачи!
Псевдокод:
//******************************************************************************
//
// INTERRUPT HANDLERS
//
//******************************************************************************
// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt
void Port_1(void) {
//Only defined interrupt should be (P1.0). Yes, slimy cheating here to keep things fast.
//Bit1.0 - Initial Pulse detected. Start Discrimination.
//Start Window timing, TA1R should already be set to 0 somewhere else.
TA1CTL |= TIMER_A_CONTINUOUS_MODE;
//Start Pulse counting, TA2R should already be set to 0 somewhere else.
TA2CTL |= TIMER_A_CONTINUOUS_MODE;
//Disable this pin input interrupt
P1IE = 0x0; //Hard-coded and blunt-force trauma for speed.
State = Active;
}
//Handle interrupts from Timer A1 ('Timer1_A'), section 0 ('0') which connects to CCR0
//This is the Frequency Window timer.
#pragma vector=TIMER1_A0_VECTOR
__interrupt
void TIMER1_A0_ISR(void){
//if we've made it here, then we've run out of time. Abort. Low Frequency.
//Turn off/reset Pulse counter
Timer_A_stop(TIMER_A2_BASE);
Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);
//Turn off/reset this (Window) counter
Timer_A_stop(TIMER_A1_BASE);
State = LowF;
}
//Handle interrupts from Timer A2 ('Timer2_A'), section 0 ('0') which connects to CCR0
//This is the pulse counter.
#pragma vector=TIMER2_A0_VECTOR
__interrupt
void TIMER2_A0_ISR(void){
//if we've made it here, then we have enough pulses. Check for event...
//Turn off/reset the window counter
Timer_A_stop(TIMER_A1_BASE);
Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);
//Turn off/reset this (Pulse) counter
Timer_A_stop(TIMER_A2_BASE);
//Verifiy timer results outside the ISR, and determine is this is really a good event
State = Verify;
}
Даниэль
Тревор_G
Гарри Свенссон
Энди ака
Творог
чупакабры