Garip sayımları denemeye çalışıyor

Şimdi umutsuzca takıldım ve yardıma ihtiyacım var.

Otomatik gözlemevi yapıyorum ve şimdi gözlem evinin kubbesini kontrol etmeye çalışıyorum. Kubbe bir adım motoru kullanılarak döndürülür ve iyi çalışır. Kubbın dönüşü, kubbenin hareket ettiği konusunda bağımsız bir doğrulama sağlamak için bir döner kodlayıcıyı da döndürür. RE bir kareleme türü olmasına rağmen, yön bilgisine gerek duymadığımdan, RE kanallarını her iki kanaldan sayıyorum.

Şimdi yapmaya çalıştığım şey, her bir RE kenarı çifti arasında kaç tane motor sürüş darbesi olduğunu saymak. Bunun arkasındaki mantık, kubbe hareketlerini izlemek ve sıkışmayı tespit etmektir. Gerçek motor darbeleri tüm kubbeli konum hesaplamaları için kullanılacaktır.

Bunu başarmak için, bir ULN2803A inverting buffer ve bir Arduino Nano ile küçük bir tahta inşa ettik. Nano, RE onaylarını saymak için D11 ve D12 pinlerinde Pin Change kesmelerini kullanır. Pin D7, şu anda mevcut olmasa da, bir Ev Konum sensörünü izlemek için de kullanılacaktır. Motor darbeleri tampon aracılığıyla Pin D2'ye (INT0) gönderilir ve motor yönü tampon yoluyla D3 pinine (INT1) gönderilir. Harici kesmeler, motor sinyallerine bağlı olarak motor sinyallerini yukarı veya aşağı saymak için kullanılır.

Bilgi için, başka bir kart mevcut, bir de Velleman VM110 USB koparma kartı, ayrıca döner kodlayıcı kene alır. Bu, döner kodlayıcı şaftını el ile döndürdüğümde anakartın aynı cevabı verdiğinin kontrol edilmesinin basit bir yoludur.

Tamam - üzgünüm bu kadar uzun sarıldı ama şimdi tuhaf oluyor.

Motoru çevirmeden RE döndürdüğümde her şey yolunda. Velleman kartı olarak dört kez kadar darbe alıyorum, Pin Changes kullanıyordum, her yükselişte ve düşüşte tetikleniyor, enkoderin tam döngülerinde değil. Bu tahmin edildiği gibi olur ve her şey güzel ve istikrarlıdır.

ANCAK - motoru çalıştırmaya başladığımda, kodlayıcıyı her hareket ettirdiğimde yüzlerce RE kenarı alıyorum ve bazen kodlayıcıya hiç dokunmadan RE tick'lerini arttırıyorum.

Açık cevap, bir çeşit RFI'dır ancak bunu elimden çıkarmak için elimden geleni yaptım. Motor sürücüsü ve onu besleyen Nano anakart blendajlı bir muhafazalıdır, motora giden kablo blendajlı bir kablodur ve dört motor kablosunun her birinde 10uH bobini vardır. Son olarak, güç hatlarına geri giden herhangi bir RFI'yi en aza indirgemek için motor kutusuna gelen güç kaynağına bir filtre taktım.

ULN2803A arabelleğinin kullanımı, bu işi yapmak için son girişimdi. Önceden sinyaller doğrudan Nano pinlerine gitti. Tampon ile, giriş tarafında 20k pull-up ve çıkışlarda 10k pull-up kullandım. Bu, sorunsuz çalıştığını bildiğim Velleman board giriş devresinin doğrudan bir kopyasıydı.

Benim girişimde Nano'ya giriş pimi üzerindeki motor darbelerine baktım ve bunlar 70 uS'lik bir süre ve 497 Hz'lik bir frekansa sahip hoş görünümlü keskin kenarlı darbeler. Accelstepper kütüphanesini kullanarak nabız hızını 500Hz'e ayarlamam kötü değil.

Şimdi bunun bir yazılım problemi olduğundan şüpheleniyorum. Bu benim için çok yeni olduğum için beni şaşırtmayacak, sadece ihtiyacım olan şeyi yapmak için her aşamada yeterince öğrenmeye çalışıyorum. Kodu ekledim - bu sorunlarım ile ilgili olmayan bir çok I2C nesnesi olmayan soyulmuş bir versiyon.

