Щоденний радіожурнал зі звуком. Іноді з гумором. Завжди з картинками

Круглые столы области

Круглий стiл 11.10.25 Record by UY2RA Круглий стiл 01.11.25 Record by UY2RA

02.11.2025

Второй пилот

 Как и больштнство "поверхностных" пользователей Windows 11 я не обратил особого внимания на программный Copilot.  Но когда  мой друг написал что экономит на нём кучу времени я подумал что наверное стоит попробовать. Для примера я вернулся к заброшенному прожекту поворотки с указателем на потенциометре.  В своё время я его бросил как раз из-за недостатка времени и свежих идей - неточности в работе сильно раздражали. А "вычистить" логику и перевести в код без ошибок не хватило времени . А может терпения :-) Одним словом пробуем новое.  Прошу копилота написать скетч для Ардуино  чтобы вращал антенну:

Создать скетч поворотного устройства для Ардуино с указанием угла установки исполнительного мотора с помощью двух потенциометров. Первый из них ведущий, предустановка. Второй отслеживает реальное положение антенны и если они не совпадают определяет направление движения и включает мотор в эту сторону. На двустрочном дисплее выводить на английском значение предустановки, реального угла поворота направление движениея и статус мотора.

Ответ второго пилота: Отличная задача — это классический пример системы с обратной связью: один потенциометр задаёт целевой угол (setpoint), второй измеряет фактическое положение (feedback), а мотор двигается до совпадения. Ниже приведён пример скетча для Arduino с использованием двух потенциометров, реле/драйвера мотора и LCD 16x2 (через библиотеку LiquidCrystal).

⚙️ Аппаратная схема (пример)

  • Pot1 (предустановка) → A0

  • Pot2 (датчик положения) → A1

  • Мотор → через драйвер (например, L298N или H-bridge) к пинам D8 и D9 (вперёд/назад)

  • LCD 16x2 → пины RS=12, E=11, D4=5, D5=4, D6=3, D7=2

📜 Код Arduino

cpp
#include <LiquidCrystal.h>

// LCD: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int potSetPin = A0;   // ведущий потенциометр (предустановка)
const int potRealPin = A1;  // обратная связь (реальное положение)

const int motorPinFwd = 8;  // мотор вперёд
const int motorPinRev = 9;  // мотор назад

int setAngle = 0;
int realAngle = 0;
int deadZone = 3; // допуск в градусах

void setup() {
  pinMode(motorPinFwd, OUTPUT);
  pinMode(motorPinRev, OUTPUT);
  lcd.begin(16, 2);
  lcd.clear();
}

void loop() {
  // Чтение потенциометров (0-1023) и преобразование в угол (0-180)
  setAngle = map(analogRead(potSetPin), 0, 1023, 0, 360);
  realAngle = map(analogRead(potRealPin), 0, 1023, 0, 360);

  String direction = "STOP";
  String motorStatus = "OFF";

  // Управление мотором
  if (abs(setAngle - realAngle) > deadZone) {
    if (setAngle > realAngle) {
      digitalWrite(motorPinFwd, HIGH);
      digitalWrite(motorPinRev, LOW);
      direction = "RIGHT";
      motorStatus = "ON";
    } else {
      digitalWrite(motorPinFwd, LOW);
      digitalWrite(motorPinRev, HIGH);
      direction = "LEFT";
      motorStatus = "ON";
    }
  } else {
    digitalWrite(motorPinFwd, LOW);
    digitalWrite(motorPinRev, LOW);
  }

  // Вывод на дисплей
  lcd.setCursor(0, 0);
  lcd.print("Set:");
  lcd.print(setAngle);
  lcd.print(" Real:");
  lcd.print(realAngle);

  lcd.setCursor(0, 1);
  lcd.print("Dir:");
  lcd.print(direction);
  lcd.print(" M:");
  lcd.print(motorStatus);

  delay(200);
}

🖥️ Что будет на дисплее

Пример отображения: 

Код
Set:120 Real:115
Dir:RIGHT M:ON
  • Set — предустановленный угол

  • Real — фактический угол

  • Dir — направление движения (LEFT/RIGHT/STOP)

  • M — статус мотора (ON/OFF)

К момему удивлению скетч заработал сразу и правильно. Единственное замечание было к тому что он не знал, что у меня реле c отрицательной логикой и естествеено вкл/выкл мотора, а точнее влево/вправо после остановки оставались включенными.  И еще забыл ему сказать что дисплей подключен по I2C. Задаю исправления которые надо внести:

