логин: 
<< предыдущая заметкаследующая заметка >>
03 мая 2017
Подскажите про алгоритм

Сижу, занимаюсь ерундой — пришла из Китая электрическая личинка дверного замка, пытаюсь с помощью чипа ESP8266 обучить ее грамотно открывать замок:

Научил ESP8266 рисовать вебстраничку с эпюрами — измеряет, собственно, ток мотора во время хода:

Выше на фотке два прогона мотора туда и обратно, сверху — на 9 вольт (медленнее ехал), снизу на 12 вольт. В момент старта мотора, соответственно идет всплеск мощности, а в конце пути мотор упирается и застревает, и там тоже зашкал. А вот по пути в каждую из сторон (не важно, закрывается замок или открывается) должны быть два отчетливых пика, потому что замок на два оборота, и мотору приходится в эти моменты двигать стержни, что тоже для него работа про сравнению с прогулочным холостым ходом. Я обозначил эти пики стрелочками.

Задача: как программно определять эти пики? Делать это надо в момент их появления (на крайняк — в момент окончания) — чтобы уметь останавливать мотор на одном обороте. Время их появления может немного различаться — в зависимости от плавающего напряжения питания и конструкции замка. В конце концов, поворотов может быть три в каком-то другом замке. Ну и величина их тоже сильно плавающая штука — зависит от сопротивления проводов и запыленности/разработанности замка. Например, через месяц работы параметры могут поплыть.

Есть идея, каким алгоритмом находить эти пики?

Идея ставить константы мне не нравится. Идея время от времени проводить тестовый прогон замка с автоматической юстировкой и записью констант тоже не кажется умной. Что посоветуете?

PS: Кому интересно, скетч для ESP8266 с графиками:

показать код

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

#include <EEPROM.h>

#include <Ticker.h>

const char* ssid = "lleo-home-wifi";
const char* password = "gfhjkm";
MDNSResponder mdns;

ESP8266WebServer server(80);

#define led  2
#define led2 16
#define MOTO1 4
#define MOTO2 5
#define HALL 13
#define INP0 A0

#define AnalogReadBuffer_MAX 500
int AnalogReadBuffer_count=0;
unsigned char AnalogReadBuffer[AnalogReadBuffer_MAX];
uint8_t A0_log=0;
uint8_t timer_blink=0; // Таймер http://www.pvsm.ru/arduino/111541

  Ticker blinker;
  void timerIsr() { if(!A0_log) return;
    digitalWrite(led,(timer_blink++)&1);
    if(AnalogReadBuffer_count<AnalogReadBuffer_MAX) AnalogReadBuffer[AnalogReadBuffer_count++]=analogRead(A0)/4;
  }

int i,pc=0;
char motor_go=0;

// DATA in EEPROM

char motor_pos=1; // последняя позиция мотора
unsigned int Tugo200=250; // порог поворота
unsigned int Tugo500=500; // порог упора
unsigned int Skip500=200; // интервал оценки
unsigned int DelayOtPoroga=200; // задержка от порога
unsigned int DelayOtStarta=200; // задержка от старта
unsigned char MotorSide=1; // прямая-обратная установка в дверь

unsigned int eeprom_count=0;
unsigned int eeprom_Tugo200=2; // 2б
unsigned int eeprom_Tugo500=4; // 2б
unsigned int eeprom_Skip500=6; //2,
unsigned int eeprom_DelayOtPoroga=8; //2,
unsigned int eeprom_DelayOtStarta=10; //2,
unsigned int eeprom_MotorSide=12; // 1
unsigned int eeprom_motor_pos=13; // 1

void motor(uint8_t x){
  if(!x) { digitalWrite(MOTO1,0); digitalWrite(MOTO2,0); motor_go=0; return; }
  if(x==1) { if(motor_pos>1) return; digitalWrite(MOTO1,1);digitalWrite(MOTO2,0); }
  else { if(motor_pos==0) return; digitalWrite(MOTO1,0);digitalWrite(MOTO2,1); }
  motor_go=(MotorSide==1)?x:-x;
  delay(DelayOtStarta);
}

