Управление текущей скоростью шагового двигателя через COM-порт

Rasool114
Offline
Зарегистрирован: 07.08.2022

Как написать программу (на Delphi) и скетч для задания произвольной скорости вращения шагового двигателя в любой момент времени из программы на Delphi через COM-порт на одноплатном компьютере ODYSSEY - X86J4105800? Задача заключается в том, чтобы в произвольный момент времени из программы на Delphi посылать в COM-порт один байт, задающий скорость вращения ШД, скетч должен читать этот байт и менять в соответствии с его значением текущую скорость вращения ШД. Должно быть примерно следующее:

#include <Arduino.h>
#include "BasicStepperDriver.h"
 
// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 3600
#define RPM 200
 
// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS 1
 
// All the wires needed for full functionality
#define DIR 6
#define STEP 5
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);
 
int incomingByte = 0;
 
// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(250000);
  // initialize digital pin LED_BUILTIN as an output.
  stepper.begin(RPM, MICROSTEPS);
}
 
// the loop function runs over and over again forever
void loop() {
  if (Serial.available() > 0) {  //если есть доступные данные
    // считываем байт
    incomingByte = Serial.read();
    stepper.Speed(incomingByte);
  }
 
 stepper.rotate(360);
 // delay(2000);
}

Тут возникает одна проблема последовательного чтения байтов из COM-порта в скетче. Что происходит с текущим значением в COM-порте при срабатывании команды Serial.read()? Оно сохраняется в COM-порте? Вторая проблема: как в скетче менять текущую скорость вращения ШД?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

такие вещи делают хотя бы через простейший протокол обмена

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Rasool114 пишет:

... из программы на Delphi через COM-порт на одноплатном компьютере ODYSSEY - X86J4105800

...

Что происходит с текущим значением в COM-порте при срабатывании команды Serial.read()?

...

Вторая проблема: как в скетче менять текущую скорость вращения ШД?

1. Хотел поёрничать, но кто-то повадился все мои шутки удалять... Серьёзно спрошу: что за страсть, и уже не у тебя первого, к мертвым языкам? Палеопрограммирование? Почему Дельфи и почему такая странная и жутко дорогая железка? Это не вопросы по сути, просто очень любопытно!

2. Ну а сам-то как думаешь? Если это вопрос хоть как-то осмыслен, то unread() в Ардуино не предусмотрен.

3. При помощи функции из библиотеки, у тебя ж уже написано.

Rasool114
Offline
Зарегистрирован: 07.08.2022

ua6em пишет:

такие вещи делают хотя бы через простейший протокол обмена

Спасибо за компетентное мнение, буду знать примерно в какую сторону копать.

Rasool114
Offline
Зарегистрирован: 07.08.2022

wdrakula пишет:

1. Хотел поёрничать, но кто-то повадился все мои шутки удалять... Серьёзно спрошу: что за страсть, и уже не у тебя первого, к мертвым языкам? Палеопрограммирование? Почему Дельфи

У меня сейчас на руках жутко legacy проект на Delphi в полмиллиона строк кода, над которым работали несколько программистов в течение нескольких десятилетий. Его очень проблемно перекодировать на другой язык.[/quote]

b707
Offline
Зарегистрирован: 26.05.2017

Rasool114 пишет:

У меня сейчас на руках жутко legacy проект на Delphi в полмиллиона строк кода, над которым работали несколько программистов в течение нескольких десятилетий. Его очень проблемно перекодировать на другой язык.

и оно аж несколько десятилетий назад уже управляло моторами по последовательному порту?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

b707 пишет:

Rasool114 пишет:

У меня сейчас на руках жутко legacy проект на Delphi в полмиллиона строк кода, над которым работали несколько программистов в течение нескольких десятилетий. Его очень проблемно перекодировать на другой язык.

и оно аж несколько десятилетий назад уже управляло моторами по последовательному порту?


я не знаю что там у TC, но по протоколу YAESU GS-232 двигатели управляются не одно десятилетие )))

Rasool114
Offline
Зарегистрирован: 07.08.2022

b707 пишет:

И оно аж несколько десятилетий назад уже управляло моторами по последовательному порту?

Нет, не по COM-порту. Была специальная PCI-плата для этого, которая вставлялась в системник. Этот проект был разработан для больших системных блоков.

Сейчас есть задача сделать управление нашими железками (не только шаговыми двигателями) через одноплатный компьютер. Пока остановились на посылке байтов (2 бита - номер одного из трех двигателей, 1 бит - направление движения, 5 битов - скорость вращения ШД) через COM порт на скетч Arduino.

Rasool114
Offline
Зарегистрирован: 07.08.2022

Я наваял следующий скетч:

#include <Arduino.h>

#include "BasicStepperDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 3600
#define RPM 200

// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS 1

// All the wires needed for full functionality
#define DIR 6
#define STEP 5
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);

int incomingByte = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(250000);
  // initialize digital pin LED_BUILTIN as an output.
  stepper.begin(RPM, MICROSTEPS);
}

// the loop function runs over and over again forever
void loop() {
  if (Serial.available() > 0) {  //если есть доступные данные
        // считываем байт
        incomingByte = Serial.read();
 
  if (incomingByte > 1)  {        
    stepper.rotate(1020);
    delay(2000);
    }
  else
    if (incomingByte > 0)  {         
    stepper.rotate(-1020);
    delay(2000);
    }
  }
}

void yield(){
uint16_t ADC0 = digitalRead(adc_pin0);
Serial.write(ADC0);
return;
}

Подаю на COM-порт байт "2" - ШД вращается. Посылаю на COM-порт байт "1" - ШД вращается в ту же сторону. Не понятно, почему вращается только в одну сторону.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Rasool114 пишет:

b707 пишет:

И оно аж несколько десятилетий назад уже управляло моторами по последовательному порту?

Нет, не по COM-порту. Была специальная PCI-плата для этого, которая вставлялась в системник. Этот проект был разработан для больших системных блоков.

Сейчас есть задача сделать управление нашими железками (не только шаговыми двигателями) через одноплатный компьютер. Пока остановились на посылке байтов (2 бита - номер одного из трех двигателей, 1 бит - направление движения, 5 битов - скорость вращения ШД) через COM порт на скетч Arduino.

Я буду очень не оригинален, но реально советую нанять грамотного консультанта. Можно - даже не меня! ;)) Я не могу подобрать слов для комментирования прочитанного.

Не зная таймингов оборудования, требований к скорости реакции, требований по надежности - я никаких рекомендаций не стану писать. Если это реальное научное или промышленное решение, которому "десятки лет", то просто анализ задачи и рекомендации по способам решения - это нормальный консалтинг. Без накладных накруток на фирму я, как фрилансер, оцениваю примерно в 25-30 т.р.

Базовые варианты - поставьте на компьютер модуль CAN или RS485, а модуль управления периферией - на соответствующем интерфейсе ...ну пусть на Ардуине, меня она особо не коробит, при правильном использовании. Такой вариант будет хоть немного похож на профессиональное решение.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

wdrakula пишет:

 Я не могу подобрать слов для комментирования прочитанного.

ты не одинок )))

lilik
Offline
Зарегистрирован: 19.10.2017

Rasool114 пишет:

Подаю на COM-порт байт "2" - ШД вращается. Посылаю на COM-порт байт "1" - ШД вращается в ту же сторону. Не понятно, почему вращается только в одну сторону.

Так и должно быть.

int val;
int LED = 13;
void setup()
{
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);
}
void loop()
{
  if (Serial.available())
  {
    val = Serial.read();
    // При символе "1" включаем светодиод
    if (val == '1')
    {
      digitalWrite(LED, HIGH);
    }
    // При символе "0" выключаем светодиод
    if ( val == '0')
    {
      digitalWrite(LED, LOW);
    }
  }
}

Видите 1 и 2 это не числа, а символы.

vrd
Offline
Зарегистрирован: 20.01.2022

Для начала подключить дуину к ком порту и посмотреть - а чего шлёт нам ком порт. И от этого плясать.

ТС пишет про байты с ком порта, а использует параметр ИНТ в скетче. Моя твоя непонимай.

Rasool114
Offline
Зарегистрирован: 07.08.2022
У меня есть три скетча:
 
1. При работе этого скетча при посылке байта из программы ардуино ловит его, но не различает его значение - ШД поворачивается с постоянной скоростью.
 
#include <Arduino.h>
#include "BasicStepperDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 3600
byte RPM = 60;

// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS 1

// All the wires needed for full functionality
#define DIR 6
#define STEP 5
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);

uint8_t incomingByte = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(250000);
}

// the loop function runs over and over again forever
void loop() {
  if (Serial.available() < 1) return;  // Если есть доступные данные, считываем байт
  incomingByte = Serial.read(); // Чтение байта из программы - ШД поворачивается с постоянной скоростью
  RPM = incomingByte;
  stepper.begin(RPM, MICROSTEPS); // Здесь крутится с постоянной скоростью
  stepper.rotate(100);
  delay(1); 
}
 
2. При работе этого скетча байт посылается из программы - но скетч не работает. В смысле, ничего не крутится.
 

#include <Arduino.h>
#include "BasicStepperDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 3600
byte RPM = 60;
byte Angle = 10;

// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS 1

// All the wires needed for full functionality
#define DIR 6
#define STEP 5
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);

uint8_t incomingByte = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(250000); 
}

