Система автоматического тестирования ВМГ (народный проект)

sulaex

Инструкция

Будьте внимательны при работе со стендом!!!

DOS-интерфейс
Имея скромные познания в программировании, и тем более работая над проектом, впервые столкнулся с платформой ардуина (имеется в виду, что либо писать под нее), решил не слишком напрягаться и создать интерфейс а ля DOS-консоль (так как хотелось побыстрее получить результаты).
И так, слепленный из чего под руку попавшееся наш стенд, подключаем к юзби компьютера, запускаем любой терминал (PuTTY, ардуиновский, маздаевский Hiper Terminal и т. д.).
Начальное меню будет выглядеть так:

%       g       v       v+f+*   a       a+f+*
0       0       0.00    0.00    0.00    0.00

Please type the commands:
test(t), calibration(c), null(n)

>

Первым делом вам предлагаются данные с датчиков.
% - шаг тяги
g - тяга (не нуждается в фильтрации ИМХО)
v - напряжение как есть
v+f+* - напряжение после фильтра и коэффициента для выравнивания
a - ток как есть
a+f+* - ток после фильтра и коэффициента для выравнивания
Данные “как есть” предназначены для ваших фильтров, если надумаете писать свои обработчики данных или интерфейсы.

Нажмите Enter и данные с датчиков прочитаются еще раз.
Таким образом можно мониторить данные с датчиков.

Дальше имеем подсказку, что можно выбрать для последующих действий.
test(t) - перейти в меню тестов
calibration© - перейти в меню калибровки датчиков
null(n) - перейти в меню установки нулевых значений

Первым делом нам следует установить нулевое значение и откалибровать датчики.

Нажимаем клавишу “n” - переходим в меню установки нулевых значений.

============= Select action: =============
1 - null weight
2 - null current
any key - return to console
==========================================

1 - обнуление датчика тяги
2 - обнуление датчика тока
любая клавиша - возврат в начальное меню

Уберите с датчика тяги любой посторонний вес и нажмите клавишу “1”, произойдет обнуление значения данных с тензадатчика. Под посторонним весом подразумевается все, что вносит погрешность в измерение. У меня в тензодатчик вкручен болт, с помощью его я регулирую расстояние до ноги луча, но меняя разные пропеллеры, которые имеют разный вес, не обязательно болтом подгонять идеальное расстояние, достаточно просто принять малую долю в изменении веса за нулевое значение. Так же обнуление датчика тяги может понадобиться при длительной эксплуатации или изменении температуры.

Также следует обнулить начальные значения с датчика тока. Для этого отключите любую нагрузку (регулятор) и нажмите клавишу “2”, предварительно войдя в меню обнуления. Это следует проделать единожды и повторять, если заметите изменение нулевого значения.

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

============= Select action: =============
1 - calibration weight
2 - calibration voltage
3 - calibration current
4 - calibration ESC
any key - return to console
==========================================

1 - калибровка тяги
2 - калибровка напряжения
3 - калибровка тока
4 - калибровка регуля
любая клавиша - выход в начальное меню

Для калибровки тяги нажимаем клавишу “1”. Берем эталонный вес, его можно получить разными способами, например, если нет весов в наличии, возьмите любой предмет и взвесьте его на магазинных весах, на крайний случай при покупке продуктов на них указывается вес. В общем, чем точнее будет значение веса эталона, тем лучше для получаемых результатов. Кладем эталон на тензодатчик и набираем вес в граммах, после чего нажимаем “Enter”. Проверяем точность.

Для калибровки напряжения нажмите клавишу “2” из меню калибровок и так же как в предыдущем абзаце введите значение эталонного напряжения, предварительно подключив аккумулятор к стенду и измерив напряжение тестером. Ввод напряжения производится без учета запятой. Например напряжение 4 баночного аккумулятора значением в 16,65 вольта следует ввести как 1665 и нажать клавишу “Enter”.

Калибровка датчика тока. Как и следовало ожидать, из меню калибровок нажимаем клавишу “3” и так же вводим значение тока без запятой с эталонного замера. Здесь имеются некоторые сложности в получении эталонного значения по току. Если вы имеете какие либо предложения для решения данной проблемы, прошу высказываться. Пока более простого решения нет, в программе все таки имеется возможность калибровки. Для этого в разрыв питания регуля подключаем амперметр. Собираем ВМГ как для теста и нагружаем датчик тока путем раскрутки ВМГ. В режиме ввода эталонного значения тока можно нажимать клавиши “+” и “-” для задействования ВМГ в качестве нагрузки. Плюсом будем увеличивать обороты, минусом уменьшать. Но не забываем перед этими действиями откалибровать регулятор.

ВНИМАНИЕ!!! СНИМИТЕ ПРОПЕЛЛЕР С МОТОРА.
Калибровка регулятора (установка высокого и низкого уровня). Сигнальный провод регулятора должен быть отключен от стенда. Выбираем данный режим нажав клавишу “4”.

==========================================
1 - 100%
0 - 0%
any key - return to console
==========================================

Клавишей “1” вы установите высокий уровень на клейме стенда, подключите сигнальный разъем от регуля к стенду, регуль (сигналы могут быть разными) пропищит, нажмите клавишу “2”, установится нулевое значение на клейме стенда, после этого регуль готов для работы. Проверяем уровни например ручным тестом. Вращаться мотор должен начать при уровне 0-5% и максимально вращаться на 95-100%.

Закончив обнуление и калибровку стенда можно приступать к работе.
Имеется три режима тестов.
Нажмите клавишу “t”

============= Select action: =============
1 - begin auto test 50, 65, 75, 85, 100%
2 - begin auto test 1-100%
3 - begin manual test
any key - return to console
==========================================