void handleRoot() {
  digitalWrite(led,1);
  String s="<!DOCTYPE html><html><head><title>LEOPOLD</title>";
s+="<style>RINPUT {padding:20px;}\n#er {color:red;}</style>";
s+="<script type='text/javascript' src='http://home.lleo.me/projects/arduino/rg.js'></script>";
s+="<script>";
s+="function clean(id){ if(idd(id)) setTimeout(\"var s=idd('\"+id+\"');if(s)s.parentNode.removeChild(s);\",40); }";
s+="function idd(id){ return typeof(document.getElementById(id))=='undefined'?false:document.getElementById(id); }";
s+="function idie(s){ var e=idd('buka'); e.innerHTML=e.innerHTML+s; }";

s+="var RGON=0; function RG(a){ if(a===false||RGON==0) return RGON=0;";
s+="    if(a.length) { for(var i in a) { var c=a[i]*8+1; if(c>=512) c=511; line.originalData[0].unshift(c); line.originalData[0].pop(); } RGraph.SVG.redraw(); }";
s+="    setTimeout(\"AJAX('getlog?')\",200);";
s+="}";

s+="function RG_init(){";
s+="line=new RGraph.SVG.Line({id:'rg',data: RGraph.SVG.arrayFill({array:[],value:0,length:300}),options: {";
s+="gutterLeft:40,yaxisMax:512,yaxisMin:0,backgroundGridVlinesCount:30,filled:true,colors:['#c00'],linewidth:3,filledColors:['rgba(255,0,0,0.25)'],shadow:true}}).draw();";
s+="}";

s+="function AJAX(x){";
s+="    var request=new XMLHttpRequest(); request.onreadystatechange=function(){ if(this.readyState==4 && this.status==200 && this.responseText!=null)";
s+="       try{eval(this.responseText);}catch(e){alert('Error Ajax');}";
s+="    }; request.open('GET',x+(/\\&/.test(x)?'&':/\\?/.test(x)?'':'?')+'rand='+Math.random(),true); request.send(null);";
s+="}";

s+="var m=[0,1,2,3,4,5,10,12,13,14,15,16],i; for(i in m) document.write((\"<input type=button value='PIN?n=#&on=1' onclick='bu(this)'> <input type=button value='PIN?n=#&on=0' onclick='bu(this)'>\").replace(/#/g,m[i]));";
s+="function bu(e) { AJAX(e.value); }";

s+="</script>";

s+="</head><body onload='RG_init();'>";

s+="<h1>LEOPOLD</h1>";

s+="<center><div style='width:95%;height:400px' id='rg'></div></center>";
s+="<div><input type=button value='A0_ON' onclick='bu(this)'>   <input type=button value='A0_OFF' onclick='RGON=0;bu(this)'></div>";

s+="<p><input type=button value='STOP' onclick='bu(this)'>   <p><input type=button value='MOTOL' onclick='bu(this)'>   <input type=button value='MOTOR' onclick='bu(this)'>";

s+="<div id='er'></div><div id='buka'></div>";
s+="</body></html>";

  server.send(200,"text/html",s);
  digitalWrite(led,0);
}

void handleNotFound(){
  String s = "File Not Found\n\n";
  s += "URI: ";
  s += server.uri();
  s += "\nMethod: ";
  s += (server.method() == HTTP_GET)?"GET":"POST";
  s += "\nArguments: ";
  s += server.args();
  s += "\n";
  for (uint8_t i=0; i<server.args(); i++){ s += " " + server.argName(i) + ": " + server.arg(i) + "\n"; }
  server.send(404, "text/plain", s);
  digitalWrite(led, 0);
}

void setup(void){

  pinMode(led, OUTPUT); digitalWrite(led, 0);
  pinMode(led2, OUTPUT); digitalWrite(led2, 0);

  pinMode(MOTO1,OUTPUT); digitalWrite(MOTO1,0);
  pinMode(MOTO2,OUTPUT); digitalWrite(MOTO2,0);

  pinMode(HALL,INPUT_PULLUP);

  pinMode(INP0,INPUT);

  Serial.begin(115200);

  Serial.println("RESET");

  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while(WiFi.status() != WL_CONNECTED) {
    digitalWrite(led,pc); pc=(!pc)&&1; digitalWrite(led2,pc); delay(200);
    Serial.print(".");
  }
  digitalWrite(led,0);
  digitalWrite(led2,1);

  Serial.println("");
  Serial.print("Server ESP #"); Serial.println(ESP.getChipId());
  Serial.print("Connected to "); Serial.println(ssid);
  Serial.print("IP address: "); Serial.println(WiFi.localIP());

  if(mdns.begin("esp8266", WiFi.localIP())) {
    Serial.println("MDNS responder started");
  }

 server.on("/", handleRoot);

 server.on("/ping",[](){ server.send(200,"text/plain","OK");});

 server.on("/MOTOL",[](){ motor(1); server.send(200,"text/plain","idie('MOTOL<br>')"); Serial.println("MOTOR 1"); });
 server.on("/MOTOR",[](){ motor(-1); server.send(200,"text/plain","idie('MOTOFF<br>')"); Serial.println("MOTOR -1"); });
 server.on("/STOP",[](){ motor(0); server.send(200,"text/plain","idie('STOP<br>')"); Serial.println("MOTOR OFF");});

 server.on("/A0_ON",[](){ A0_log=1; AnalogReadBuffer_count=0;

for(int c=0;c<10;c++) AnalogReadBuffer[AnalogReadBuffer_count++]=10;

 server.send(200,"text/plain","idie('A0_ON<br>'); RGON=1;RG([]);"); Serial.println("A0_ON"); });
 server.on("/A0_OFF",[](){ A0_log=0; digitalWrite(led,0); AnalogReadBuffer_count=0; server.send(200,"text/plain","idie('A0_OFF<br>'); RGON=0;"); Serial.println("A0_OFF"); });

 server.on("/getlog",[](){ if(!A0_log && AnalogReadBuffer_count) return server.send(200,"text/plain","RG(false);");
      String s=""; for(i=0;i<AnalogReadBuffer_count;i++) s+=(i?",":"")+String(AnalogReadBuffer[i],DEC);
      AnalogReadBuffer_count=0;
      server.send(200,"text/plain","RG(["+s+"])");
 });

 server.on("/getset",[](){
   String s="clean('sform');idie(\"<form id='sform' action='/set'>";
   s+="<br>Max-do: <input name=Tugo200 value='"+String(Tugo200,DEC)+"'>";
   s+="<br>Max-end: <input name=Tugo500 value='"+String(Tugo500,DEC)+"'>";
   s+="<br>Skip: <input name=Skip500 value='"+String(Skip500,DEC)+"'>";
   s+="<br>Delay-do: <input name=DelayOtPoroga value='"+String(DelayOtPoroga,DEC)+"'>";
   s+="<br>Delay-start: <input name=DelayOtStarta value='"+String(DelayOtStarta,DEC)+"'>";
   s+="<br>Motor-side: <input name=MotorSide value='"+String(MotorSide,DEC)+"'>";
   s+="<p><input type=submit value='SAVE'></form>\");";
   server.send(200,"text/plain",s); Serial.println("OK");
  });

 server.on("/set",[](){
   i=server.arg("Tugo200").toInt(); if(i<50||i>400) { server.send(200,"text/plain","er('Error Max-do (50..400)')"); return; } Tugo200=i; // EEprom
   i=server.arg("Tugo500").toInt(); if(i<50||i>800) { server.send(200,"text/plain","er('Error Max-end (50..800)')"); return; } Tugo500=i; // EEprom
   i=server.arg("Skip500").toInt(); if(i<1||i>5000) { server.send(200,"text/plain","er('Error Skip (1..5000)')"); return; } Skip500=i; // EEprom
   i=server.arg("DelayOtPoroga").toInt(); if(i<50||i>800) { server.send(200,"text/plain","er('Error Delay-do (50..800)')"); return; } DelayOtPoroga=i; // EEprom
   i=server.arg("DelayOtStarta").toInt(); if(i<50||i>800) { server.send(200,"text/plain","er('Error Max do (50..800)')"); return; } DelayOtStarta=i; // EEprom
   i=server.arg("MotorSide").toInt(); if(i!=1&&i!=0) { server.send(200,"text/plain","er('Error Motor-side (0 or 1)')"); return; } MotorSide=i; // EEprom
   server.send(200,"text/plain","clean('sform')");
 });

 server.on("/PIN",[](){
    char i=server.arg("n").toInt(),on=server.arg("on").toInt();
    pinMode(i,OUTPUT); digitalWrite(i,on);
    String s="Pin #"+String(MotorSide,DEC)+" "+(on?"ON":"OFF");
    server.send(200,"text/plain","idie('"+s+"<br>')"); Serial.println(s);
 });

 // 


  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");

  blinker.attach(0.05,timerIsr);
  digitalWrite(led,0);
}