// the loop function runs over and over again forever
void loop() {
  if (Serial.available() < 1) return;  // Если есть доступные данные, считываем байт
  incomingByte = Serial.read(); // Чтение байта из программы - не работает. В смысле, ничего не крутится.
  stepper.begin(RPM, MICROSTEPS);
  switch( incomingByte )
  { 
    case 0: stepper.disable(); break;
    case 1: stepper.rotate(2000); break;
    case 2: stepper.rotate(-2000); break;
    case 3: RPM += 20; break;
    case 4: RPM -= 20; break;
    case 5: stepper.move(-MOTOR_STEPS*MICROSTEPS); break;
    case 6: stepper.move( MOTOR_STEPS*MICROSTEPS); break;
    case 7: stepper.enable(); break;
    default: break;
  }
  delay(1);
}
 
3. Число посылается из монитора COM-порта - все работает, движок крутится, как ему положено. 
 
#include <Arduino.h>
#include "BasicStepperDriver.h"

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 3600
byte RPM = 60;
byte Angle = 10;

// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS 1

// All the wires needed for full functionality
#define DIR 6
#define STEP 5
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);

uint8_t incomingByte = 0;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(250000);
}

// the loop function runs over and over again forever
void loop() {
  if (Serial.available() < 1) return;  // Если есть доступные данные, считываем байт
  incomingByte = Serial.read()-48; // Чтение байта из монитора - все работает, движок крутится
  Serial.read();
  Serial.println(incomingByte);
  stepper.begin(RPM, MICROSTEPS);
  switch( incomingByte )
  { 
    case 0: stepper.disable(); break;
    case 1: stepper.rotate(2000); break;
    case 2: stepper.rotate(-2000); break;
    case 3: RPM += 20; break;
    case 4: RPM -= 20; break;
    case 5: stepper.move(-MOTOR_STEPS*MICROSTEPS); break;
    case 6: stepper.move( MOTOR_STEPS*MICROSTEPS); break;
    case 7: stepper.enable(); break;
    default: break;
  }
  delay(1);
}

В чем дело? И как можно увидеть в скетче число, которое получает Ардуино из COM-порта?

 
sadman41
Offline
Зарегистрирован: 19.10.2016

Дело в том, что взялись не за своё. С наскоку тут ничего не выйдет, начинать надобно с более простых задач.
Но, может, и случайно получится... Если руки никому этим мотором не оторвет.

Rix1970
Offline
Зарегистрирован: 16.06.2022

В нашей программе на Delphi есть специальная кнопочка, при нажатии на которую вызывается процедура с аргументами SendToCOMPort(ComPort, Speed), где Speed - это скорость вращения, которая задается в специальном поле на нашей формочке,
а при отжатии кнопки вызывается SendToCOMPort(ComPort, 0).

 

procedure SendToCOMPort(ComPort: TComPort; Value: Integer);
var
  code: Integer;
  str: String;
begin
  if not ComPort.Connected then Exit;
  if Value < 0 then code := 0
  else code := Value;
  str := IntToStr(code);
//  str := str + #13#10;
  ComPort.WriteStr(str);
end;

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

в цифре 48 )))

Rix1970
Offline
Зарегистрирован: 16.06.2022

Большое спасибо за подсказку про передачу символов, а не чисел в COM-порт. Сделал - все заработало. (Чувствую себя идиотом, что сам не допер до этого.)

Rasool114
Offline
Зарегистрирован: 07.08.2022

Сейчас мучаю скетч NonBlocking.ino. У нас стоит задача запустить вращение мотора из Delphi и во время его вращения управлять его скоростью тоже из Delphi. Из библиотеки StepperDriver попробовал загрузить для пробы скетч NonBlocking.ino - ШД не крутится. Что не так?

/*
 * Example using non-blocking mode to move until a switch is triggered.
 *
 * Copyright (C)2015-2017 Laurentiu Badea
 *
 * This file may be redistributed under the terms of the MIT license.
 * A copy of this license has been included with this distribution in the file LICENSE.
 */
#include <Arduino.h>

// this pin should connect to Ground when want to stop the motor
#define STOPPER_PIN 4

// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200
#define RPM 120
// Microstepping mode. If you hardwired it to save pins, set to the same value here.
#define MICROSTEPS 16

#define DIR 8
#define STEP 9
#define SLEEP 13 // optional (just delete SLEEP from everywhere if not used)

/*
 * Choose one of the sections below that match your board
 */

#include "DRV8834.h"
#define M0 10
#define M1 11
DRV8834 stepper(MOTOR_STEPS, DIR, STEP, SLEEP, M0, M1);

// #include "A4988.h"
// #define MS1 10
// #define MS2 11
// #define MS3 12
// A4988 stepper(MOTOR_STEPS, DIR, STEP, SLEEP, MS1, MS2, MS3);