Yine bilgi için. attachInterrupt() işlevini kullanmayı denedim ve ilgili kayıtları doğrudan ayarlayarak - fark yok!

Her neyse, gerçekten birisinin bunu çözmemde bana yardımcı olabileceğini umuyorum.

Saygılarımızla, Hugh

/*          
ABoard3  
ROTATION MONITORING AND POSITION
Version AB3_stripped
*****************************PURPOSE*****************************************
This sketch is used on an Arduino Nano to count the motor pulses from ABoard1
and the Rotary Encoder ticks. The motor pulse count between encoder ticks is
used to detect dome jamming.
****************************INPUTS*******************************************
PIN CHANGE INTERRUPTS
**********ROTARY ENCODER INPUT*********
The rotary encoder is a Bourns ENA1J-B28 L00064L 1139M MEX 64 cycle per turn
optical encoder. This is connected to ABoard3 Pins D11 and D12. These pins
connect to Channel A and Channel B respectively. Pin change interrupts are used
to receive the rotary encoder output.
(The output pulses from the rotary encoder is also sent to the Velleman board
for use by LesveDomeNet for finding dome position)
*********HOME POSITION INPUT*********
The home position sensor is an Omron EESX671 Optical Sensor.
The sensor output is connected to ABoard3 Pin D7.
Pin change interrupt PCINT21 records activation/deactivation of the sensor.
EXTERNAL INTERRUPTS
*********MOTOR PULSE INPUT***********
The pulses sent to the G251X stepper driver are also sent to Aboard3 Pin D2.
This pin is the External Interrupt pin, vector INT0
*********MOTOR DIRECTION INPUT********
Motor direction is input to ABoard3 from ABoard2. ABoard2 pin, pnVmInRotMotor
(AB2:A0{54}) is connected to Velleman pins DI4 and DO2 and also to AB3:D3.
AB3:D3 is an External Interrupt pin, vector INT1.
*/

#include                        
#include "streaming.h"                        
#include "I2C_AnythingHEG.h"   
#include                     

//CONSTANTS                       
//PIN ASSIGNMENTS For ABOARD3
const uint8_t pnMotorPulse = 2;      //Port PD2, INT0, ISR(INT0_vect){}
const uint8_t pnMotorDirection = 3;  //Port PD3, INT1, ISR(INT1_vect){}
const uint8_t pnDomeAtHome = 7;      //Port PD7, PCINT23,ISR(PCINT2_vect){}
const uint8_t pnREChanA = 11;        //Port PB3, PCINT3, ISR(PCINT0_vect){}
const uint8_t pnREChanB = 12;        //Port PB4, PCINT4, ISR(PCINT0_vect){}

//*****************EXPERIMENTAL STUFF FOR PULSE COUNTING*******************************                  
uint16_t volatile myTest = 0;
int32_t volatile ratioCount = 0L;
int32_t volatile totalCount = 0L;
int32_t volatile tickCount = 0L;
uint8_t volatile halftickCount = 0;
int32_t volatile addPulse = 0L; 