1 - запускаем тест с замером промежутков по тяге 50, 65, 75, 85, 100%
2 - запускаем тест с шагом тяги от 1 до 100%
3 - запускаем тест с ручным управлением тяги
любая клавиша - выйти в основное меню

Первый и второй тесты стандартно на автомате крутанут ВМГ и выдадут результат.
Третий тест нажимая клавишу “+” и “-” устанавливаем тягу в пределах от 1 до 100%, так же можно ввести значение тяги цифровыми клавишами и нажать “Enter”, тяга постепенно, что бы рывком не нагрузить ВМГ, наберет требуемый шаг тяги или резко его сбросит до требуемого значения. Клавишей “r” вы получите результаты с датчиков. Любая не задействованная клавиша остановит тест и вернет вас в начальное меню.

На этом описание работы со стендом думаю будет достаточным.
Дальше будет расписано как быстро и просто обработать данные полученные со стенда.

Скетч последних изменений

#include <EEPROM2.h> //подключаем библиотеку EEPROM2 
#include <Servo.h> // добавляем библиотеку для работы с сервоприводами

//объявление переменных
//подключаемые разьемы на ардуине
#define servoPin 3 // для дальнейшей работы назовем 3 пин как servoPin
int DATA = 4;  //пин D4 подключаем АЦП тяги
int SCLK = 5;  //пин D5 подключаем АЦП тяги
int PWDN = 6;  //пин D6 подключаем АЦП тяги
#define CurrPin A0  //пин A0 датчик тока
#define VoltPin A1  //пин A1 датчик напряжения

#define servoMinImp 544 // 544 это стандартная длина импульса при котором сервопривод должен принять положение 0°
#define servoMaxImp 2400 // 2400 это эталонная длина импульса при котором сервопривод должен принять положение 180°

//переменные для работы
unsigned long volt; //четырех байтная переменная для хранения в памяти
unsigned long amper; //четырех байтная переменная для хранения в памяти
unsigned long gramm; //четырех байтная переменная для хранения в памяти
float grammT = 0;
int32_t grammM = 0;
float voltT = 0;
int32_t voltM = 0;
float amperT = 0;
int32_t amperM = 0;

int nullFilter = 0;
int CurrentValueOld = 0;
int CurrentValueNew = 0;
int VoltageValueOld = 0;
int VoltageValueNew = 0;

float CurrentValue = 0;  //переменная для расчета тока (с плавающей точкой)
float CurrentValueRes = 0;  //переменная с результатом для расчета тока (с плавающей точкой)
float VoltageValue = 0;  //переменная для расчета напряжения (с плавающей точкой)
int32_t Weight = 0;  //переменная для расчета тяги (32 разряда)
int val; //здесь будет храниться принятый символ
int n; //рабочая переменная
int error = 0; //так же рабочая переменная
int throttle = 0; //переменная газа
String strnumber = "0"; //переменная для временных текствых значаний
int throttleOld = 0; //переменная для хранения временных значений газа

//переменные для нулевых значений
int32_t WeightNull = 0; //нулевое значение по весу (переменная калибруется при включении)
int CountNull = 0;  //нулевое значение по току, данная переменная для однонаправленных датчиков ACS758 (с буквой U) не используется (переменная калибруется при включении)

//эти переменные заполняются пользователем
int ISensor = 200;  //максимальное значение измеряемое датчиком (смотрим даташит по ним)

Servo myServo;

//инициализация
void setup() {
  //инициализация I/O
  pinMode(DATA, INPUT);
  pinMode(SCLK, OUTPUT);
  pinMode(PWDN, OUTPUT);
  digitalWrite(PWDN, HIGH);



  Serial.begin(9600); //скорость порта

  myServo.attach(servoPin, servoMinImp, servoMaxImp);
// устанавливаем пин как вывод управления сервоприводом,
// а также для работы сервопривода непосредственно в диапазоне углов от 0 до 180° задаем мин и макс значения импульсов.
// импульсы с большей или меньшей длиной восприниматься не будут.
// для сервоприводов даже одной партии значения длин импульсов могут отличаться, может быть даже и 584-2440.
// поэкспериментируйте и найдите идеальные длины импульсов конкретно для вашего сервопривода.

  myServo.writeMicroseconds(set_pos(0)); //газ в ноль при включении
}

//чтение вводимой строки из терминала
//нахождение в цыкле пока не будет нажат ENTER или набранно определенное количество символов
//возвращает набранную строку
String readText(int n){
  int i = 0; //временная целая переменная
  String str; //временная строковая переменная
  //собираем заданное количество символов
  while (i<n) {
	while (!(Serial.available())); //ждем символ
        val = Serial.read(); //дождавшись, читаем его
        if (val==13){return str;} //если нажат Enter, прекращаем ввод символов и передаем набранную строку
        Serial.print(char(val)); //показываем нажатую клавишу на терминале
        str += char(val); //формируем строку
        i++; //наращиваем переменную
  }
  return str; //передаем набранную строку заданной длины
}

// Функция устанавливает стик газа
//диапазон желательно указывать от 0 до 100
int set_pos(int pos) {
  int tmp=(servoMaxImp - servoMinImp) /100;
  pos = servoMinImp + tmp * pos;
  return pos;
}

//вывод меню для начала теста
//предоставление выбора типа проводимого теста
void beginTest(){
  //вывод меню выбора
  Serial.println("\n\r============= Select action: =============");
  Serial.println("1 - begin auto test 50, 65, 75, 85, 100%");
  Serial.println("2 - begin auto test 1-100%");
  Serial.println("3 - begin manual test");
  Serial.println("any key - return to console");
  Serial.println("==========================================");
  while (!(Serial.available())); val = Serial.read(); //ожидание выбора
  Serial.print("you select "); Serial.println(char(val)); //сообщаем, что выбрали
  //по результатам выбора начинаем тест или переходим в консоль
  if (val==49){test(1);} //переход на тест с указанием номера теста 1
  if (val==50){test(2);} //переход на тест с указанием номера теста 2
  if (val==51){test(3);} //переход на тест с указанием номера теста 3
  Serial.println("\n\r stop test return to console"); return; //возвращаем в консоль
}

