Плавное касание концевика

Здравствуйте уважаемые форумчане.
Сразу скажу, что в программировании контроллеров я не силён, но очень хочу освоить это не лёгкое дело :slight_smile: .
Опишу задачу, которую пока не могу решить без вашего совета:

1.Вводные данные.
Есть каретка, которая перемещается на линейных направляющих при помощи ШД и швп. Присутствует 5 кнопок управления и 1 концевой выключатель. Также есть ещё 2 аварийных концевика, которые физически отключают питание от ШД, но в скетче не участвуют.
Логика работы должна быть такая:
1.1При включении системы каретка едет в направлении концевого выключателя до тех пор, пока в него не упрётся.
1.2 Срабатывание концевика определяет нулевую координату и отводит каретку от концевика до его размыкания.
1.3 С этого момента каретка ориентирована и кнопками управления её можно отправить в различные координаты либо вручную двигать вперед-назад.

Контроллер arduino UNO
Драйвер ШД - dm860h (промышленный).
Концевик нормально разомкнутый.

  1. Суть проблемы.
    Программу переписывал множество раз. Уверен, что присутствуют какие то нелепые куски от старых кодов и комментарии для удобства, которые можно исключить.
    Во время написания каждый раз проверяю скетч на эмуляторе с сайта https://wokwi.com/
    На нём всё прекрасно работает. В реале получается следующее:
    2.1 Каретка упирается в концевик и возвращается назад на 10000 шагов.
    (иногда она почему то мгновенно зависает при срабатывании концевика и залипает в таком положении, не начав возврат. На сколько я понимаю т.к. работает аппаратное прерывание - никакие кнопки не работают и снимать каретку с концевика приходится вручную отключив питание).
    2.2. Когда каретка производит возврат то происходит мгновенная пауза после размыкания концевика и ещё один возврат на 10000 шагов…
    (иногда этого не происходит при размыкании концевика. Т.е. концевик сработал - каретка вернулась на 10000 шагов разомкнув концевик и всё ОК и повторного возврата нет).
    3.3 Также есть проблема “перебегания” концевика, если каретка успевает разогнаться, находясь далеко при подачи питания. Поэтому из 2000 шагов откат назад после замыкания концевика превратился в 10тыс шагов, чтобы каретка гарантированно отъехала и разомкнула концевик. Это влияет на точность установки нуля.

  2. Вопрос

Для моих задач такого скетча в целом достаточно и точность нуля в ±3мм и не частые залипания на концевике, но хочу сделать так как я ХОЧУ, а не как получилось :frowning: .
Хотелось бы реализовать плавное касание концевика.
Т.е. включаем питание:
-каретка летит в концевик
-он срабатывает,
-каретка отъезжает обратно на определенное число шагов (чуть дальше гарантированного размыкания концевика)
-устанавливается низкая скорость вращения мотора и он опять едет к концевику но уже медленно (исключить перебег)
-концевик срабатывает
-мотор отъезжает чуть чуть дальше “размыания концевика”

  • активно управление кнопками.

Просьба бить сильно, чтобы лучше дошло =) .
Заранее спасибо.

#include <AccelStepper.h>
AccelStepper stepper(1, 13, 12); //DRIVER, step, direction
boolean initZero;

void setup(){
  Serial.begin(9600);
  initZero = true; // установили флаг
attachInterrupt(0, setZero, !LOW);      //(0 - номер прерывания (int) для UNO это D2, setZero - функция обработчик прерывания, !LOW - режим работы "прерывание будет срабатывать всякий раз, когда на выводе присутствует низкий уровень сигнала" )
pinMode(A0, INPUT_PULLUP);              //против часовой
pinMode(A1, INPUT_PULLUP);              //по часовой
pinMode(A2, INPUT_PULLUP);              //координата 1 (ПМ)
pinMode(A3, INPUT_PULLUP);              //координата 2 (ТС)
pinMode(A4, INPUT_PULLUP);              //вернуться в 0 (не налажено)
pinMode(2, INPUT_PULLUP);               //Концевик
   }
 long pastTime = 0;
 volatile uint32_t debounce;
