Тут в видео напечатол но что то с катриджем разберусь
Вверху отпечатка посмотрите все четка,
Получается, пиши что хочешь, никто тебя не проверит!))
Ошибка-то набежала в 1 шаг.
Терпимо, НО
В случае моего кода, увы, это не так.
Ошибка накапливается.
Спойлер
Ошибка 2шага - 3.368 *2000 = 6736
Ошибка 3шага - 3.368 * 3000 = 10104
И дальше растёт соответственно
Думал, что это косяк моей интерпретации кода @Arduman ,
запустил, вообще не понятно. Просто идёт шаг в шаг с энкодером. Где я протупил?
Спойлер
//Энкодер на пинах 2, 3. Используется внутренняя подтяжка.
// volatile int enc, motor_position;
volatile int32_t enc, motorPos;
float Kmotor = 0.567; //ПОДБИРАЕМ СООТНОШЕНИЕ МОТОР/ЭНКОДЕР
void setup(){
Serial.begin(115200);
}
void Step(bool Dir) //шаг в + или -
{
if(Dir) {motorPos++; } else { motorPos--; } //направление шага
}
void loop() {
static int32_t motorPosPrev = 0;
// Мотор следит за энкодером:
int16_t deltaPos = ++enc-((int16_t) motorPos * Kmotor);
if(deltaPos>= 1) Step(1); // надо делать шаг +
if(deltaPos<= -1) Step(0); // надо делать шаг -
Serial.print("enc = ");
Serial.print(enc);
Serial.print(" motorPos = ");
Serial.print(motorPos);
Serial.print(" execute step ");
Serial.println(motorPos - motorPosPrev);
motorPosPrev = motorPos;
}
И зачем я снова зашёл сюда? Ведь всё же было уже ясно и понятно)))
у вас здесь ошибка накапливается, тк прибавляется флоат.
А у меня ВСЕГДА идет сравнение ЦЕЛЫХ enc и motorPos, в которых ошибка накопиться не может. (даже если накопится то на следующем шаге скомпенсировалось бы).
Вот здесь мы берем общее кол-во имп и шагов:
int16_t deltaPos = enc-((int16_t) motorPos * Kmotor);
накопленных к этому моменту, причем в целых числах. Накопления по шагам быть тут не может. Можем даже пропустить несколько шагов - догоним, чтобы было ровно позже.
А ++ откуда тут взялся:
int16_t deltaPos = ++enc-((int16_t) motorPos * Kmotor);
тогда получается всего ОДИН вызов этого рассчета, тогда как у меня в ЛУУП они идут непрерывно, пока соотношение не будет достигнуто, то есть 3 или 4 раза сработает Step();
от блин.
//как я и говорю: причину ошибок искать сложнее, чем сделать правильно ахаха
мне тоже делать нехер ахаха
Спасибо за разъяснения!
Как раз свободного времени не очень много, но не люблю, когда не понимаю то что делаю.
Да! Протупил здесь.
Ваш код надо было так проверять
Спойлер
//Энкодер на пинах 2, 3. Используется внутренняя подтяжка.
// volatile int enc, motor_position;
volatile int32_t enc, motorPos;
float Kmotor = 0.567; //ПОДБИРАЕМ СООТНОШЕНИЕ МОТОР/ЭНКОДЕР
void setup(){
Serial.begin(115200);
}
void Step(bool Dir) //шаг в + или -
{
if(Dir) {motorPos++; } else { motorPos--; } //направление шага
}
void loop() {
static int32_t motorPosPrev = 0;
static uint32_t last_millis = 0;
// Мотор следит за энкодером:
if(millis() - last_millis > 20 )
{
last_millis = millis();
++enc;
}
int16_t deltaPos = enc-((int16_t) motorPos * Kmotor);
if(deltaPos>= 1) Step(1); // надо делать шаг +
if(deltaPos<= -1) Step(0); // надо делать шаг -
Serial.print("enc = ");
Serial.print(enc);
Serial.print(" motorPos = ");
Serial.print(motorPos);
Serial.print(" execute step ");
Serial.println(motorPos - motorPosPrev);
motorPosPrev = motorPos;
}
Да, можно и так.
мне немного жаль, что я не могу лично проверить реальную работу. Так-то задача любопытная. Однако понять остальную эл. автоматику выше моих сил, там натуральная клоунада, я такого не выдержу.
занимаюсь глобальной доделкой .
пару дней перепечатал то что до этого было , еще дня три печвтать ось Z
избавляюсь от корпуса принтерв и установлю ось z пока без привода
,
так как еще не знаю до конца где будет она стоять
.
верхнюю часть тоже не могу пока доделать пока все на своих местах будет
потроха ринтера , энкодер , плата все будет внутри рядом с ардуиной .
Не читал еще коментарии, просмотрю все
Я как соберу кое что проверю, я тут в ютубе просмотрел видео на низкой скорости, там плохо видно но все же, когда принтер начинал печатать.
- Стол едет вперет 10см
2…Стол Отезжает назад 20см
В это вреия головка подезжает к правой стороне готовясь к печати.
- Стол подезжает к месту печати
Начинается печать.
Я. У жены, возьму телефон сниму все в замедленной сьемки и расчерчу по милиметрам
как соберу все могу трансляцию сделатьть что бы сами со своего стола запускали все и видели как работает .
И всё же, решил разобраться, почему накапливается ошибка.
(#557, #568)
Довольно долго провозился, и, казалось уже, она берётся ниоткуда))
Дело оказалось не в прибавлении флоат,(он как раз то округляется до целых, что тоже потери) а в самой операции деления . Стоило заменить умножением,( плюс сохранение остатка флоат), мои мучения закончились. ))
Ошибка менее 1 шага.
Спойлер
float K = 3.368;//каждые 0.297 шагов enc 1 шаг ШД
//Или на 1 шаг enc 3.368 шагов ШД
// Или 3-4 шага)))
void setup() {
Serial.begin(9600);
}
void loop() {
static int32_t enc = 0;
static int32_t motoPos = 0;
static int32_t motoPosPrev = 0;
float temp = 0.0;
float rem = 0.0;
temp = ++enc * K;//
motoPos = temp;
rem += temp - motoPos;
if(rem >= 1.0)
{
motoPos++;
rem -= 1.0;
}
Serial.print("enc ");
Serial.print(enc);
Serial.print(" motoPos ");
Serial.print(motoPos);
Serial.print(" rem ");
Serial.print(rem);
Serial.print(" err ");
Serial.print((int32_t)(enc * 3.368) - motoPos);
Serial.print(" step");
Serial.print(" execute ");
Serial.print(motoPos - motoPosPrev);
Serial.println(" step ");
motoPosPrev = motoPos;
}
Это вариант, когда расчёт идёт один раз на один шаг энкодера, и, его можно делать в прерывании, независимо от loop()
P.S. Выше вариант кода теоретический, расчётный.
А это то же самое, но в практическом применении
Спойлер
//Энкодер на пинах 2, 3. Используется внутренняя подтяжка.
// volatile int enc, motor_position;
float K = 3.368; //ПОДБИРАЕМ СООТНОШЕНИЕ МОТОР/ЭНКОДЕР
volatile int32_t enc = 0;
volatile int32_t motoPos = 0;
volatile int32_t motoPosPrev = 0;
volatile float temp = 0.0;
volatile float rem = 0.0;
const int STEP_PIN = 4;
const int DIR_PIN = 7;
const int ENABLE_PIN = 8;
void setup(){
Serial.begin(115200);
pinMode(2,INPUT_PULLUP);
pinMode(3,INPUT_PULLUP);
pinMode(ENABLE_PIN , OUTPUT);
digitalWrite(ENABLE_PIN, 0); //пока включим драйвер на постоянку, чтобы не было пропусков
PCIFR=PCIF2; PCICR=1<<PCIE2; //разрешить прерывание
PCMSK2=1<<PCINT18 | 1<<PCINT19; //выбрать вход на котором сработает прерывание
}
ISR(PCINT2_vect){
static char EncPrev=0; //предыдущее состояние энкодера
static char EncPrevPrev=0; //пред-предыдущее состояние энкодера
char EncCur = 0;
if(!(PIND & (1 << PD2))){EncCur = 1;} //опрос фазы 1 энкодера
if(!(PIND & (1 << PD3))){ EncCur |= 2;} //опрос фазы 2 энкодера
if(EncCur != EncPrev) //если состояние изменилось,
{ if(EncPrev == 3 && //если предыдущее состояние 3
EncCur != EncPrevPrev ) //и текущее и пред-предыдущее не равны,
{
if(EncCur == 2)
enc++;
else
enc--;
//======================================
temp = enc * K;//
motoPos = temp;
rem += temp - motoPos;
if(rem >= 1.0)
{
motoPos++;
rem -= 1.0;
}
if(motoPos > motoPosPrev)Step(true,(uint8_t)(motoPos - motoPosPrev));
if(motoPos < motoPosPrev)Step(false,(uint8_t)(motoPosPrev - motoPos));
motoPosPrev = motoPos;
//======================================
}
EncPrevPrev = EncPrev; //сохранение пред-предыдущего состояния
EncPrev = EncCur; //сохранение предыдущего состояния
}
}
void Step(bool dir, uint8_t steps) //шаг в + или -, кол-во шагов
{
digitalWrite(DIR_PIN,dir);
while(steps--)
{
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(2);
digitalWrite(STEP_PIN, LOW);
}
}
void loop() {
}
Продолжаю печатать.
Сейчас будет печататься 2 ванночки по бокам для парковки и для чистки.
Печататься будет 10 часов.
Еще держатели axis Z 4шт., сяду спроектирую и завтро поставлю на печать.
Ось Z незнал какую высоту взять, взял наугат, ход 180 мм получился.