void setup() {
  //**********************************SERIAL FOR DEBUG ONLY************************
  Serial.begin(115200);
  //*************************INPUT PIN MODE SETUP**********************************
  //NOTE Set all UNUSED PCINT0:5 pins (D8, D9, D10, D11) to OUTPUT.
  //and set the value to LOW
  //The actual pins used to receive interrupts have external 10k pull-ups.
  //This is to reduce susceptibility to interference causing false triggering.
  pinMode(pnMotorPulse, INPUT); //D2
  pinMode(pnMotorDirection, INPUT); //D3
  pinMode(pnDomeAtHome, INPUT); //D7
  pinMode(pnREChanA, INPUT); //D11
  pinMode(pnREChanB, INPUT); //D12
  pinMode(4, OUTPUT); //D4
  digitalWrite(4, LOW);
  pinMode(8, OUTPUT); //D8
  digitalWrite(8, LOW);
  pinMode(9, OUTPUT); //D9
  digitalWrite(9, LOW);
  pinMode(10, OUTPUT); //D10
  digitalWrite(10, LOW);
  //******************SET UP AddPulse According to Motor Direction******************
  //This is needed to make sure the pulse counting starts in the correct direction
  //as the direction is only checked in the ISR after a change has occurred.
  //If Motor Direction is AntiClockwise, change to Subtract a pulse
  if( digitalRead(pnMotorDirection)) {
    addPulse = 1L;
  } else {
    addPulse = -1L;
  }
  //**************************SET UP PIN CHANGE INTERRUPTS**************************
  //Set the Pin Change Interrupt Masks
  //Clear all bits to start with
  PCMSK0 &= 0b00000000; //Clear all bits
  PCMSK1 &= 0b00000000; //Clear all bits
  PCMSK2 &= 0b00000000; //Clear all bits
  //Mask for PCINTs 0 through 7 is PCMSK0 (Rotary Encoder Pulses)
  //Need to allow interrupts on PCINT3 and PCINT4, so set bits 3 and 4
  //PCINT3 is Nano  pin D11 and PCINT4 is Nano pin D12
  //Use a compound bitwise OR to set the bits
  PCMSK0 |= 0b00011000; //Enable PCINT3 ONLY (bit 3)
  //Interrupt on pins 11 and 12, RE Ticks
  //Mask for PCINTs 16through 23 is PCMSK2 (Home Position)
  //Need to allow interrupts on PCINT23 so set bit 7
  PCMSK2 |= 0b10000000; //Interrupt on pin 7, Home Position Sensor activated
  //Now enable the interrupts (TURN THEM ON) by setting bits in PCICR
  //PCICR is Pin Change Interupt Control Register.Set bit 0 (PCIE0)  
  //to enable interrupts PCINT0:7 This catches PCINT3 and 4 - RE Ticks
  //Set bit 2 (PCIE2) to enable interrupts PCINT16:23. Catches PCINT21 - Home Position Sensor
  PCICR &= 0b00000000; //Clear PCICR register 
  PCICR |= 0b00000001; //Set bit 0 - Catches PCINT3 & PCINT4 - RE Ticks
  PCICR |= 0b00000100; //Set bit 2 - Catch PCINT21 - Home Position Sensor
  //**************************SET UP 'EXTERNAL INTERRUPTS'**************************
  //Interupts on External Interrupt Pins D2 (INT0) and D3 (INT1).
  //INT0 (Nano pin D2)occurs when a stepper motor driver pulse is received
  //INT1 (Nano pin D3)occurs when the ABoard2 pin, pnVmInRotMotor toggles 
  //indicating a motor direction change.
  //To use the 'External Interrupts' the following registers need to be set-up:         
  //EICRA External Interrupt Control Register A       
  //Need to set Interrupt Sense Control bits ISC11 .. ISC00 (bits 3:0 in EICRA)
  //ISC01     ISC00 (INT0)    Interrupt
  //ISC11     ISC01 (INT1)    Generated by
 // 0         0             Low level on Pin
 // 0         1             Any Logical Change
 // 1         0             Falling Edge
 // 1         1             Rising Edge
  //First clear all bits, then set as follows:  
  //For INT1 - Motor Direction - Generate on ANY LOGICAL CHANGE     
  //bit 3 ISC11 0     
  //bit 2 ISC10 1 This combination = Any logical change causes interrupt 
  //For INT0 - Stepper Motor Pulses  - Generate on RISING EDGE      
  //bit 1 ISC01 1     
  //bit 0 ISC00 1 This combination = Rising edge of pulse causes interrupt
  //NOTE: To provide some immunity to RFI, Aboard3:Pins 2 & 3 are pulled high
  //using 10k resistors. 
  //So, code is
  EICRA &= 0b00000000; //Clear EICRA register
  EICRA |= 0b00000111;//Set bits 0,1 and 2 in EICRA register
  //EIMSK External Interrupt Mask Register        
  //Need to set External Interrupt Request Enables INT1 & INT0  (bits 1:0)          
  //First clear both bits, then set as follows: 
  //bit 1  INT1  1 External interrupt pin (D3) enabled   
  //bit 0  INT0  1 External interrupt pin (D2) enabled   
  //So, code is
  EIMSK &= 0b00000000; //Clear EIMSK register
  EIMSK |= 0b00000011;//Set bits 0 and 1 in EIMSK register
  //NOTE: Setting EIMSK TURNS ON THE EXTERNAL INTERRUPTS
  //************VARIABLE INITIALISATION*********
  myCommand = 0;
  myTest = 0;
  tickCount = 0L;
  totalCount = 0L;
} //END of setup