void setZero(){         
  if (millis() - debounce >= 100 && !digitalRead(2)) { // D2 сигнал концевика
    debounce = millis();
    initZero = false;                    //Отменить возвращение домой при включении контроллера
    stepper.setAcceleration(5000);
    stepper.setCurrentPosition(0);
    stepper.moveTo(-10000);
    stepper.run();
    // ваш код по прерыванию по высокому сигналу
  }
}
void loop(){
  bool push = !digitalRead(A0);                //назначаем кнопку(по часовой) на выход A0
  bool push1 = !digitalRead(A1);               //назначаем кнопку(против часовой) на выход A1
  bool goToCoordinatePM = !digitalRead(A2);    //назначаем кнопку(ехать в ПМ) на выход A2
  bool goToCoordinateTC = !digitalRead(A3);    //назначаем кнопку(ехать в ТС) на выход A3
  bool goToZero = !digitalRead(A4);            //назначаем кнопку(найти 0) на выход A4

if (initZero == 1){                     //Возвращение домой при включении контроллера
  stepper.setMaxSpeed(3000);
  stepper.setAcceleration(400);
  stepper.setSpeed(510);
  stepper.runToNewPosition(999000);  
  stepper.run();

}
 
  for(bool x=!digitalRead(A0); x == 1; x=!digitalRead(A0)){
    for (float s=1; s > -1; s=s+0.01){
    stepper.setMaxSpeed(-7000);
    stepper.setSpeed(-1000-s);
    stepper.runSpeed();
     if (!digitalRead(A0) == 0) break;
    }
  }

    for(bool x=!digitalRead(A1); x == 1; x=!digitalRead(A1)){
     for (float v=1; v > -1; v=v+0.01){
    stepper.setMaxSpeed(7000);
    stepper.setSpeed(1000+v);
    stepper.runSpeed();
     if (!digitalRead(A1) == 0) break;
     }
  }
 if (goToCoordinatePM == 1){
    stepper.setMaxSpeed(7000);
  stepper.setAcceleration(500);
  stepper.setSpeed(510);
  stepper.runToNewPosition(-74000);            //координата для ПМ
  stepper.run();
    }
  if (goToCoordinateTC == 1){                  // 665 формат
    stepper.setMaxSpeed(7000);
  stepper.setAcceleration(500);
  stepper.setSpeed(510);
  stepper.runToNewPosition(-630000);         //координата для ТС
  stepper.run();
    }
  if (goToZero == 1){
stepper.setMaxSpeed(5000);
  stepper.setSpeed(510);
  stepper.runToNewPosition(990000);  
  stepper.run();
    } 
Serial.println("Sensors value is:  ");   
Serial.print("ПМ\t\t");
Serial.println(analogRead(A2), DEC); 
Serial.print("TC\t\t");
Serial.println(analogRead(A3)); 
Serial.print("KOHCEBUK\t\0");
Serial.println(digitalRead(2)); 
Serial.println("--------");

}

Не нашел кнопки “редактировать тему”.
Забыл сказать, что крайне не хотелось бы использовать сторонние библиотеки для этой задачи.

Имхо, перемудрено. Лучше при срабатывании концевика отъезжать малым ходом, пока не разомкнется концевик. После этого можно отодвинуться еще на какое-то количество шагов (если нужно)

1 лайк

Не стоит так уж драматизировать) Тут банальная механическая операция.
Всего два пути после касания концевика на скорости. Либо справа, либо слева коснутся на малой скорости. Причём выбор обусловлен конструктивными особенностями концевика и механикой в целом.

А откуда вдруг взялось аппаратное прерывание?
До сих пор о нем не было ни слова. Да и логика работы не предусматривает использования аппаратного прерывания.

Так и делайте.

Возможно и перемудрил…Просто на моем 3d принтере логика обнуления по концевикам именно такая. Руководствовался только этим живым примером.

Спасибо за ответ. В первой части вашего сообщения, касаемо быдлокодов из интернета и отсутствия полного понимания их логики работы, вы безусловно правы :slight_smile:

Тер.мех. изучал и физика процесса мне ясна. Возможно я не совсем корректно выразил свою мысль… Вас видимо стригеррили слова “каретка летит” и “перебегание концевика” О_0. Фактически каретка движется совсем не быстро - около 2м/мин, если навскидку. Но даже при таких скоростях вышеуказанный эффект “перебегание” присутствует.
Ехать к концевику всегда медленно для меня не вариант - слишком долго, т.к. длина шва более 3х метров. Как иначе корректно реализовать - не знаю, потому и прошу вашего совета. Если считаете, что в моем случае что либо советовать дело гиблое - ок. Вопрос ведь не горящий - буду изучать основы, если ответа на форуме не найду.

Кроме того могу добавить, что быдлокоды, как ни крути, в общем и целом помогли решить задачу дилетанту :wink: .

Ещё раз спасибо за ответ :slight_smile:

Моя вина - не описал прерывание.
Его стал использовать потому, что не смог найти какого либо альтернативного пути.

Использую библиотеку accelstepper.h
В ней у меня получилось заставить мотор перемещать каретку корректно только при использовании команды (функции):
stepper.runToNewPosition()