//начало теста
//в зависимости от выбора, запускается тест ВМГ
int test(int n){
  //ждем нажатие подтверждения начала тестов
  Serial.println("\n\r============= Select action: =============");
  Serial.println("8 - begin test");
  Serial.println("any key - stop test and return to console");
  Serial.println("==========================================");
  while (!(Serial.available())); val = Serial.read(); //ожидание выбора
  Serial.print("you select "); Serial.println(char(val)); //сообщаем, что выбрали
  //если подтверждение нажато, начинаем тест, иначе выходим в консоль
  if (val==56){
    Serial.println("\n\r start test"); Serial.println(); //информируем о начале теста

    //первый тест
    if (n==1){
      Serial.println("set throttle 50% 65% 75% 85% 100%"); //выводим сообщение
      if (delayM(200)==1){return 0;} //пауза с возможностью прерывания по нажатию любой клавиши
      Serial.println("\n\r%\tg\tv\tv+f+*\ta\ta+f+*"); //формируем шапку для вывода результатов
      setthrottle(50, 1, 0); if (delayM(1000)==1){return 0;} nullFilter=0; printRez(50); //газ плавно доводим до 50%, ждем, выводим результат
      setthrottle(65, 1, 0); if (delayM(1000)==1){return 0;} nullFilter=0; printRez(65); //газ плавно доводим до 65%, ждем, выводим результат
      setthrottle(75, 1, 0); if (delayM(1000)==1){return 0;} nullFilter=0; printRez(75); //газ плавно доводим до 75%, ждем, выводим результат
      setthrottle(85, 1, 0); if (delayM(1000)==1){return 0;} nullFilter=0; printRez(85); //газ плавно доводим до 85%, ждем, выводим результат
      setthrottle(100, 1, 0); if (delayM(1000)==1){return 0;} nullFilter=0; printRez(100); //газ плавно доводим до 100%, ждем, выводим результат
      setthrottle(0, 0, 1); //газ в ноль
    }

    //второй тест
    if (n==2){
      Serial.println("throttle from 0 to 100%"); //выводим сообщение
      if (delayM(200)==1){return 0;} //пауза с возможностью прерывания по нажатию любой клавиши
      Serial.println("\n\r%\tg\tv\tv+f+*\ta\ta+f+*"); //формируем шапку для вывода результатов
      nullFilter=0; for (n=0; n<100; n++){myServo.writeMicroseconds(set_pos(n)); printRez(n); if (delayM(50)==1){return 0;};} //плавный набот газа от 0% до 100% с выводом результата и возможностью прерывания процесса тестирования
      Serial.println("throttle = 0%"); myServo.writeMicroseconds(set_pos(0)); //заканчиваем тест, газ в 0%
    }

    //третий тест
    if (n==3){
      Serial.println("select throttle percent or press +/- or r for print result"); //выводим сообщение
      error=0; //обнуляем временную переменную
      //создаем петлю
      while (1){
        while (!(Serial.available())); val = Serial.read();  //ждем нажатия клавиши и читаем ее
        //если нажат + (причем любой) наращиваем значение газа, так же присутствует вывод степени набора газа, ограничение на больше 100% и прерывание процесса тестирования
        if (val==61 || val==43){if (error==1){breakTest(); return 0;}else if (throttle<=99){throttle++; setthrottle(throttle, 0, 1);}else{Serial.println("maximal throttle 100%");}}
        //подобно условию выше для знака +, только теперь для знака -
        else if (val==45){if (error==1){breakTest(); return 0;}else if (throttle>=1){throttle--;  setthrottle(throttle, 0, 1);}else{Serial.println("minimal throttle 0%");}}
        //при нажатии Enter, формируется и устанавливается уровень газа с выводом уровня установленного газа
        else if (val==13){Serial.println(); error=0; throttle=strnumber.toInt(); if (throttle>=101){breakTest(); return 0;} setthrottle(throttle, 1, 1); strnumber="0";}
        //тут мы формируем уровень газа путем нажатия цифровых клавиш, формирование прекращается по нажатию клавиши Enter
        else if (val>=48 && val<=57){Serial.print(char(val)); error=1; strnumber += char(val);}
        //если в процессе работы теста нажать калвишу "r", то произойдет вывод данных датчиков
        else if (val==114){Serial.println("\n\r%\tg\tv\tv+f+*\ta\ta+f+*"); nullFilter=0; printRez(throttle);}
        //завершаем тест
        else {breakTest(); return 0;}
      }
    }
  }
  return 0; //если нажата не "8", завершаем тест
}

//установка уровня газа
//при нулевом значении газ обрабатывается моментально, использовать только для снижения значения
//при занчении противоположном нулевому, газ будет набираться плавно
//еще добавлено одно значение для разрешения/запрета вывода результата установленного уровня газа
void setthrottle(int throttle, int x, int y){
  int r = 0; //обнуляем переменную
  //если значение переменной х равно 0, изменение газа происходит моментально, при любом другом, газ будет наращиваться плавно
  if (x==0){
      myServo.writeMicroseconds(set_pos(throttle)); //моментальное изменение газа
    }else if (throttleOld>=throttle){myServo.writeMicroseconds(set_pos(throttle)); //условие для активации плавного набора газа
      }else{
      r = throttle - throttleOld; //просчитываем разность старого и нового значения газа для счетчика
      //плавное изменение газа
      for (n=0; n<r; n++){
        myServo.writeMicroseconds(set_pos(throttleOld+n)); //изменяем уровень газа
        if (delayM(30)==1){return;} //задержка и возможность прекращение теста по нажатию на клавишу
      }
    }
  if (y==1){Serial.print("throttle = "); Serial.print(throttle); Serial.println("%");} //еслт y имеет значение 1, выводим результаты значения газа
  throttleOld=throttle; //формируем старые показания уровня газа
  return; //выход из подпрограммы
}