int top=0;
int an=0;

void loop(void){
  server.handleClient();

  /*
   if(motor_go) {
        an=analogRead(A0);

    if(an>Tugo200) {
      if(an<Tugo500) {
        if(motor_go==1) motor_pos++; else motor_pos--;
        delay(DelayOtPoroga);
      } else {
        if(motor_go==1) motor_pos=2; else motor_pos=0;
      }
      motor(0);
     }

    if(top++ > Skip500) { top=0;
    pc=(!pc)&&1; digitalWrite(led,pc);
    Serial.print("inp=");
    Serial.println(analogRead(A0));
    }


  } else {
    if(digitalRead(HALL)==0) motor(0);
  }
  */

}
<< предыдущая заметка следующая заметка >>
пожаловаться на эту публикацию администрации портала
архив понравившихся мне ссылок
Оставить комментарий
Mac Safari Chrome
 Нидерланды
0
0
tucher (#6772593)
Дифференцировать сперва, а потом на графике производной уже искать пики, сравнивая с порогом.
Windows Firefox
 Москва
6
0
Katsuk
А если пылинка однажды попадет или подшипник шевельнется?
Только датчик положения, только хардкор!
Windows Safari Chrome
 Monroe
1
0
pink_panther__ (#6754502)
Фильтровать высокие частоты "на лету". Полагаю, в радио эта тема хорошо развита. На коленке если, то можно что-то типа скользящей медианы дифференцировать, ширину окна задать по характерным размерам "пылинок". Как вариант - повторять дважды: упёрлись - встали - попробовали ещё раз - если встали второй раз то всё, закрыто, а пылинки второй раз может не быть. (Могу ошибаться - не имея доступ поиграться, сложно выдать чёткий рецепт.)
Windows Safari Chrome
 Москва
0
0
Ilia
Численно дифференцировать зашумлённый сигнал!? Крайне плохая идея.
Mac Safari Chrome
 Нидерланды
0
0
tucher (#6772593)
Да, конечно, согласен. Если сигнал может быть достаточно зашумлённым, сгладить перед дифференцированием стоит.
Linux Safari Chrome
 Санкт-Петербург
0
0
ВладБес (#6691557)
А ссылку на замок можно? Спасибо :)
Windows Safari Chrome
 Москва
1
0
alex-mah
Три заказа, и теперь замок не доступен :-)
Некий L***d K. был вторым.
А цилиндр на нем можно поменять, и если нет, сколько обещают комбинаций ключа?
Linux Ubuntu Safari Chrome
 Ashburn
3
0
Лжедмитрий Малобуков (#6735759)
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Спасибо, похоже на то, что нужно! Буду завтра смотреть.
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Блин, а что это за язык? Как его перевести в человеческий? :)
Mac Safari
 Новосибирск
1
0
red_dragon
Написано же там. Псевдокод. Ниже, там же, есть реализации на куче разных языков.
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Cделал модельку на PHP:


function fmean($m) { $N=sizeof($m); $mu=0; for($i=0;$i<$N;$i++) $mu+=$m[$i]; return $mu/sizeof($m); }
function fstd($m) {
$N=sizeof($m);
$mu=fmean($m);
$sum=0; for($i=0;$i<$N;$i++) $sum+=($m[$i]-$mu)*($m[$i]-$mu);
$sum=$sum/$N;
return sqrt($sum);
}
function fm($m,$from,$to) { $X=array(); for($i=$from-1;$i<$to;$i++) $X[]=$m[$i]; return $X; }

$y=array(393,417,417,417,417,433,433,409,417,401,417,433,497,393,433,409,393,401,441,505,185,89,89,25,33,25,9,9,49,25,33,41,9,9,25,25,33,33,25,41,33,25,33,33,17,25,33,17,33.................);

// Settings
$lag=10; // lag 5 for the smoothing functions
$threshold=3.5; // 3.5 standard deviations for signal
$influence=0.5; // between 0 and 1, where 1 is normal influence, 0.5 is half

$N=sizeof($y);

$signals=array(); for($i=0;$i<$N;$i++) $signals[$i]=10; // Initialise signal results
$filteredY=fm($y,1,$lag); // Initialise filtered series
$avgFilter=array(); // Initialise average filter
$stdFilter=array(); // Initialise std. filter
$avgFilter[$lag]=fmean($filteredY); // Initialise first value
$stdFilter[$lag]=fstd($filteredY); // Initialise first value

for($i=$lag+1;$i<$N;$i++) {
if(abs($y[$i]-$avgFilter[$i-1]) > $threshold*$stdFilter[$i-1]) {
if($y[$i] > $avgFilter[$i-1]) $signals[$i]=150; // Positive signal
else $signals[$i]=50; // Negative signal
// Make influence lower
$filteredY[$i]=$influence*$y[$i] + (1-$influence)*$filteredY[$i-1];
} else {
$signals[$i]=100; // No signal
$filteredY[$i]=$y[$i];
}
// Adjust the filters
$p=fm($filteredY,$i-$lag,$i);
$avgFilter[$i]=fmean($p);
$stdFilter[$i]=fstd($p);
}


Как играться с параметрами пока не понял, но при lag=10 вместо 5 всё получилось на тестовых данных:



Linux Firefox
 Boulder
2
0
Михаил (#1684620)
Идея алгоритма правильная в том, что пик определяется по превышению уровня шума, но реализация плохая.

Во-первых, внутри пика параметры шума обновлять не нужно вообще.

Во-вторых, скользящее среднее и дисперсию лучше обновлять с каждым (не-пиковым) отсчётом, а не пересчитывать заново. Это заодно позволит сохранять их значения между прогонами. (Ну и, по-хорошему, в дисперсии надо делить на N − 1, а не на N.)

Но судя по последней картинке в заметке, отношение сигнал/шум (особенно для первого пика) весьма фиговое, так что я тоже за непосредственный индикатор положения вместо этих плясок с бубном.
Linux Firefox
 Mt Laurel
2
0
Михаил (#1684620)
И ещё (забыл сразу написать) — обязательно нужен гистерезис, т. е. порог для перехода фон → пик должен быть выше, чем для перехода пик → фон. А то полезет всякая колбасня (как на втором пике правой картинки).
Windows Firefox
 Москва
5
0
Katsuk
Только по датчику абсолютного положения. Это не мигалка на ёлке, это замок от квартиры, куда можно деньги положить.
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Датчик мне лень, я его снял. Хочу по мотору.
Windows Firefox
 Москва
2
0
Katsuk
Не получится, забей. Только крайние состояния, когда ток отличается на порядок
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
У меня среди читателей необычайно много грамотных математиков и людей, опытных в обработке сигналов. Ты бы их послушал, она там выше дельные советы дают. Задача простая, нерешаемой не является. При этом - очень частая. Тебе пригодится.
Windows Safari Chrome
 Домодедово
4
0
id
У тебя среди читателей есть не только грамотные математики, но и люди, опытные в управлении электроприводами. Мне так кажется, вторые для решения задачи управления электроприводом подошли бы чуть больше. И это я не про себя :)

Концевик. И подстраховка концевика: таймаут и датчик сверхтока.
А вот над конструкцией концевика - можно подумать.
Windows Safari Chrome
 Красноярск
1
0
balal
Тогда контроль времени движения добавить, для дополнительной защиты... А в замке велика вероятность внештатных ситуаций, мало ли где что подклинит! Как это математически посчитать?
...Так Вы его ещё и на стенде без непосредственно замка гоняете, без усилия на перемещения задвижки?!
Mac Safari
 Ottawa
3
0
VadimPanov (#6685720)
Леонид, как эксперимент твой метод вполне интересен, но в реальной жизни для надёжности надо ставить датчик. Сам же программист, знаешь, что костыли ни к чему хорошему не приводят. Всплески будут говорить о том, что привод делает что-то с напрягом, а не о том, где реально находится личинка. Рано или поздно что-то проглючит и метод не сработает.
Windows Safari Chrome
 Москва
3
0
chmyrnovich
Ты не сможешь определить пики в момент их появления, а анализировать готовый график - тебе уже подсказали - строй производную и ищи нуль.
Mac Safari Chrome
 Санкт-Петербург
2
0
shabanovd (#6763552)
Остановится на самом пике невозможно, так как его не детектировать пока он не будет пройден. Максимум что можно, так это "собирать" максимум и как только "текущие" значение окажется ниже этого максимума на некий порог то порог пройден.
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Это мне тоже годится - замок должен все-таки сделать оборот прежде чем мотор надо остановить.
Mac Safari Chrome
 Санкт-Петербург
0
0
shabanovd (#6763552)
Лады, тогда еще есть смысл усреднять по 2-3 значениям с шагом 1, чтобы сгладить и убрать "помехи".
Mac Safari
 Израиль
0
0
braintunic
Больше трёх месяцев шло по почте?
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Почему больше трех месяцев? Недели три-четыре, не помню. Другое дело, что было не до замков.
Mac Safari
 Израиль
0
0
braintunic
Отправлено из Китая 20-го января ;)
Linux Ubuntu Firefox
 Москва
1
0
Leonid Kaganov
Он долго валялся на столе. У меня было много работы. А сейчас работы нет, вот занимаюсь хуйней.

Забавно: искал алгоритмы в Яндексе, Яндекс мне предложил ответить на несколько вопросов по программированию для устройства к ним на работу. Ну, поотвечал ;) Хочу поработать.
Mac Safari
 Израиль
1
0
braintunic
> Яндекс мне предложил ...
> для устройства к ним на работу

Срочно поудаляй посты, где ты ругаешь Яндекс.
А то пришьют нелояльность к работодателю ;)
Linux Safari Chrome
 Wisconsin Rapids
0
0
Gena Kukartsev
Точно определить невозможно, но практически наверное можно. Я бы делал так:

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

2. Следил за значением скользящего среднего, его производной и второй производной.

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

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

Формально нужны такие данные:

Данные с нескольких десятков пиков:
- значение тока во всех точках по времени
- значение сглаженного тока во всех точках
- значение производной сглаженного тока
- значение второй производной сглаженного
- помеченная руками точка где надо открывать

Как-то так...
Linux Safari Chrome
 Wisconsin Rapids
0
0
Gena Kukartsev
Еще немножко деталей:

1 пусть по горизонтальной оси измерения идут через одинаковые интервалы времени, то есть у нас точки по времени [t0,t1,t2,t3...]

2. Ток в этих точках [i(0), i(1), i(2),...]

3. Средний ток в точке tk по трем измерениям: a(k) = (i(k-2)+i(k-1)+i(k))/3 (может надо будет больше чем по трем)

4. Производная среднего тока: d(k) = a(k)-a(k-1)

5. Вторая производная: d2(k) = d(k)-d(k-1)

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

В районе пика: ток высокий, производная низкая, вторая производная высокая, как-то так должно быть.
Windows Safari Chrome
 Москва
0
0
catalek (#2775318)
А я бы сглаживал фильтром Калмана, мы ведь под вполне известную кривую подгоняемся.
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Погуглю эту страшную фамилию...
Linux Safari Chrome
 Wisconsin Rapids
0
0
Gena Kukartsev
Не надо - это оверкил и не очень здесь подходит.

Вот лучше: вашу задачу решили люди довольно неплохо:

http://stackoverflow.com/questions/22583391/peak-signal-dete[...]

Windows Firefox
 Днепропетровск
0
0
Theoristos1 (#5514894)
Калман, на самом деле, тут не особо подходит.
Windows Safari Chrome
 Москва
7
0
alex-mah
Концевик нужен, без него никак. Току верить нельзя, вдруг ригели начнет подклинивать на середине поворота.
Windows Firefox
 Щелково
0
0
abrrvalk
Ригели не ходят в промежутке. Совсем. Можно убедиться на любом замке. Хотя механические проблемы, конечно, возможны.
Windows Firefox
 Киев
1
0
Кондыбас (kondybas)
"На один оборот" - это как раз провал между двумя пиками, ригель подвинут на шаг, личинка вращается вхолостую.

Ловится, как уже сказано, по смене знака производной (второй в цикле) после фильтрации высоких частот.
Mac Safari Chrome
 Ярославль
0
0
ЛёШа Фу! (kvasdopil)
Сорян за дилетантский вопрос, но может заодно с током ещё и напряжение измерять? Не получится ли график мощности более показательным?
Linux Ubuntu Firefox
 Москва
1
0
Leonid Kaganov
У меня офигенный источник Юра подарил, там напряжение всегда 12 вольт (так выставлено), а ток я выставил ограничение 400ма - чтоб мотор не сгорел, заклинившись во время отладки.
Windows Safari Chrome
 Санкт-Петербург
0
0
colibri
Keyboard Mod: A Physical Keyboard For The Moto Z
https://www.indiegogo.com/projects/keyboard-mod-a-physical-k[...]
Windows Safari Chrome
 Чили
0
0
харитон устинович йорк22 (#6772611)
Судя по графику простой медианный фильтр должен съесть весь шум.
Windows Firefox
 Юбилейный
0
0
Overrider (#6636356)
Высчитать среднее от первого десятка измерений, потом отслеживать превышение от среднего в n раз.
Windows Safari Chrome
 Домодедово
4
0
id
Датчик положения.

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

Кстати, а поясни задачу, которая требует определения этих самых оборотов? Если просто нужно определить окончание хода, почему не применить классический алгоритм "закрывания автомобильного стекла": таймаут плюс сверхток?

И заодно уж: а чем ты измеряешь ток? Надеюсь, не гадостью вроде ACS712, которая сама по себе шумит как пол-мотора? Только шунт+ОУ, только хардкор! (это мнение моей съеденной собаки).
Linux Ubuntu Firefox
 Москва
0
0
Leonid Kaganov
Когда ригели начнут ходить не свободно, задача даже упростится - нагрузка в момент поворота замка станет выше.

Ток меряю на земле микросхемы L293D. У 8266, увы, всего 1 ножка АЦП, ею и меряю.
Windows Safari Chrome
 Домодедово
2
0
id
А хотя да, похоже я был неправ: действительно, нагрузка на ригели сделает пики более различимыми.
Все равно, затея кажется неправильной.
Linux Firefox
 Москва
2
0
Чук
та поставь 3 резистора и 2 концевика и отлавливай состояние "открыто-закрыто" через АЦП. KISS-принцип
Linux Firefox
 Москва
2
0
Чук
А зачем фильтры лепить? На сколько я понял, надо просто "считать обороты". Гистерезиса вполне будет достаточно. Уровни можно подстраивать по ходу, например, в % от максимума. Оборот считается завершенным когда ток сначала превысил верхний уровень, а потом опустился ниже нижнего.
А так, да, лучшее решение - 2 концевика
Windows Opera
 Великобритания
0
0
mrtrz (#6598657)
Не по теме, но я тут случайно нагуглил, что есть RFID тэги в виде колец (на палец). Вы такой вариант не тестировали случайно?
Вживление в руку это конечно круто модно молодёжно, но не для всех.
Linux Ubuntu Firefox
 Москва
2
0
Leonid Kaganov
Я что, лебедь перелетный, кольцо на конечностях таскать?
Windows Safari Chrome
 Москва
2
0
Михаил
Ох, увидит Ольга этот комментарий...
Windows Firefox
 Калуш
1
0
Val
Вариант 1.
Поставить оптопару на отражение со стороны дверного косяка. Когда язычка нет, один сигнал, приехал язычок - другой. Привести уровни к стабильным срабатываниям 0/1.
Вариант 2.
Замерить время гарантированного закрывания на известном напряжении и, пОмОлясь, считать, что за это время замок успеет доехать. Не рекомендуется.
Mac Safari
 Домодедово
2
0
id
Со стороны дверного косяка элементарно врезается например обычный автомобильный концевик двери, таким образом, что ригель размыкает его своим торцом. Если взять концевик не от Жигулей, а от автомобиля - то лет на 20 его ресурса хватит, а там или Собянин дом снесет, или не Собянин.
А вот как сделать второй концевик - надо подумать, глядя по месту.
Windows Safari Chrome
 Красноярск
0
0
balal
Сделать концевик на 3 положения...
Windows Safari Chrome
 Домодедово
2
0
id
"Закрыто", "Открыто" и "Не открыто"? :)

Леонид считает оба промежуточных импульса не от хорошей жизни: на этом основан его метод "виртуального концевика". Ну а нам-то, адептам ортодоксального концевизма, это среднее положение к чему нужно? Совершенно не нужно оно нам :)
Windows Safari Chrome
 Красноярск
0
0
balal
Я из текста про два оборота вычитал, думал, это зачем-то важно...
Windows Safari Chrome
 Рязань
1
0
Кухаренко
Второй можно в замок и пусть ригель жмёт на него своим другим концом. При этом концевик может торчать из корпуса замка на сколько угодно - в двери места много. На самом деле врезка первого концевика не кажется такой уж элементарной задачей. Там отверстьице под ригель миллиметров 15-20, дальняя стенка профиля (если она вообще есть, а то и из П-образных профилей коробки делают) далеко. Как туда вообще залезть при уже установленной двери, не то что концевик закрепить.
Я там на фото вижу, вал торчит из личинки. Вот можно на него эксцентрик (или кулачок, или ещё что в этом роде), рядом на корпус концевик, и пускай эксцентрик жмёт на выключатель при каждом обороте. Уж такой-то пик точно не пропустишь.
Но это так, оффтопик. Хочет Леонид графики анализировать, ну и ради бога.
Windows Firefox
 Санкт-Петербург
0
0
тупиточка
(Обучить нейронную сеть, само собой.)
Или хотя бы упрощенный алгоритм с эмпирикой.
Выделить несколько признаков, в том числе и порог, и по их совокупности принимать решение. Алгоритм не видит полного графика, можно на примерах закрыть правую половину листочком бумаги и постепенно её сдвигать вправо. По постепенно открывающейся части смотреть и принимать решение, следя за собственной мыслью, потом просто свой ход мыслей и формализовать.
Windows Firefox
 Москва
2
0
владимр
в дополнение к нейронным сетям сейчас еще нужно блокчейн...

:)
Windows Firefox
 Киев
0
0
Кондыбас (kondybas)
И бигдату. Ну, чтобы уж совсем феншуй-хентай.
Windows Safari Chrome
 Германия
0
0
DennisSi (#6648451)
Оффтоп:
Может уже знаешь, но на всякий случай вот полезная либа, чтобы пароли и название сети в коде текстом не хранить
https://github.com/tzapu/WiFiManager
Mac Safari Chrome
 Краснодар
1
0
ignik
язадатчик. Пока новый - всё хорошо. Начнёт заедать - дверь не откроешь.
Linux Ubuntu Firefox
 Израиль
0
0
200-1.95M
(Блядь) "общество может состоять сплошь из умных людей, но быть при этом в состоянии идиотизма" (журнал Новособирской АН "Эко", когда-то) Почему Леонид или кто-то из комментаторов не президент или министр. Что виноват кто делать?
Linux Ubuntu Firefox
 Израиль
1
0
200-1.95M
Mac Safari
 Израиль
4
0
braintunic
> Почему Леонид или кто-то из комментаторов не президент или министр?

Потому что людей жалко!

Пока ещё, слава богу, писателей-фантастов а тем паче программистов PHP в правительстве не было - и только благодаря этому ещё не наступил полный абзац ;)
Linux Ubuntu Firefox
 Израиль
0
0
200-1.95M
Я думаю, что с греческого "демократия" переводится как любовь к народу, а не власть народа. Гиппократ - любитель лошадей, а не власть лошадей. "Кл" это гордость. Патрокл - отца
Linux Ubuntu Firefox
 Израиль
0
0
200-1.95M
"Кл" это слава, славянское слав
Linux Safari Chrome
 Москва
1
0
albedо
У вас хорошо получается.
Переведите имя Гиппарх.
Linux Ubuntu Firefox
 Израиль
0
0
200-1.95M
От древнегреч."лошадь" + "правитель". Правитель лошадей:)?
Источник: http://kurufin.ru/html/A_greek_names/a_greek_names_ch.html
Windows Safari Chrome
 Новосибирск
2
0
Алекс (yozh73)
Проще спросите. Почему умных Леонида и комментаторов много, а надежного и доступного отечественного электрозамка нет и не будет.
И даже запчасти из Китая приходится выписывать.
Потому что умные люди умом пользуются ради фана. Одно дело в выходной поизгаляться, совсем другое жизнь на эти железки убить. Дураков среди умных нет.
Windows Safari Chrome
 Москва
2
0
Twentydraft
Леонид, мой вам совет, купите на али два шаговых мотора с драйверами, или прикрутите две оптопары и линейку с прорезями. Детектить положение осей моторов по потребляемому току - дело исключительно неблагодарное как из-за изменений сопротивления самого замка, так и из-за скачков напряжений. Я делал задвижку для бункера с кормом для кур и намучался изрядно, поверьте.
Лучше один раз заморочиться и сделать нормально, имхо
Windows Firefox
 Израиль
0
0
Павел бывший Пашка
Ну почему, это вполне легитимно, остановка мотора по механическому усилию - встречал это во всяческих сервомоторах и в гидравлике нередко, иногда как предохранение от поломки механизма, иногда как штатное отключение. Делают даже чуть плавающую подпружиненную подвеску мотора с редуктором, в крайних положениях вся сборка чуть поворачивается и давит на контактные группы. Остроумно, очень дешево и надежно.
Windows Safari Chrome
 Красноярск
0
0
balal
У меня на электромясорубке какой-то там предохранитель с кнопочкой не предохранил шестерни редуктора.
Linux Safari Chrome
 Красногорск
0
0
doublekey (#6641011)
Можно попробовать считать свёртку с фрагментом сигнала, снятого в момент поворота ригеля. Даже если сигнал изменится со временем, в моменты поворота должен получаться максимум. Ну и можно обновлять периодически опорную функцию.
Windows Safari Chrome
 Франция
1
0
Stanislav
Самый вычислительно затратный способ (куда уж там фильтру Калмана), но может очень хорошо работать. Особенно если перед вычислением свертки и записью опорной функции применить медианную фильтрацию, как предлагали выше.
А вообще, конечно, аппартный датчик лучше устройства оценки (наблюдателя).
Windows Firefox
 Израиль
0
0
Павел бывший Пашка
Этот способ хорош для дистанционного привода гидроусилителя кнопки стеклоподъемника.
Windows Safari Chrome
 Красноярск
0
0
balal
Возможно, кстати, приклеить кусочек яркой фольги на предпоследнюю шестерёнку механизма (или чёрным покрасить, оставив сектор, или двухцветный диск приклеить на шестерёнку, что на валу двигателя), просверлить напротив неё дырочку, поставить оптопару на отражение (Или к шестерёнке двигателя разместить маленький индуктивный датчик, если та шестерёнка магнитится) и считать обороты той шестерёнки.
Linux Ubuntu Firefox
 Amsterdam
1
0
gehrmann
Резистор-потенциометр через шестерёнку. Там вон и ось подходящая, и очень легко программируется.
Windows Firefox
 Санкт-Петербург
0
0
тупиточка
А энкодер, как же без энкодера?!
Linux Ubuntu Firefox
 Германия
1
0
gehrmann
Резистор-потенциометр - это частный случай энкодера. В данном случае самый простой, дешёвый, довольно надёжный и вполне уместный. Или это был тонкий троллинг?
Windows Safari Chrome
 Домодедово
5
0
id
Косвенные измерения стоит использовать только там, где иным путем - ну вообще никак. А вы предлагаете "трижды косвенное": сопротивление через шестеренку с вала...

Задача: определить положение ригеля.
Именно на ригеле и должны быть концевики.

И то же самое - про их конструкцию. "Наклеить зеркало и поставить оптопару", "наклеить магнит и поставить датчик Холла", "поставить индуктивный датчик" - это все игры в хайтек. Увлекательные - но по своей сути деструктивные, так как уводят задачу в плоскость выпендрежа в ущерб надежности.

Обычный механический контакт. Который, будучи правильно выбран и правильно размещен (а так же правильно использован), обеспечит ресурс не только заметно выше пластиковой крышки щеточного узла мотора этого замка :) , но и вообще не потребует замены до окончания срока службы здания.
Windows Firefox
 Санкт-Петербург
0
0
тупиточка
В данном случае человека интересует не надёжность и полезность конструкции, а абстрактная техническая задача - выделение из реального сигнала - сигнала полезного, на фоне шума.
Linux Ubuntu Firefox
 Германия
0
0
gehrmann
Не буду спорить с вами о глубоком смысле использования концевиков для этой задачи. Замечу лишь, что у меня есть непосредственный опыт работы с вышеприведённым решением. Оно зарекомендовало как весьма и весьма надёжное именно для такого рода задач (ограниченные линейные перемещения от ДПТ с редуктором). К нему даже ПИД-регулятор можно дописать, что есть для меня немаловажный бонус.
Windows Safari Chrome
 Los Angeles
1
1
mexalon
Вот пара советов, которые возможно пригодятся
1. Не слушать тех, кто предлагает в том или ином виде дифференцировать численные данные, это путь в никуда.
2. Совсем без констант не выйдет, нужно хотя бы определить порог на соотношение "сигнал/шум".
3. Возможно самое простое будет сравнивать на ходу значения среднего сигнала в двух окнах разной ширины: одно окно от точки первого падения мощности до текущего момента, второе окно - бегущее, шириной порядка половины характерного размера отчётливого пика. Как только среднее во втором окне станет больше первого на величину порога - это будет нужный пик.
4. Можно всякий раз закрывать замок полностью, снимать кривую тока, анализировать (у готовой кривой найти пики гораздо проще, чем у получаемой в реальном времени), и по результатам анализа откручивать замок на нужные обороты.
Windows Safari Chrome
 Израиль
2
0
Igor
Я буду сотым, кто дал этот совет. Но капля камень точит. Вдруг дойдет.
1) Ты пытаешься принять таблетку за пять минут до появления головной боли. Когда картинка целая - то есть масса алгоритмов, которые выявят пики. Но ты хочешь выявить первый пик до того, как прошел второй и до того, как двигатель дошел до конца.

2) У меня один из ригелей идет вообще вниз. В полу ямка. Иногда в ямку попадает мусор. Усилие на ключе и поведение замка изменяется значительно.

Как инженер - только датчик. А твое решение в твоем случае - баловство и профанация.
Windows Safari Chrome
 Санкт-Петербург
4
0
leon_first
Вспоминается старый программистский анекдот - "- У нас проблема, будем решать с помощью регулярных выражений. - Теперь у вас две проблемы..." Если серьезно. Когда есть возможность решить прямую задачу (определение конечных точек), не следует решать косвенную задачу (детектирование пиков тока). Это - из моего многолетнего опыта проектирования систем. Вам НЕ НУЖНО знать, где находятся пики тока. Вам нужно останавливать моторчик в нужных точках. Конечно, в нужной точке будет пик тока, но не все пики тока будут соответствовать нужным точкам (инъекция). Впрочем, если заниматься ерундой приятно - почему бы и нет. Тем более за свой счет :)
Windows Firefox
 Москва
0
0
kuz
а зачем надо останавливать на одном обороте?
Windows Firefox
 Израиль
1
0
Павел бывший Пашка
У меня работала и отлично выделяла пики в очень похожей задаче такая аналоговая вычислялка на нескольких ОУ.
Принцип - схема сравнения с плавающим базовым уровнем.
Входной сигнал - сравнительно медленно меняющееся (частоты от десяти-двадцати до пары сотен герц) постоянное напряжение.
Главный элемент - ОУ в режиме компаратора. Т.е. который перебрасывается из одного насыщения в другое.
На один вход этого ОУ подается входной сигнал, а на второй - он же, но сильно сглаженный фильтром, "усредненный".
Моменты срабатывания этого компаратора будут соответствовать началу каждого пика.
(Разумеется, моменты срабатывания в определенную сторону - тут надо добавить после него еще ОУ, дабы получить на выходе пригодный, практически цифровой сигнал).
Эта схема неплохо работала и с простыми RC фильтрами, но мне нужно было - для кардиологии - весьма стабильно ловить пики со строго определенной крутизной атаки, на фоне диких помех, поэтому сначала добавился на входе полосовой фильтр, а потом и сглаживающий фильтр постепенно усложнился. В конце дошло до десятка ОУ (фигня, если есть счетверенные, ну 3 корпуса, подумаешь) и стало ваще идеально работать...
Но вам, думаю, для мотора хватит двух. И релюшку на выходе.
Почему лучше иметь плавающий уровень сравнения - так мы имеем право вообще не знать, какой там в среднем рабочий ток. Важно, чтобы на его фоне были хоть какие-то значительные пики.
Щас тут програмеры нагонят волну - а что проще, слепить из десятка деталей эту аналоговую машинку, или писать программу - не забывайте, что для этого извращения вам еще нужно сперва весь ток оцифровать, т.е. опять паять что-то ну никак не проще 2 операционников...
Windows Safari Chrome
 Израиль
0
0
Igor
Павел, у вас был периодический сигнал. А здесь - разовый импульс. Вот если бы Леонид открывал/закрывал дверь 60 раз в минуту - тогда другое дело.
Linux Safari Chrome
 Германия
0
0
_N_E_R_O_
Леонид, поверь без измерения оборотов и положения мотора или хода стержней не обойтись! Представь, что замок заклинило немного, появился всплеск, программа подумает, что дверь закрылась.

Если лень ставить датчики, то можно измерять обороты мотора методом DCM‐MotionTechnology, например:
zCda5aqTWNY


Но проще поставить датчик!
Windows Safari Chrome
 Москва
0
0
chmyrnovich
Интересны мелкие пички.

Если бы их количество было одинаковым между соотв. поворотами, видимо, можно было бы опознавать следующий.
Mac Safari
 Россия
0
0
Александр
А если кто-то отверткой с обратной стороны помешает личинке в момент закрывания ? и программа детектирует два пика и решит что замок закрылся полностью ?
Также не вижу смысла крутить меньше чем на два оборота. При силовом взломе вынимают и по 3-4 см ригеля из коробки, так что останавливаться на одном обороте не стоит.
Мне к примеру такая личинка не подходит, тк управление у нее только электронное. Ибо механически открыть его крайне сложно, нужно преодолеть огромное сопротивление редуктора.
Linux Ubuntu Firefox
 Одесса
0
0
Azimut
Возможно Вам будет удобнее использовать для этой цели аппаратное решение - а именно один операционник - очень кстати популярное решение у ардуиншиков, когда им надо яркость от тени отличать.
Windows Firefox
 Щелково
0
0
abrrvalk
Косячные исходные данные. На графике не ток, а случайные короткие выборки. Данные должны усредняться между измерениями. Хотя бы аппаратно примитивной RC цепочкой.

Потом можно будет применять стандартные алгоритмы. А так всегда есть высокая вероятность ложного срабатывания.
Windows Firefox
 Щелково
0
0
abrrvalk
И да, буду сто первым - пик тока не гарантирует события закрывания.

Ток это защита мотора и схемы от перегрева.

всего комментариев: 110

<< предыдущая заметка следующая заметка >>