Не знаю как правильно это описать, но эта команда блокирует выполнение цикла, пока себя не исполнит - по аналогии с функцией delay. Пока каретка не приедет в указанную координату - никакое нажатие кнопки её не останавливает. По крайней мере у меня не получилось. Получилось сделать только с использованием attachinterrupt.
Такое ощущение, что код по прерыванию срабатывает постоянно и циклично в тот момент, пока концевик вжат. Завтра ещё раз попробую изменить режим прерывания с !LOW на RISING, чтобы срабатывало только 1 раз по изменению состояния пина, но думаю, что результата это не даст :frowning: .
Хочется понять причины проблеми 2.1 и 2.2 для начала.

В этом действии, увы, нет никакого смысла с таким качеством кода. Зачем после runToNewPosition() вызывать run() - можете объяснить?

А тут зачем постоянно устанавливать параметры аксельстеппера, пока нажата кнопка?

И тд и тп.

Концевик замыкается дребезг. Концевик размыкается - тоже дребезг.

Попробуйте уменьшить время debounce

Так же попробуйте закомментировать всё, что связано с Serial

Приятно видеть абсолютно адекватную реакцию, мое почтение.
Теоретическую механику вы изучали, но до того момента что я обозначил, вы ее игнорируете. Раз уж вы всерьез хотите сделать свою “приблуду”, я вам попробую объяснить подробнее. Это будет полезно и тем коллегам, которые используют выражение типа “простая механическая операция”.
Начнем с того, что всех вычислительных ресурсов на нашей плонете не хватит, чтобы математически корректно эмулировать растворение капли чернил в стакане воды. Это не связано с вычислительной мошностью и быстродействием компьютеров, эти ограничения ставит термодинамика, если вам интересно я расскажу подробнее но не в этом сообщении.
Далее, переходим к вашему конкретному случаю. Итогом дифференциального преобразование по Лагранжу является закон движения тела (детали) в обобщенных координатах. Проще говоря, уравнение, которое описывает, как деталь двигается относительно любой произвольно выбранной системы координат , т.е. в любой момент времени по этой формуле можно будет вычислить текущее положение любой точки детали, и ее (точки детали) ускорение. При простом прямолинейном равномерном движении это будет формула по типу S=vt=at*t, в вашем случае формула будет намного сложнее.
Без этого уравнения даже теоретически нельзя решить вашу задачу. Более того, без этого уравнения вы даже не сможете сформулировать, в чем ваша проблема. Использование вами слов “быстрее” и “медленнее” (которые являются субъективной оценкой происходящего) говорит как раз об этом, задачу нельзя формализовать => параметры нельзя измерить => задачу нельзя решить.
Поэтому, еще раз, вы уж простите, но у вас ничего не получится, ибо других способов, кроме математического, наука в настоящий момент не знает.
А вот когда у вас будет это уравнение закона движения детали, его можно будет запрограммировать. Для этого надо будет разобраться в быдлокоде из интернетов. Сейчас ваша задача находится на предыдущем этапе решения.
Спасибо, что дочитали. до конца.

как всё сложно с этим 3-D принтером, в ТПА на порядок попроще, быстро двигаемся до промежуточного концевика, далее переключаемся на движение подушки (медленное) и точно, по датчику давления (до усилия запирания обычно 100 тонн)

Придумало же человечество датчики холла вместо дребезжащих контактов. ну потавь пару таких датчиков, и гоняй свой принтер на скорости 200 км в час, до 1 датчика, а до второго 2 мм. Надеюсь ещё есть свободные пины для доп датчиков?

Я хз, что там выдумал ТС , но у меня на 3Д принтере тупо едет на максимальной скорости до концевика, а потом на самой медленной с него съезжает…

Датчики холла точно так же дребезжат как контакты.

Я хз, что там выдумал ТС , но у меня на 3Д принтере тупо едет на максимальной скорости до концевика, а потом отъезжает на пару мм и уже медленно ещё раз до концевика, потом отъезжает на 10 мм и гордо об этом сообщает. Этот алгоритм можно из прошивки вытащить.

это точно? прям все?

Все, в которых гистерезис не встроен изначально. Но это как RS триггер к кнопке прицепить. Тоже дребезга не будет на аппаратном уровне.

значит не все :slightly_smiling_face:

Вспоминаем название темы: “Плавное касание концевика”.
Чтобы коснуться концевика плавно, нужно заранее знать, что мы к нему подъезжаем, и снизить скорость.
Узнать это можно разными способами, например, при помощи ультразвукового или оптического датчика.