//функция прерывания теста, выводим сообщение о прерывании, ставим значение уровня газа в 0, обнуляем переменные
void breakTest(){
  Serial.println("throttle = 0%");
  myServo.writeMicroseconds(set_pos(0));
  Serial.println("\n\r break");
  throttle=0; strnumber="0"; throttleOld=0;
  return;
}

//функция задержки с возможностью прерывания
int delayM(int m){
  int k;
  for (k=0; k<m; k++){
    if (!(Serial.available())){}else{k = 1; breakTest(); return k;}
    delay(1);
  }
  k = 0;
  return k;
}

//функция калибровки для уровня газа (еще не готова)
void servaC(){
  Serial.println("\n\r============= Select action: =============");
  Serial.println("1 - 100%");
  Serial.println("0 - 0%");
  Serial.println("any key - return to console");
  Serial.println("==========================================");
  while (1){
  while (!(Serial.available())); val = Serial.read();
  Serial.print("you select "); Serial.println(char(val));
  if (val==49){
    myServo.writeMicroseconds(set_pos(100));
    myServo.attach(servoPin, servoMinImp, servoMaxImp);
    Serial.println("\n\r 100% ok");
  }
  if (val==48){
    myServo.writeMicroseconds(set_pos(0));
    Serial.println("\n\r 0% ok");
  }
  if (val==49 || val==48){}else{return;}
  }
}

//формирование меню калибровок
void beginCalibrate(){
  Serial.println("\n\r============= Select action: =============");
  Serial.println("1 - calibration weight");
  Serial.println("2 - calibration voltage");
  Serial.println("3 - calibration current");
  Serial.println("4 - calibration ESC");
  Serial.println("any key - return to console");
  Serial.println("==========================================");
  while (!(Serial.available())); val = Serial.read();
  Serial.print("you select "); Serial.println(char(val));
  if (val==49){weightC();}
  if (val==50){voltC();}
  if (val==51){amperC();}
  if (val==52){servaC();}
  Serial.println("\n\r stop calibration return to console");
  return;
}

void weightC(){
      Serial.println("put standard and set weight"); //выводим сообщение
      error=0; //обнуляем временную переменную
      //создаем петлю
      while (1){
        while (!(Serial.available())); val = Serial.read();  //ждем нажатия клавиши и читаем ее
        //при нажатии Enter
        if (val==13){Serial.println(); error=0; grammT=strnumber.toInt(); strnumber="0"; grammM=((getSensorValueWeight() - WeightNull)/grammT)*1000000; EEPROM_write(15, grammM); return;}
        //тут мы формируем вес путем нажатия цифровых клавиш, формирование прекращается по нажатию клавиши Enter
        else if (val>=48 && val<=57){Serial.print(char(val)); error=1; strnumber += char(val);}
        //завершаем тест
        else {return;}
      }
}

void voltC(){
      Serial.println("connect standard and set real volt"); //выводим сообщение
      error=0; //обнуляем временную переменную
      //создаем петлю
      while (1){
        while (!(Serial.available())); val = Serial.read();  //ждем нажатия клавиши и читаем ее
        //при нажатии Enter
        if (val==13){Serial.println(); error=0; voltT=strnumber.toInt(); strnumber="0"; voltM=voltT/analogRead(VoltPin)/100*1000000; EEPROM_write(0, voltM); return;}
        //тут мы формируем вес путем нажатия цифровых клавиш, формирование прекращается по нажатию клавиши Enter
        else if (val>=48 && val<=57){Serial.print(char(val)); error=1; strnumber += char(val);}
        //завершаем тест
        else {return;}
      }
}

void amperC(){
      Serial.println("connect standard and set real current"); //выводим сообщение
      error=0; //обнуляем временную переменную
      //создаем петлю
      while (1){
        while (!(Serial.available())); val = Serial.read();  //ждем нажатия клавиши и читаем ее
        //если нажат + (причем любой) наращиваем значение газа, так же присутствует вывод степени набора газа, ограничение на больше 100% и прерывание процесса тестирования
        if (val==61 || val==43){if (error==1){breakTest(); return;}else if (throttle<=99){throttle++; setthrottle(throttle, 0, 1);}else{Serial.println("maximal throttle 100%");}}
        //подобно условию выше для знака +, только теперь для знака -
        else if (val==45){if (error==1){breakTest(); return;}else if (throttle>=1){throttle--;  setthrottle(throttle, 0, 1);}else{Serial.println("minimal throttle 0%");}}
        //при нажатии Enter
        else if (val==13){Serial.println(); error=0; amperT=strnumber.toInt(); strnumber="0"; amperM=amperT/(analogRead(CurrPin)-CountNull)/100*1000000; EEPROM_write(7, amperM); breakTest(); return;}
        //тут мы формируем вес путем нажатия цифровых клавиш, формирование прекращается по нажатию клавиши Enter
        else if (val>=48 && val<=57){Serial.print(char(val)); error=1; strnumber += char(val);}
        //завершаем тест
        else {breakTest(); return;}
      }
}

//чтение данных тяги
int32_t getSensorValueWeight() {
  digitalWrite(SCLK, LOW);  // wake up ADC
  while (digitalRead(DATA) == HIGH);  // wait for data ready, stay in while-loop until LOW
  Weight = shiftIn(DATA, SCLK, MSBFIRST);
  Weight <<= 8;
  Weight |= shiftIn(DATA, SCLK, MSBFIRST);
  Weight <<= 8;
  Weight |= shiftIn(DATA, SCLK, MSBFIRST);
  digitalWrite(SCLK, HIGH);  // enter sleep mode
  Weight = ((signed long) (Weight << 8)) >> 8;  // process as int24_t (two's compliment 24bit)
  return Weight;
}