// #include "DRV8825.h"
// #define MODE0 10
// #define MODE1 11
// #define MODE2 12
// DRV8825 stepper(MOTOR_STEPS, DIR, STEP, SLEEP, MODE0, MODE1, MODE2);

// #include "DRV8880.h"
// #define M0 10
// #define M1 11
// #define TRQ0 6
// #define TRQ1 7
// DRV8880 stepper(MOTORS_STEPS, DIR, STEP, SLEEP, M0, M1, TRQ0, TRQ1);

// #include "BasicStepperDriver.h" // generic
// BasicStepperDriver stepper(DIR, STEP);

void setup() {
    Serial.begin(115200);

    // Configure stopper pin to read HIGH unless grounded
    pinMode(STOPPER_PIN, INPUT_PULLUP);

    stepper.begin(RPM, MICROSTEPS);
    // if using enable/disable on ENABLE pin (active LOW) instead of SLEEP uncomment next line
    // stepper.setEnableActiveState(LOW);
    stepper.enable();

    // set current level (for DRV8880 only). Valid percent values are 25, 50, 75 or 100.
    // stepper.setCurrent(100);

    Serial.println("START");

    // set the motor to move continuously for a reasonable time to hit the stopper
    // let's say 100 complete revolutions (arbitrary number)
   // stepper.startMove(100 * MOTOR_STEPS * MICROSTEPS);     // in microsteps
    stepper.startRotate(100 * 360);                     // or in degrees
}

void loop() {
    // first, check if stopper was hit
    if (digitalRead(STOPPER_PIN) == LOW){
        Serial.println("STOPPER REACHED");

        /*
         * Choosing stop() vs startBrake():
         *
         * constant speed mode, they are the same (stop immediately)
         * linear (accelerated) mode with brake, the motor will go past the stopper a bit
         */

        // stepper.stop(); // Закомментировал временно
        // stepper.startBrake();
    }

    // motor control loop - send pulse and return how long to wait until next pulse
    unsigned wait_time_micros = stepper.nextAction();

    // 0 wait time indicates the motor has stopped
    if (wait_time_micros <= 0) {
        stepper.disable();       // comment out to keep motor powered
        delay(3600000);
    }

    // (optional) execute other code if we have enough time
    if (wait_time_micros > 100){
        // other code here
    }
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

нет ребята всё не так, всё не так ребята )))

nik182
Offline
Зарегистрирован: 04.05.2015

Задержка на 1 час это круто!

 

Rix1970
Offline
Зарегистрирован: 16.06.2022

На Arduino.cc мне посоветовали использовать библиотеку MobaTools, которая может уменьшать и увеличивать скорость вращения шаговика во время его работы. На Github'е указано, что она поддерживает следующие процессоры:
- AVR ATmega
- AVR ATtiny, if it has the 16-bit timer 1 and a SPI or USI hardware
- STM32F103x processors ( the core of Roger Clark must be used )
- ESP32 ( minimum core version is 1.0.6 )
- ESP8266 ( with some restrictions, Stepper via SPI does not work )
Мы работаем на одноплатном компьютере "ODYSSEY - X86J4105800" с "Arduino Coprocessor ATSAMD21 Core ARM Cortex-M0+". Он подходит для Mobatools? И еще глупый вопрос: как можно скачать и установить Mobatools с Github? Можно скачать соответствующие cpp-файлы и откомпилировать их у себя?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Rix1970 пишет:

На Arduino.cc мне посоветовали

 

Подгоняешь DetSimen плату (если согласится) тогда у тебя будет хотя бы призрачная возможность реализовать свои хотелки

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ua6em пишет:
Подгоняешь DetSimen плату (если согласится)

Нет.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ua6em пишет:
Подгоняешь DetSimen плату (если согласится)

Нет.

Дима, ты чё такой категоричный, хотя бы глянули, что за зверь )))

Rix1970
Offline
Зарегистрирован: 16.06.2022

Попытался установить эту библиотеку (Mobatools) и скомпилировать скетч - выдает ошибку:

Используем библиотеку MobaTools-master версии 2.4.3 из папки: C:\Users\ODYSSEY\Documents\Arduino\libraries\MobaTools-master exit status 1 Ошибка компиляции для платы Seeeduino Zero.

Походу, с этой платой Mobatools не работает.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Rix1970 пишет:

Попытался установить эту библиотеку (Mobatools) и скомпилировать скетч - выдает ошибку:

Используем библиотеку MobaTools-master версии 2.4.3 из папки: C:\Users\ODYSSEY\Documents\Arduino\libraries\MobaTools-master exit status 1 Ошибка компиляции для платы Seeeduino Zero.

Походу, с этой платой Mobatools не работает.

а с чего ей работать?

берешь даташит и дописываешь библиотеку