Как скрестить джойстик с шаговым двигателем?)

gvozdik

✩✩✩✩✩✩✩
15 Окт 2024
7
0
Взял примеры с "Изучаем Arduino от AlexGyver" : джойстик и шаговый двигатель.
Все работает:
начальный скетч:
// пример с записанным в памяти маршрутом
int path[][2] = {   {10, 10},   {100, 5},   {200, 200},   {150, 150},   {0, 0},   {0, 50}, };
int nodeAmount = sizeof(path) / 4;    // количество точек (пусть компилятор сам считает) как вес всего массива / (2+2) байта

#include "GyverPlanner.h"

Stepper<STEPPER2WIRE> stepper1(8, 9);
Stepper<STEPPER2WIRE> stepper2(5, 6);
GPlanner<STEPPER2WIRE, 2> planner;

#define J_VRX 0
#include <GyverJoy.h>
GyverJoy jx(J_VRX);   // джойстик на пине 1


void setup() {
  Serial.begin(115200);
  // добавляем шаговики на оси
  planner.addStepper(0, stepper1);  // ось 0
  planner.addStepper(1, stepper2);  // ось 1

  // устанавливаем ускорение и скорость
  planner.setAcceleration(100);
  planner.setMaxSpeed(300);

  jx.calibrate();   // калибровка нуля при запуске
  jx.deadzone(30);  // мёртвая зона

}

//int count = 0;  // счётчик точек маршрута
void loop() {
  // здесь происходит движение моторов, вызывать как можно чаще
  planner.tick();

  // вернёт true, если все моторы доехали
  if (planner.ready()) {

  //  Chagaem();

    if (count < nodeAmount) {         // ограничиваем на количество точек, чтобы не бахнуло
     planner.setTarget(path[count]); // загружаем новую точку (начнётся с 0)
     count++;
    }
  }

  // тикер опрашивает АЦП по своему таймеру
  if (jx.tick()) {
    // выводим значение
    Serial.println(jx.value());
  }
}
Решил Все что касается ШД перенести в stepper5 : (создал cpp и h)
получилось:
начальный скетч- измененный:
#include "stepper5.h"

//// пример с записанным в памяти маршрутом
//int path[][2] = {   {10, 10},   {100, 5},   {200, 200},   {150, 150},   {0, 0},   {0, 50}, };
//int nodeAmount = sizeof(path) / 4;    // количество точек (пусть компилятор сам считает) как вес всего массива / (2+2) байта

#include "GyverPlanner.h"

Stepper<STEPPER2WIRE> stepper1(8, 9);
Stepper<STEPPER2WIRE> stepper2(5, 6);
GPlanner<STEPPER2WIRE, 2> planner;

#define J_VRX 0
#include <GyverJoy.h>
GyverJoy jx(J_VRX);   // джойстик на пине 1


void setup() {
  Serial.begin(115200);
  // добавляем шаговики на оси
  planner.addStepper(0, stepper1);  // ось 0
  planner.addStepper(1, stepper2);  // ось 1

  // устанавливаем ускорение и скорость
  planner.setAcceleration(100);
  planner.setMaxSpeed(300);

  jx.calibrate();   // калибровка нуля при запуске
  jx.deadzone(30);  // мёртвая зона

}

//int count = 0;  // счётчик точек маршрута
void loop() {
  // здесь происходит движение моторов, вызывать как можно чаще
  planner.tick();

  // вернёт true, если все моторы доехали
  if (planner.ready()) {

    Chagaem();

//    if (count < nodeAmount) {         // ограничиваем на количество точек, чтобы не бахнуло
//      planner.setTarget(path[count]); // загружаем новую точку (начнётся с 0)
//      count++;
//    }
  }

  // тикер опрашивает АЦП по своему таймеру
  if (jx.tick()) {
    // выводим значение
    Serial.println(jx.value());
  }
}
stepper5.h:
#pragma once
// Указывает компилятору, что данный файл нужно подключить только один раз.

#include <Arduino.h>

extern GPlanner<STEPPER2WIRE, 2> planner;

void Chagaem();
stepper5.cpp:
#include "stepper5.h"

// пример с записанным в памяти маршрутом
int path[][2] = {   {10, 10},   {100, 5},   {200, 200},   {150, 150},   {0, 0},   {0, 50}, };
int nodeAmount = sizeof(path) / 4;    // количество точек (пусть компилятор сам считает) как вес всего массива / (2+2) байта
int count = 0;  // счётчик точек маршрута


void Chagaem() {
  if (count < nodeAmount) {         // ограничиваем на количество точек, чтобы не бахнуло
    planner.setTarget(path[count]); // загружаем новую точку (начнётся с 0)
    count++;
  }
}
planner не видится :
error: 'GPlanner' does not name a type
'planner' was not declared in this scope