void loop() {
  //******************************COMMAND ACTIONS******************************
  if (myTest == 3) (
    //RE tick
    Serial << "Tick Count = " << tickCount << "  totalCount = " << totalCount << "\n";
    myTest = 0;
  }
}
//*************************FUNCTIONS/ISRs FROM HEREON*************************
ISR(INT0_vect) {
  //Triggered by stepper motor drive pulse from ABoard1
  totalCount = totalCount + addPulse;
}
ISR(INT1_vect) {
  //Triggered by a change in motor direction
  if(digitalRead(pnMotorDirection)) {
    addPulse = 1L;
  } else {
    addPulse = -1L;
  }
}
ISR(PCINT0_vect) {
  //Triggered by a ROTARY ENCODER TICK
  halftickCount++;
  if (halftickCount == 2) {
    //Make count same as Velleman
    tickCount++;
    halftickCount = 0;
    myTest = 3;
  }
}
ISR(PCINT2_vect) {
  //Triggered by activation of Home Position Sensor
  myTest = 4;
}
0
1) Bir kapsamınız var, motor vuruşlarına bakmak için kullandınız. Enkoder darbelerine de baktın mı? Nasıl görünüyorlar? 2) Bir karesel kodlayıcıda, herhangi bir zamanda en fazla bir kanalın “zıplama” olmasını beklerdim. Daha sonra, kodlayıcıyı her zamanki gibi kullanırsanız, sıfıra kadar +1, −1, +1, −1 ... sekanslarını almalısınız. 3) AVR I/O kayıtlarını ayarlamak için kullanılan standart deyim PCMSK0 = _BV (PCINT3) | PCMSK0 & = 0b00000000'den daha net görünen _BV (PCINT4); ; PCMSK0 | = 0b00011000; , en azından AVR programlamasına aşina olanlara.
katma yazar Sprogz, kaynak
PCMSK0 & = 0b00000000;//Tüm bitleri temizle - PCMSK0 = 0; daha açık olmaz mıydı? Bu arada Gerben'in cevabına katılıyorum. Erişiminizi kesintilerle ayarlanan çok baytlı değişkenlere "korumayı" deneyin. Kesmeler konusuna bakın.
katma yazar Nick Gammon, kaynak
Kuadratür enkoder çıkışları ile Arduino arasında uygun bir ortak zemine sahip misiniz? Öyleyse, @EdgarBonet haklı. Kuadratörler enkoderler çıldırmış gibi sıçrayabilir, bu yüzden kodlayıcıyı doğru okumaya, adım yönünü ve her bir okumadan gerçekten okumanıza gerçekten ihtiyacınız vardır. Bu şekilde, eğer +1 ve sonra -1, ya da herhangi başka bir sekansı, bir satırda 100 kez geri döndürürseniz, yeni yerin ne olduğunu bilersiniz, ve böylece siz de onu geri döndürdünüz demektir. Her kareleme çıkışında da 2.2uF kapağını eklemeyi deneyin, donanımın geri gelmesini sağlayarak biraz yardımcı olun.
katma yazar meepsh, kaynak
Kodlayıcıyı düzgün bir şekilde okumak, gerçekten ihtiyacınız olan yazılımı açığa çıkaran bir yazılımdır.
katma yazar meepsh, kaynak
Rotatif kodlayıcınız elektrik mi, optik mi? Anahtarın zıplamasından veya muhtemelen optik alıcının sınırda hızla açılıp kapanmasıyla ilgili sorunlarınız varsa merak ediyorum. Bu durumda, çözülmesine yardımcı olabilecek bir yol, dört kodlu darbeleri düzgün bir şekilde çözmektir. Bu blog yazısı, dört kodlu darbeleri kodlamanın güvenilir bir yolunu gösterir: thewanderingengineer.com/2014/08/11/… Regad'lar,
katma yazar CMaster, kaynak
İşlemcideki geri dönüşü gerçekleştirmenin bir alternatifi, amaç için tasarlanan bir çipi kullanmaktır. İşte uygun olanlardan biri: elmelectronics.com/ic/elm402 Saygılarımızla,
katma yazar CMaster, kaynak