//результат по тяге
int weightRez(){
  Weight = (getSensorValueWeight() - WeightNull)/grammT;;
  return Weight;
}

//результат по напряжению
float voltageRez(){
  //расчет данных напряжения
  VoltageValue = analogRead(VoltPin);  // считываем значение аналогового входа (напряжение)
  //if (nullFilter==0){VoltageValueOld=VoltageValueNew;}; VoltageValueOld=VoltageValue=filter(VoltageValueOld, VoltageValueNew);
  VoltageValue = VoltageValue*voltT;  ;
  return VoltageValue;
}

//результат по току
float currentRez(){
  //расчет данных тока
  CurrentValue = analogRead(CurrPin); (CurrentValueNew); // считываем значение аналогового входа (ток)
  //if (nullFilter==0){CurrentValueOld=CurrentValueNew;}; CurrentValueOld=CurrentValue=filter(CurrentValueOld, CurrentValueNew); // Serial.println(CurrentValue);
  CurrentValueRes = (CurrentValue-CountNull)*amperT;
  //CurrentValueRes = (CurrentValue-CountNull)*ISensor/512;  //формула расчета тока для двунаправленнх датчиков ACS758
  //CurrentValueRes = CurrentValue*ISensor/1024;  //формула расчета тока для однонаправленных датчиков ACS758
  return CurrentValueRes;
}

//выводим результаты датчиков, переменная v для уровня газа
void printRez(int v){
  //if (visable==0){voltageRez(); currentRez(); return;}
  //выводим результат
  Serial.print(v);
  Serial.print("\t");
  Serial.print(weightRez());
  Serial.print("\t");

  VoltageValueNew=100*voltageRez();
  Serial.print((float)VoltageValueNew/100);
  Serial.print("\t");
  if (nullFilter==0){VoltageValueOld=VoltageValueNew;};
  VoltageValueNew=filter(VoltageValueOld, VoltageValueNew);
  VoltageValue=(float)VoltageValueNew/100;
  (VoltageValue);
  ("\t");
  VoltageValue=VoltageValue*(1-(float)v/10000);
  Serial.print(VoltageValue);
  VoltageValueOld=VoltageValueNew;

  Serial.print("\t");

  CurrentValueNew=100*currentRez();
  Serial.print((float)CurrentValueNew/100);
  Serial.print("\t");
  if (nullFilter==0){CurrentValueOld=CurrentValueNew;};
  CurrentValueNew=filter(CurrentValueOld, CurrentValueNew);
  CurrentValueRes=(float)filter(CurrentValueOld, CurrentValueNew)/100;
  (CurrentValueRes);
  ("\t");
  CurrentValueRes=CurrentValueRes*1.5;
  Serial.println(CurrentValueRes);
  CurrentValueOld=CurrentValueNew;

  Serial.flush();
  nullFilter=1;
}

void nullF(){
  //вывод меню выбора
  Serial.println("\n\r============= Select action: =============");
  Serial.println("1 - null weight");
  Serial.println("2 - null current");
  Serial.println("any key - return to console");
  Serial.println("==========================================");
  while (!(Serial.available())); val = Serial.read(); //ожидание выбора
  Serial.print("you select "); Serial.println(char(val)); //сообщаем, что выбрали
  //по результатам выбора обнуляем датчики
  if (val==49){WeightNull = getSensorValueWeight(); EEPROM_write(23, WeightNull); Serial.println("\n\r zero value of the set");} //обнуляем датчик веса
  if (val==50){CountNull = analogRead(CurrPin); EEPROM_write(31, CountNull); Serial.println("\n\r zero value of the set");} //обнуляем датчик тока
  Serial.println("\n\r return to console"); return; //возвращаем в консоль
}

//фильтр
int filter(int y, int r)
{
        int z = (15 * y + r) >> 4;
        return z;
}

//начало программы
void loop()
{
  EEPROM_read(0, volt); //читаем из пямяти переменную
  EEPROM_read(7, amper); //читаем из пямяти переменную
  EEPROM_read(15, gramm); //читаем из пямяти переменную
  voltT = (float)volt/1000000;
  amperT = (float)amper/1000000; (amper);
  grammT = (float)gramm/1000000;

  EEPROM_read(23, WeightNull);
  EEPROM_read(31, CountNull);

  Serial.println();
  Serial.println("\n\r%\tg\tv\tv+f+*\ta\ta+f+*"); nullFilter=0; printRez(0);
  Serial.println();
  ("Hellow my friend!");
  Serial.println("Please type the commands:");
  Serial.println("test(t), calibration(c), null(n)");
  Serial.println();
  Serial.print(">");
  while (!(Serial.available())); val = Serial.read(); Serial.print("you select "); Serial.println(char(val));
  //String myString = readText(60);
  if (val==116){Serial.println(); beginTest(); error = 0;}
  //if (myString=="setup" || myString=="s"){Serial.println("\n\r setup ok"); error = 0;}
  if (val==99){Serial.println(); beginCalibrate(); error = 0;}
  if (val==110){nullF(); error = 0;}
  if (val==13){Serial.println(); error = 0;}
  if (error==0){error=1;}else{Serial.println("\n\r incorrect command");}
}
sulaex

Как быстро обработать данные полученные со стенда и предоставить их в удобочитаемом виде?