Как его правильно подключить?
В чем ошибка?

как обращаться к
GPlanner<STEPPER2WIRE, 2> planner; - описанном в главном скетче
из stepper5.cpp ?
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Это особенность шаблонов С. Перенесите весь код stepper5.cpp в stepper5.h - будет компилироваться
 

gvozdik

✩✩✩✩✩✩✩
15 Окт 2024
7
0
@bort707,
новый stepper5.h:
#pragma once
// Указывает компилятору, что данный файл нужно подключить только один раз.

#include <Arduino.h>

extern GPlanner<STEPPER2WIRE, 2> planner;

// пример с записанным в памяти маршрутом
int path[][2] = {   {10, 10},   {100, 5},   {200, 200},   {150, 150},   {0, 0},   {0, 50}, };
int nodeAmount = sizeof(path) / 4;    // количество точек (пусть компилятор сам считает) как вес всего массива / (2+2) байта
int count = 0;  // счётчик точек маршрута

void Chagaem() {
  if (count < nodeAmount) {         // ограничиваем на количество точек, чтобы не бахнуло
    planner.setTarget(path[count]); // загружаем новую точку (начнётся с 0)
    count++;
  }
}
не прокатило...
error: 'GPlanner' does not name a type
In function 'void Chagaem()': stepper5.h:18:5: error: 'planner' was not declared in this scope

не видится planner
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
472
134
@gvozdik,
Просто добавить #include "GyverPlanner.h" в stepper5.h:
Хотя переменная и внешняя для stepper5.cpp, но правила работы должны быть известны и в stepper5.cpp, для этого должен быть #include "GyverPlanner.h"

ПС (Есть ли особенность для шаблонов - не знаю).
 
  • Лойс +1
Реакции: bort707

bort707

★★★★★★✩
21 Сен 2020
3,058
910
добавить #include "GyverPlanner.h" в stepper5.h:
А, ну да:) это в любом случае.


@gvozdik, я был уверен что это вы сразу сделали, даже и не посмотрел.
Это базовые вещи - если используете библиотеку или сторонний класс - включайте его хидер в каждый файл, где он используется.

В вашем случае ещё можно вместо описания GPlanner как extern передать его как параметр в функцию Chagaem()
 

gvozdik

✩✩✩✩✩✩✩
15 Окт 2024
7
0
@Bruzzer, добавка #include "GyverPlanner.h" все решила! Спасибо! Упустил.
Теперь выношу все что касается джойстика в отдельный файл:
Joy.h:
#pragma once
#include <Arduino.h>
#include <GyverJoy.h>

//extern GyverJoy jx(0);   // джойстик на пине 0

void Prn_Ms() {
   // выводим значение
    Serial.println(jx.value());
}
из скетча обращаемся через Prn_Ms();
Не сидится jx.
если оставляем
extern GyverJoy jx(0); // джойстик на пине 0
выскакивает ошибка : error: redefinition of 'GyverJoy jx' в скетче
Как быть?
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
472
134
@gvozdik,
Вопрос "Как быть?" - расцениваю, как риторический.
Я не знаю, что в какой последовательности целесообразно изучать. Я думаю, разбиение на файлы, это не то с чего надо начинать. И можно долго работать с ардуино до того как это понадобится.
Сейчас есть сомнения - не троллинг ли это с вашей стороны. Так что отключаюсь от дальнейшего обсуждения.

Переменная должна быть объявлена до ее использования.
Включение #include - просто вставляет текст файла в это место.
Значит если Joy.h вставляется в основной скетч, то переменная в строке 5 не extern, а обычная, а ее второе объявление в тексте скетча надо удалить.
Но повторюсь - правильность и целесообразность такого разбиения на файлы я оценить не берусь.
 

gvozdik

✩✩✩✩✩✩✩
15 Окт 2024
7
0
@Bruzzer,спасибо!
C++:
#include "stepper5.h"
#include "GyverPlanner.h"

Stepper<STEPPER2WIRE> stepper1(8, 9);
Stepper<STEPPER2WIRE> stepper2(5, 6);
GPlanner<STEPPER2WIRE, 2> planner;

#define J_VRX 0
#include <GyverJoy.h>

GyverJoy jx(J_VRX);   // джойстик на пине 0

#include "Joy.h"

void setup() {.........
поставив #include "Joy.h" после GyverJoy jx(J_VRX);
действительно все заработало!

изучая материалы по программированию (https://alexgyver.ru/lessons/big-projects/) везде #include выносятся в начало . Поэтому я так и сделал...
но здесь похоже не тот вариант.
.... и напрягает что пришлось весь код по ШД свалить в stepper5.h, а не в stepper5.h и stepper5.cpp . но, думаю, со временем разберусь.
Спасибо за помощь.