1 cevap

Bazı değişkenler için int32_t kullanılmasına gerek yoktur. 8 bitlik bir işlemcinin 8 bitten fazla olan değişkenleri kullanmayla ilgili problem, işlemcinin değeri almak için 4 okumaya ihtiyacı olmasıdır. Okunanların ortasında, eski değerin bazı bitlerine ve yeni bazı bitlere sahip bir değere neden olan bir kesinti meydana gelebilir.

Bazı değişkenlerde sadece 8 bit gerekir.

uint8_t volatile myTest = 0;
int32_t volatile totalCount = 0L;
int32_t volatile tickCount = 0L;
uint8_t volatile halftickCount = 0;
int8_t volatile addPulse = 0L; 

Bir sonraki şey atomik değerin okunmasını sağlamaktır.

void loop()                                             
{                                               
//******************************COMMAND ACTIONS******************************  

if (myTest == 3)   //RE tick
{
    noInterrupts();
    int32_t tickCountCopy = tickCount;
    int32_t totalCountCopy = totalCount;
    interrupts();
    Serial << "Tick Count = " << tickCountCopy << "  totalCount = " << totalCountCopy << "\n"; 
    myTest = 0; 
}
}   

PS. Bu mutlaka bir cevap değil, ancak yorumlara uymadı.

1
katma
Burada gerçek bir sıçrama yok, ama muhtemelen beklediğiniz gibi bir geçiş kadar açık değil. Benim tahminim sadece bir schmitt tetikleyicisi işe yarayacak. Cevabım sorununuzu çözmese de, hala kodunuzla ilgili bir soruna işaret ediyor.
katma yazar Al., kaynak
Merhaba, teşekkürler Gerben ve Nick. Önerdiğin değişiklikleri yaptım ama aslında işleri daha da kötüleştiriyor gibiydi, daha iyi değil, çünkü adım motorunu çalıştırmasaydı bile RE kanallarının her birinde birden fazla tetiklemeye başladım.
katma yazar SeaDrive, kaynak
Oops - yeni bir hat istemiş ve getiri bastı, ancak bu iş bitmeden önce yorumu gönderdi. Yani, bundan sonra biçimlendirme eksikliğini mazur göster. Şimdi Rotary Encoder'ı çözmemiz gerektiği sonucuna ulaştım. Optik bir kodlayıcı olduğu için, bu durumun geri çekilmeyi gerektirmeyeceğini, ancak şimdi varsayımın yanlış olduğunu düşündüğümü KABUL ETTİM. Ben RC zamanlama ve Schmitt tetikleyici IC ters çevirerek bir 74HC14 hex kullanarak küçük bir donanım debouncer yapmak için gidiyorum. Umarım şapka problemi çözer. İyi haber şu ki, gerçek step motor darbeleri herhangi bir sorun olmadan sayılıyor. Sağol Hugh.
katma yazar SeaDrive, kaynak
Merhaba, kodlayıcı çıkışlarına bakmak için kapsamımı kullanmaya çalıştım ama nasıl düzgün kullanılacağını bilmiyorum ve anlamlı sonuçlar alamadım. Her kodlayıcı kanalında ca 5 mS gecikmesi kullanarak debouncer panosunu yaptım ve nihayetinde olması gerektiği gibi çalışıyor. Bu problemi ilk başta Aralık ayı başında yaşadım, bu yüzden bütün bu zamanı çözdü. Aslında bu sorunla ilgili yardım almak için kapsamımı satın aldım. Yanıtlayan ve yorum yapan herkese tekrar teşekkürler. Saygılarımızla Hugh
katma yazar SeaDrive, kaynak
@HughGilhespie, eğer sorun şimdi çözülüyorsa, lütfen kendi sorunuza bir cevap gönderin ve çözüldüğü gibi işaretleyin.
katma yazar meepsh, kaynak