Я пользуюсь терминалом PuTTY. Запускаем тест под номером 2 (плавное измерение с шагом тяги от 0 до 100%) четыре раза подряд.
Верхний левый угол путти выбираем скопировать все данные в клипбоард. Дальше вставляю их в Notepad++.
Нажимаю в нотепад++ ctrl+H, меню замены, меняю три пробела на два пробела, несколько раз, пока все не заменит, затем два пробела меняю на знак табуляции, в меню замены это будет выглядеть как “\t”, не забываем в serch mode выставить extended. Теперь копирую данные первого замера и вставляю в экселевскую табличку шаблон.

данные первого теста в ячейку - A1 (шесть столбцов данных)
второго - Q1
третьего - Z1
четвертого - AI1

Все данные тут же просчитаются и изменят соответственно графики (тяга, напряжение, ток, мощность, эффективность).

как ведите, некоторые данные для подсчета среднего значения можно просто исключить (например четвертый ряд при расчете среднего для эффективности), тем самым повысив качество отображаемой информации

Маленькие графики с левой стороны, это по четыре теста для каждого показания (тяга, напряжение с фильтром, ток с фильтром, мощность расчетная, эффективность расчетная).
Маленькие графики с правой стороны, это средний показатель из четырех тестов (тяга, напряжение с фильтром, ток с фильтром, мощность расчетная, эффективность расчетная).

Большой график в начале таблички, это значение эффективности полученное из средних значений тяги и мощности.

На второй страничке таблицы график с эффективностью и тягой.

sulaex

памятка (требуется для цифрового фильтра Y(n) = (15*Y(n-1) + X(n)) >> 4 )

нашел интересную формулу для побитового сдвига в Excel
=ОТБР(A1/2^B1)
Число в А1, n в В1

проще говоря, можно напрочь все вычисления убить в ардуине и все возложить на Excel 😃

Gapey

осталосЪ раскопать работу с компортом из экселя и написать макрос по вытряхиванию данных из ардумны …
тогда все можно будет делать прямо из экселя …

sulaex
Gapey:

осталосЪ раскопать работу с компортом из экселя и написать макрос по вытряхиванию данных из ардумны …
тогда все можно будет делать прямо из экселя …

strokescribe.com/ru/serial-port-programming.html

sulaex

UP 😃

sulaex:

Здесь имеются некоторые сложности в получении эталонного значения по току. Если вы имеете какие либо предложения для решения данной проблемы, прошу высказываться. Пока более простого решения нет, в программе все таки имеется возможность калибровки. Для этого в разрыв питания регуля подключаем амперметр. Собираем ВМГ как для теста и нагружаем датчик тока путем раскрутки ВМГ. В режиме ввода эталонного значения тока можно нажимать клавиши “+” и “-” для задействования ВМГ в качестве нагрузки. Плюсом будем увеличивать обороты, минусом уменьшать. Но не забываем перед этими действиями откалибровать регулятор.

пока едет более чувствительный датчик тока, собрал схемку для настройки оного

руководствовался данной статьей

как видите собрал вторую схему, но в нашем варианте можно обойтись более простой
вторая схема проверена лично и работает на ура, но не увеличивайте нагрузку выше 5-7 ампер

ARXITEKTOR

Вот пришла в голову идея а что если совместно с андурино использовать среду
LabVIEW там и с андуриной работать можно и математику возложить на комп.

Nesenin

дык используйте. все поделки так и делаю arduino + labview. отправляю команды. читаю данные. хошь графики строй хошь 3D модели. можно интерполяцию прикрутить. запись в базу\чтение сравнение. ммм

по поводу серво сигнала на arduino. он не аппаратный. в смысле не по прерываниям от таймера работает. от того может дергать туда-сюда. для данной темы наверно не сильно актуально, но вообще есть средство arduiniana.org/libraries/pwmservo/ мож кому пригодится.

1 month later
Nesenin

sulaex, возможно у вас не точна схема передачи усилия на тензодатчик. на вид присутствует “рычаг”, см. ось двигателя имеет небольшой вылет над ножкой. я тут как рас подобную схему о 2х опорах ваяю. и заметил что даже небольшого смещения точки приложения силы и точки опоры, хватает на возникновение ошибки. а у вас еще 1 опора усилие оказывает.
может все ж сделать площадку на самой конструкции датчика и туда уже движок крепить? правда не ясно как вибрация повлияют.

Nesenin

фух! получил первый результат

эт без фильтров. мышкой крутил уровень сервосигнала. внизу на графике видно как он рос.
поздно прочел про точность датчика тока. купил ACS758LCB-050 B надо было с U(униполярный)
выход с датчика тока сначала без обвеса подключил
см

были помехи. сейчас ок.
аналогично надо на выход с потенциометра прикрутить кондер. чтоб показания напряжения батареи не скакали. глядишь ничего программно фильтровать не придется.

Nesenin

список покупок тут rcopen.com/forum/f123/topic345296/22
вот так выглядит мой стенд

сейчас на проводе, а эксплуатироваться будет с Bluetooth
благо windows подхватывает за пару минут и в ПО никакой разницы в работе, кроме как необходимость ввести пароль в начале. так что реально можно хоть в другую комнату унести. все ради безопасности.

по поводу ПО. под arduino я свой код наваял на основе нарытого в сети китайского кода под модуль АЦП.
вот архив yadi.sk/d/f1CwtYiKHuQwb
папку PWMServo надо в libraries добавить в месте где среда arduino стоит. тогда будет пахать с аппаратным серво сигналом (см. выше писал).
ноги на которые цепляются выводы с модуля АЦП датчика веса устанавливаются в файле HX711.h коэффициент для тензодатчика в файле HX711.cpp
моё творчество выглядит так

#include “HX711.h”
#include <PWMServo.h> //arduiniana.org/libraries/pwmservo/ arduiniana.org/PWMServo/PWMServo_v2.zip
int Weight = 0;
int analogVolt = 2; //pin для измерения напряжения аккума
int analogTok = 3; //pin для чтения датчика тока
int Volt = 0;
int Tok = 0;
int suma = 0;
int serva = 0;