Дисплей подключен по i2C. Он не отображает положение углов. Сделать замедление Старт-Стоп но без PWM

Ответ второго пилота: Понял 👍. Если у вас дисплей по I²C, нужно использовать библиотеку LiquidCrystal_I2C. А для «замедления без PWM» можно сделать пошаговое движение: мотор включается короткими импульсами с паузами, и чем ближе к целевому углу — тем длиннее пауза. Это даст эффект замедления без использования ШИМ.

📜 Обновлённый скетч

cpp
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Адрес может быть 0x27 или 0x3F — зависит от модуля
LiquidCrystal_I2C lcd(0x27, 16, 2);

const int potSetPin = A0;   // ведущий потенциометр (предустановка)
const int potRealPin = A1;  // обратная связь (реальное положение)

const int motorPinFwd = 8;  // мотор вперёд
const int motorPinRev = 9;  // мотор назад

int setAngle = 0;
int realAngle = 0;
int deadZone = 2; // допуск в градусах

void setup() {
  pinMode(motorPinFwd, OUTPUT);
  pinMode(motorPinRev, OUTPUT);

  lcd.init();
  lcd.backlight();
  lcd.clear();
}

void loop() {
  // Чтение потенциометров (0-1023) и преобразование в угол (0-360)
  setAngle = map(analogRead(potSetPin), 0, 1023, 0, 360);
  realAngle = map(analogRead(potRealPin), 0, 1023, 0, 360);

  String direction = "STOP";
  String motorStatus = "OFF";

  int diff = setAngle - realAngle;

  if (abs(diff) > deadZone) {
    motorStatus = "ON";
    if (diff > 0) {
      direction = "RIGHT";
      digitalWrite(motorPinFwd, HIGH);
      digitalWrite(motorPinRev, LOW);
    } else {
      direction = "LEFT";
      digitalWrite(motorPinFwd, LOW);
      digitalWrite(motorPinRev, HIGH);
    }

    // Эффект замедления: чем ближе к цели, тем длиннее пауза
    int pauseTime = map(abs(diff), 0, 180, 200, 20); 
    delay(pauseTime);

    // Короткий импульс
    digitalWrite(motorPinFwd, LOW);
    digitalWrite(motorPinRev, LOW);
    delay(pauseTime);

  } else {
    digitalWrite(motorPinFwd, LOW);
    digitalWrite(motorPinRev, LOW);
  }

  // Вывод на дисплей
  lcd.setCursor(0, 0);
  lcd.print("Set:");
  lcd.print(setAngle);
  lcd.print(" Real:");
  lcd.print(realAngle);
  lcd.print("   "); // очистка хвоста

  lcd.setCursor(0, 1);
  lcd.print("Dir:");
  lcd.print(direction);
  lcd.print(" M:");
  lcd.print(motorStatus);
  lcd.print("   "); // очистка хвоста
}

🔑 Что изменилось

Используется LiquidCrystal_I2C для работы с дисплеем.
Добавлен «пошаговый» режим: мотор включается короткими импульсами, а пауза зависит от разницы углов.Чем ближе к цели, тем дольше пауза → мотор замедляется.

И это исправление заработало исправно. Код оказался короче и прозрачнее чем у меня было изначально. То есть я думаю что расхождения во мнениях начнутся после второго или третьего уровня корректировки задания, но пока умственные способности второго пилота меня порадовали.  В реалиях у меня потенциометры дополнены резисторами по 100 Ом сверху поэтому корретировку значений пришлочь внести. Работает в точно обозначенном диапазоне.
 // Чтение потенциометров (0-1023) и преобразование в угол (0-360)
  setAngle = map(analogRead(potSetPin), 0, 910(1023), 0, 360);
  realAngle = map(analogRead(potRealPin), 0, 910(1023), 0, 360);
Так что теперь даже те, у кого  о Ардуино совсем поверхностные сведения может запросто писать скрипты для своих устройств с применением микроконтроллеров.

Плюс исполнительный механизм с концевиками. Осталось совсем немного - собрать всё в кучу :-)



© Copyright 2011-2024 UY2RA,    All rights reserved.    Все права защищены.    Пожалуйста уважайте их. Использование материалов с этого сайта разрешается. Буду рад если при этом меня помянут незлым тихим словом.

FREE & OPEN UKRAINIAN HAM  RADIO  BANNERS NET