Дело оказалось не в прибавлении флоат,(он как раз то округляется до целых, что тоже потери) а в самой операции деления
я там похоже ошибся насчет накопления ошибки, у вас там накопления нет. (накопление ошибки может быть если мы что-то прибавляем на каждый мелкий шаг в флоате или типа того).
Деление самая неудобная операция, её всегда следует избегать в наших игрушках. Она длинная (и не точная?) , в 90% случаев ее можно заменить умножением.
Короче ну его в ж. надоело мусолить, кому надо пусть юзает и проверяет.

Деление самая неудобная операция, её всегда следует избегать в наших игрушках. Она длинная (и не точная?) , в 90% случаев ее можно заменить умножением.
это из за прцесора avr . в grbl разработчики из за деления уже 10 лет не могут решить важную функцию которая есть на других процесорах .
сейчас уже не помню что да как , я три года назад пытался на станок , не помню , вроде тангенсного ножа станок , наделить функциюь, не смог и связался с разработчиками , они обьяснили что из за деления на avr и esp32 это нельзя сделать , только на stm32 и др.
и обьяснили что да как нужно сделать .
мне тогда парень софт плагин для тангенсного ножа написал а я доделал станок нормально и получил опыт .
но ничего , доже без этой фунции grbl дорос до профессионального софта и развивается .
да , вспомнил , avr не может круг за один раз сделать , Gcode команда G3 не работает , связано это с делением окружности , можно только сделать полудугами или множеством прямых отрезков .
всегда есть выход .