unsigned long previousMillis = 0; // храним время
unsigned long currentMillis = 0;
long interval = 400;
PWMServo servo1; //объявляем

void setup()
{
Init_Hx711(); //инициализация датчика веса

Serial.begin(115200);

servo1.attach(SERVO_PIN_A); //выход сервосигнала 9 pin

delay(3000);
Get_Maopi(); //
}

void loop()
{
Weight = Get_Weight(); //чтение веса
Volt = analogRead(analogVolt); //чтение напряжения
Tok = analogRead(analogTok); //чтение тока

Serial.print(Weight); //вывод в порт
Serial.print(" “);
Serial.print(Volt); //
Serial.print(” “);
Serial.print(Tok); //
Serial.print(” ");
Serial.println(serva); //

if(Serial.available() > 2)
{
byte a,b,c; // принимаем байты и разбиваем их
a = Serial.read(); //значение сервосигнала
b = Serial.read(); // добавочное число (20)
c = Serial.read(); // контрольное значение для проверки

suma = a + b-3;
if(suma == c && suma != 0)
{servo1.write(a);
serva =a;
previousMillis = millis();
}
}

currentMillis = millis();

if( currentMillis - previousMillis > interval)
{
servo1.write(0);
serva = 0;
}

delay(20);
}

тут у нас чтение команд с компа и отправка данных. из плюшек это избыточные данные с компа и контрольная сумма. это надо для того чтоб проверять целостность данных и левые игнорировать. потом есть авто выключение моторки в случаях если нет поступления “правильных” команд больше 400мс(для беспроводного соединения будет актуально). все ради безопасности.

ПО для компа ща ваяю в labview. как че годное сделаю, выложу.
пока зянят борьбой с шумом в показаниях напряжения. кондеры ставлю. чет не шибко помогает. потом есть одиночные скачки в показаниях датчика веса. но эт легко отсеивается. думаю будет некоторая выборка набираться. потом фильтроваться. потом всякие графики строиться и экспорт\импорт данных будет.
PS шаг измерений тока почти 100мА это печаль. потом других датчиков докуплю. буду менять в зависимости от амплитуды с соответствующим ростом точности см.rcopen.com/forum/f123/topic345296/19

Gapey
Nesenin:

шаг измерений тока почти 100мА это печаль.

на более правильном 50U будет 50 ма , что впринцепе достаточно для больших моторов но маловато для мелких …
можно использовать датчики еще на меньший ток а можно использовать внешний АЦП например ADS1100 , тогда достаточно будет любого ACS758 , какой есть под руками и на все случаи …

SergDoc

Только я не пойму, а зачем рычаг? балку(датчик силы, тензодатчик - да как угодно) одним концом понятно - к станине, а прямо на второй конец балки крепление мотора?

Dimus

Тоже с шумами по напряжению борюсь, аппаратный фильтр не очень помогает, код тоже свой, оболочка в разработке, зато обмерял пачку винтов, очень интересные данные.
Мотор креплю прям на датчик.
На графиках обрыл линий, это отсечка по весу, датчик пока на 1кг, хотя весами тянул за мотор, до 4кг меряет.

Nesenin
Gapey:

можно использовать датчики еще на меньший ток а можно использовать внешний АЦП например ADS1100

да, очень желательно использовать внешний АЦП на датчик тока. я тут по показаниям мультиметра (не самого дешевого) подобрал коэффициент для своего датчика . получилось 0,1237934195959(ампер на единицу). очень печально наблюдать как например при 10мА (регулятор столько ест при выключенном моторе) у меня показания за счет шума скачут 0\0.123…А
надо решать вопрос.

SergDoc:

Только я не пойму, а зачем рычаг? балку(датчик силы, тензодатчик - да как угодно) одним концом понятно - к станине, а прямо на второй конец балки крепление мотора?

я думал, но мысль о вибрациях, напрямую трясущие мост меня пугают. сейчас там винт концом давит (точно под валом). микровибрация просто трет подложенный кусочек алюминия, а не ломает стенки выреза в мосте.

может потом сделаю.

Dimus:

Тоже с шумами по напряжению борюсь, аппаратный фильтр не очень помогает

а я кажись поборол

потребовалось аж 100мкФ прикрутить (потенциометр 25кОм настроен на 4S, подключено после датчика тока перед регулятором). по сути маленькие пики это стандартный шум, который всегда присутствует и составляет сотые доли В и меньше.
такие дела. работаю дальше.

Gapey
Nesenin:

микровибрация просто трет подложенный кусочек алюминия,

можно резиновый демпфер поставить … и конструкцию лучше вертикально ставить , чтобы спереди и сзади винта ничего не было …

Nesenin

вот тут будут жить файлы yadi.sk/d/eEj0iObbHuS9Z
собственно добавил исходник для среды LabVIEW2013(+модуль visa нужны установленные на ПК для запуска) exe’шник пока не делаю.смысла пока нет.
вот как выглядит тест и работа на сей момент (включите fullHD)

youtu.be/uBhMO2FbR2E

рекомендую всеж среду разработки поставить. там куча фильтров и примеров. программировать очень просто. запуск из среды без компиляции(мгновенно). то есть меняешь работу кода “на ходу”.
PS вертикальное расположение мотора на мосту датчика веса, как мне кажется, добавит шумов - будет качаться туда\сюда. но конечно попробую со временем. для меня главное данные как можно более похожие на правду. буду тестировать и улучшать стенд\ПО.

Nesenin

начал работать уже над третьей вкладкой “анализ”. хочу поделиться результатами экспериментов. как и ожидалось показания ток а сильнее всего вносят шум. и чем меньше значение тока тем, естественно ,больше хрени на графике гр\Вт.
я сначала делал тесты с max значениями тока до 7.5 А и малость озадачился вопросом “насколько сильно сглаживать замеры что бы конечные результаты были ближе к правде?”
если сглаживать слабо, получается такой волнистый график, который малость пугает своей кривостью. если сглаживать сильно, то уже вполне себе выпуклый плавненький, но на сколько он верен?
взял прогнал мотор с max 14А. имеем:

тут первый график это без программных фильтров. только выборка (выборка это когда из нескольких значений для заданного сервосигнала берется последнее значение с той мыслью что первые это еще не установившиеся обороты и значения; у меня шаг 100мс 4-5 значений успевают прийти см. код)
второй график это тож самое + проведено довольно сильное сглаживания данных по току, чтоб пофиксить начало .
ну и последний это уже сам график эффективности сглажен.
отдельно отмечу “уход в минус”. вообще для сервосигналов 0-4 и 176-180 обороты двигателя регулятор уже не регулирует то есть они в первом случае =0 в последнем на max . а фильтры стремятся эти участки ровных прямых привести в соответствие с общим наклоном. получается уходят значения в минус и в итоге такая вот хрень. не считаю нужным с этим что то делать. будем игнорить значения на концах сами.

так вот, на основании этого теста, буду считать что график, все-таки, должен быть плавным с резким взлетом в начале и плавным спуском вниз дальше. насколько это так, вопрос открыт. я встречал графики в этой теме rcopen.com/forum/f123/topic218743 в которых линии явно страдают от сильного влияния шумов в начале. там аж впадины встречаются в месте где должен быть максимум! ну и общее “волнение” по линии. мне кажется это все ошибки.

далее приведу реальные замеры на моем стенде с сильным сглаживанием значений тока и не сильным других (значения напряжения практически никак не влияют хоть сглаживай хоть нет). опять же значения на концах игнорим

моторка www.rctimer.com/index.php?gOo=goods_details.dwt&go…
винты
hobbyking.com/…/__25814__8045_SF_Props_2pc_CW_2_pc…
hobbyking.com/…/__25821__10x4_5_SF_Props_2pc_Stand…
www.rctimer.com/index.php?gOo=goods_details.dwt&go…

вопрос по сохраняемым данным для базы знаний. то что первоначальные значения со стенда сохраняются эт понятно. но они потом индивидуально должны обрабатываться для получения сносных графиков. загрузить их все разом и обработать единым фильтром не получится.
я вот думаю еще пустить в оборот данные вышеприведенного графика. то есть это точки[x,y] с значениями гр\вт и гр. уже сглаженные. в справочной части будет указываться мотор, винт, max ток ну и возможно среднее напряжение.
у меня тут кстати не одинаковый заряд на батарее 2s был. а это тоже важно. при разряде батареи график меняется.

кстати тот самый тест с ростом до 14А (который как бы ближе к истине) был получен так

я тут вижу высокий уровень “подобия”. буду считать что на 2S то же достойны доверия, хоть и подверглись сильной обработке.
PS исходник под LabVIEW все время свежий кидаю. мож кто приложит руку с пользой.

Nesenin

хм. чего то данные по напряжению не оч. точно меряется. при подключении заряженного аккума до 8.3В с проверкой по мультиметру коэффициент пришлось повысить (получается реальное потребление выше ранее намеренного), а последующие подключение 4S потребовало понижение коэффициента! откуда такая не линейность? там ошибка до 150мВ как то многовато.
я тут подзарядил акум 2S чтоб прогнать тесты с более близкими значениями напряжения для 3х винтов. и вот что получилось

сразу видно как понизилась эффективность. частично это из за разных напряжений (7.3В vs 8.3В) а частично изза более точной подгонки коэффициента для замера напряжения . потом винт 1245, судя по диким показаниям на графиках(тут не видно все сильно обработано) вообще срывал синхронизацию. по сему он едва превысил max тягу 10ти дюймового.
о чем это все говорит? что пипец, а не показатели эффективности ВМГ
в зависимости от заряда батареи графики плывут и оч. сильно.
надо будет специально цикл замеров провести с разрядом скажем от 8.4 до 6.6В
подозреваю что на каком то уровне будет наблюдаться максимальный КПД, а при смещении в ± по напряжению будет падать. или вообще максимум будет не в этом диапазоне.

представляете себе картину, на одном винте максимальный КПД чуть выше рабочего диапазона напряжений . при максимальном заряде показания лучше чем в сравнении с другим. но у другого скажем максимум КПД в этом самом диапазоне напряжений. и пока все это падает получается на втором дольше висит мультиротор. мм?

встает вопрос: " а как судить то об эффективности и сравнивать ВМГ?"
у нас и стенды\настройки разные и шумы и не линейности. + в зависимости от напряжения графики плывут туда сюда. вверху у меня за 13гр\вт зашкаливает, а теперь ниже 12.

ну и вот допустим у нас rcopen.com/forum/f123/topic218743 тесты всякие. кто то чет намерил из того что у него есть. привел графики гр\вт на грамм. у другого такие же графики для своего моторки винта. и мы должны сравнить и решить что лучше…и деньги потратить в пользу каких то людей.
а оно как получается? считали считали. поставили лучшее по результатом каких то выборочных тестов, а оно не то что б прям супер.
походу надо более детальные исследования проводить. более точные инструменты использовать.
а какие данные в базу добавлять чтоб что то реально можно сравнить по данным полученным от разных людей,я вообще хз. и как теперь доверять чужим тестам, проведенным по нескольким точкам? беда

короче я добавлю 3 ось и прогоню весь диапазон рабочих напряжений. посмотрим что за поверхность у нас получится и где там будет экстремум. будет весело. жаль БП регулируемого мощного у меня нет нормального. это сильно бы ускорило процесс.