Фронты по алгоритму ловятся все ,а не один ,но кроме фронта нужного я еще всегда анализирую потенциал на противоположном входе ,что бы уменьшить влияние помех .
Фронты по алгоритму ловятся все ,а не один ,но кроме фронта нужного я еще всегда анализирую потенциал на противоположном входе ,что бы уменьшить влияние помех .
электронщик до мозга костей и не только
Рад за вас и ваш алгоритм. Но в моей PRU программе используется не ваш алгоритм.
Как и обещал, проверил на случайном вращении "виртуального энкодера".
Забегая вперёд скажу, что проблем не нашлось. Т.е. программа работает верно.
Иными словами, вращение из любого состояния в любом направлении будет отрабатывать правильно.
10'000'000 импульсов эмулируются за 2-4 секунды.
Собственно, класс "эталонного энкодера". Это тот, который выдаёт эталонные A-B импульсы.
Теперь натравливаем рандомное вращение на исходную PRU программу:Код:package com.github.vlsi.pru; import static com.github.vlsi.pru.VirtualAbEncoder.EncoderState.S01; import static com.github.vlsi.pru.VirtualAbEncoder.EncoderState.S10; import static com.github.vlsi.pru.VirtualAbEncoder.EncoderState.S11; public class VirtualAbEncoder { private final static EncoderState[] ENCODER_STATES = EncoderState.values(); enum EncoderState { S00, S01, S11, S10, } private EncoderState state = EncoderState.S00; private int count; private int position; public boolean getA() { return state == S10 || state == S11; } public boolean getB() { return state == S01 || state == S11; } public void reset() { state = EncoderState.S00; count = 0; position = 0; } public void left() { step(true); } public void right() { step(false); } public void step(boolean left) { count++; int diff = left ? 1 : -1; position += diff; state = getStateByOrdinal(state.ordinal() + diff); } private EncoderState getStateByOrdinal(int i) { int length = ENCODER_STATES.length; return ENCODER_STATES[(i + length) % length]; } public int getPosition() { return position; } public int getCount() { return count; } }
Ничего особенного не происходит, всё отрабатывает верно.Код:@Test public void drunkEncoder() { PRU_ABZ_ENCODER_CodeGenerator abz = new PRU_ABZ_ENCODER_CodeGenerator(); Pru cpu = new Pru(); CodeEmitter ce = new CodeEmitter(); abz.accept(ce); cpu.setCode(ce.visitEnd()); VirtualAbEncoder encoder = new VirtualAbEncoder(); ThreadLocalRandom random = ThreadLocalRandom.current(); for(int i = 0; i < 10_000_000; i++) { encoder.step(random.nextBoolean()); abz.setA(cpu, encoder.getA() ? 1 : 0); abz.setB(cpu, encoder.getB() ? 1 : 0); executeBlock(cpu); assertEquals(abz.getCounter(cpu), encoder.getCount() & 0xffff, "counter"); assertEquals(abz.getPosition(cpu), encoder.getPosition() & 0xffff, "position"); } }
Вы попробуйте менять направление вращения случайным и независимым генератором (ГСЧ) , чтобы он попадал в разные моменты и не был синхронизован в выполнением основной программы .Кроме того ,хороший алгоритм должен исходить из того что могут быть высокочастотные помехи ,которые сравнимы по длительности с фронтами и которые сглаживать фильтром нельзя ,что бы не потерять основные импульсы с энкодера при больших скоростях .
электронщик до мозга костей и не только
В общем, если у кого-нибудь есть энкодер -- прошу протестировать программу энкодера.
Теоретически, программа должна успешно ловить импульсы вплоть до 1 мкс (~1 МГц)
Казалось бы, зачем нужна ещё одна программа обработки энкодера, если в прошивке ПЛК и так энкодер уже обрабатывается?
Отвечаю: когда PRUграммирование станет доступно для всех, то модуль энкодера уже будет в базовой поставке.
Последний раз редактировалось Владимир Ситников; 07.10.2016 в 23:22.
Попробовал "облагородить" обмен данными между PRU и основной программой -- столкнулся с тем, что мне не хватает задач.
Ещё есть кандидаты на PRU программы?
Надо кому-нибудь что-нибудь на тему "быстрого управления"?
Поясню, что мне не нравится в моём текущем подходе.
Вот фрагмент программы, которая следит за энкодером и выключает двигатель как только энкодер отсчитает нужное количество импульсов:
Снимок экрана 2016-10-08 в 22.33.42.png
Несложно заметить, что обмен данными сделан ассемблерными командами.
На КДС стороне эти данные принимаются по соответствующим адресамКод:ASM SBCO (* записываем переменную в память *) cutter.state, 3 (* тут всегда 3 *), 60 (* это адрес куда писать *) , 1 (* 1 байт *) SBCO cutter.offset, 3, 64, 4 SBCO abz.zeroDetected, 3, 68, 1 SBCO abz.position, 3, 72, 2 SBCO abz.counter, 3, 76, 2 END_ASM
Нормально?Код:VAR TMP: DWORD; END_VAR PRU_FB_GetParameter(pru_num:=0, index:=15 (* == 60/4 == cutter.state *), value:=ADR(TMP)); PRU_FB_GetParameter(pru_num:=0, index:=16 (* == 64/4 == cutter.offset *), value:=ADR(OFFSET));
Готовы так PRUграммировать?
Мне не нравится, что приходится следить за адресами и соответствием PRU кода и КДС кода.
Хочется чего-то автоматического, чтобы адреса выбирались сами собой, и чтобы КДС обёртка генерировалась одновременно с PRUграммой.
Мне-то подобная работа с памятью ещё более-менее, но, думаю, для обывателя это сложновато.
Моя проблема в том, что пары имеющихся у меня программ маловато, чтобы "обобщить опыт"
Думаю пока в таком направлении: в "основной" PRUграмме отмечаем спец флагом те блоки/переменные, которые нужно передавать между КДС и PRU.
Например, так:
Снимок экрана 2016-10-08 в 23.37.29.png
Ключевое слово @Export указывает имя ФБ на КДС стороне и перечень переменных, которые нужно передавать из/в КДС.
В примере выше, Hardella создаст не только PRUграмму, но и КДС блоки PRU_ABZ_ENC/PRU_FAST_INPUTS, входы-выходы которых будут обмениваться с PRU.
Как придумается адекватный подход, можно будет запускать PRUграммирование в массы.
Да, я жду плк110 М02, задача стоит в управлении ШД с ускорением и замедлением и обратная связь от энкодера.
Я так понимаю PRU мне как раз должна помочь в этом?
В прошлом году задача решена была на плк160 + драйвер onitex, управление по rs485 (modbus), теперь хочу исключить onitex.
На плк siemens (очень старом и очень давно) эти задачи решались 'мышкой' и работают по сей день, овен не очень хочет видимо делать просто и доступно.
А как решен вопрос с утилизацией быстрых дискретных входов в программе PRU для управления ШД, которые в самом ФБ не используются ?
Мне видится такие возможности их использования:
1) подключение двух энкодеров (фазы А, В без нулевой метки);
2) подключение одного энкодера (фазы А, В и нулевая метка) + один свободный вход для других нужд;
3) 4 быстрых входа для других нужд.
Во всех случаях надо предусмотреть фильтрацию входов.
Снимок экрана 2016-10-09 в 13.57.00.png
Снимок экрана 2016-10-09 в 13.54.36.png
Снимок экрана 2016-10-09 в 13.55.26.png
Фильтрация, это, наверное, либо параметр ФБ PRU_INPUTS, либо ещё один блок.
Последний раз редактировалось Newcomer; 09.10.2016 в 15:36.