связано это с делением окружности
если использовать ПИ то никто не может, в окружности будет всегда дырка, то-есть абсолютно всегда!
сегодня начал собирать принтер .
ардуина плата стояла неделю .
до разборки стояла прошивка и все работало .
При сборки и проверки оказалось что при включении ардуино мотор начинает ход . упирается в концевик и отьезжает как по коду и снова вперед .
начал искать причину . сжег драйвер поменял и тоже самое .
выяснил . что из кода убираешь блок джойстика и все тогда нормально .
у меня 20 шт скечей и все они с джойстиком кодом нормально работали . то есть , пока джойстик не трониш , мотор не поедет .
джойстик устройство ни при чем . я его менял на запасной и отсоединял итд
убираю строчки кода все норм
то есть . получается аналоговый вход что то случилось .
но плата с расборки не включалась .
остальное все вроде работает и концевики и энкодер и кнопки и мотор
плату вроде форматировал или фиг знает .
инструменты автоформатированния .
что может такое быть .?
спиртом протер плату .

что может такое быть .?
Выкладывайте код, с которым это произошло

Выкладывайте код, с которым это произошло
со всеми . , что раньше работали . их шт 20
со старыми с новыми
они есть уже здесь .
//Энкодер на пинах 2, 3.
volatile long int enc , ST;
#define ENABLE_PIN 8
#include <avr/wdt.h> // Библиотека часть компилятора avr-gcc
#define limitPin 9
#define button1 6
#define button2 5
void setup(){
Serial.begin(115200);
pinMode(2,INPUT_PULLUP);
pinMode(3,INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(ENABLE_PIN , OUTPUT);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
PCIFR=PCIF2; PCICR=1<<PCIE2; //разрешить прерывание
PCMSK2=1<<PCINT18 | 1<<PCINT19; //выбрать вход на котором сработает прерывание
}
uint32_t timer = 0;
void(* resetFunc) (void) = 0;
const int STEP_PIN = 4;
const int DIR_PIN = 7;
const int R360 = 200;
int T = 10;
int A = 0;
ISR(PCINT2_vect){
static char EncPrev=0; //предыдущее состояние энкодера
static char EncPrevPrev=0; //пред-предыдущее состояние энкодера
char EncCur = 0;
if(!(PIND & (1 << PD2))){EncCur = 1;} //опрос фазы 1 энкодера
if(!(PIND & (1 << PD3))){ EncCur |= 2;} //опрос фазы 2 энкодера
if(EncCur != EncPrev) //если состояние изменилось,
{ if(EncPrev == 3 && //если предыдущее состояние 3
EncCur != EncPrevPrev ) //и текущее и пред-предыдущее не равны,
{
if(EncCur == 2)
(enc++, Serial.println(enc) ,Serial.println(ST));
if (enc < 50000) {
for (ST = enc++/1.04; enc++ < ST; ST ++)
(digitalWrite(DIR_PIN, 0), digitalWrite(ENABLE_PIN, 0));
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(2);
digitalWrite(STEP_PIN, LOW);
}
else
(enc-- , digitalWrite(ENABLE_PIN, HIGH) , digitalWrite(DIR_PIN, HIGH));
if (enc < 0) {
enc = 0;}
}
EncPrevPrev = EncPrev; //сохранение пред-предыдущего состояния
EncPrev = EncCur; //сохранение предыдущего состояния
}
}
void Step() // функция вращеия мотора
{
digitalWrite(ENABLE_PIN, LOW);
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(T);
digitalWrite(STEP_PIN, LOW);
}
void reboot() { // функция сторожевого таймера
wdt_disable();
wdt_enable(WDTO_15MS);
while (1) {}
}
void loop() {
if (!digitalRead(5)) { // кнока ухода в нулевое положеия
digitalWrite(ENABLE_PIN, LOW);
digitalWrite(DIR_PIN, HIGH);
for (int i = 0; (!digitalRead(9)) < 1; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(500);
digitalWrite(STEP_PIN, LOW);
}
}
if (!digitalRead(6)) { // двигатель откл.
digitalWrite(ENABLE_PIN, HIGH);
digitalWrite(STEP_PIN, HIGH);
}
A = analogRead(A4); // pin joystick
if (A > 520) {
T = map(A, 520, 1123, 500, 0);
digitalWrite(7, 1);
Step();
}
if (A < 480) {
T = map(A, 480, 0, 500, 0); // 500, 0); шкала перерасчета
digitalWrite(7, 0);
Step();
}
if (A > 480 && A < 520) { // 480 < Serial.println(A); < 520
digitalWrite(7, 0);
digitalWrite(4, 0);
}
if (!digitalRead(10)) { //pin коцевика
digitalWrite(ENABLE_PIN, LOW);
digitalWrite(DIR_PIN, HIGH);
for (int i = 0; i < R360; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(1000); // скорость отьеда от limit
digitalWrite(STEP_PIN, LOW);
}
}
if (!digitalRead(9)) { //pin коцевика
digitalWrite(ENABLE_PIN, LOW);
digitalWrite(DIR_PIN, LOW);
for (int i = 0; i < R360; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(1000); // скорость отьеда от limit
digitalWrite(STEP_PIN, LOW);
}
{ delay(1000);
reboot(); // сброс таймера
}
}
}
если убрать юлок джойстика то все нормально .
A = analogRead(A4); // pin joystick
if (A > 520) {
T = map(A, 520, 1123, 500, 0);
digitalWrite(7, 1);
Step();
}
if (A < 480) {
T = map(A, 480, 0, 500, 0); // 500, 0); шкала перерасчета
digitalWrite(7, 0);
Step();
}
if (A > 480 && A < 520) { // 480 < Serial.println(A); < 520
digitalWrite(7, 0);
digitalWrite(4, 0);
}
if (!digitalRead(10)) { //pin коцевика
digitalWrite(ENABLE_PIN, LOW);
digitalWrite(DIR_PIN, HIGH);
for (int i = 0; i < R360; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(1000); // скорость отьеда от limit
digitalWrite(STEP_PIN, LOW);
}
}

со всеми . , что раньше работали . их шт 20
со старыми с новыми
Дык, если код не менялся, железо проверять надо…