3

So for my project I have one Arduino Mega hooked up with a quadrature rotary encoder which is connected to the computer. An Arduino Uno is connected to a circuit I built, which in turn is connected to a valve and a touch connector (also connected to the computer via USB). Both of them should be controlled with a Python script.

If the rotary encoder is moved, I can read out a value via the serial port. The value of the rotary encoder is used in Python to move a dot on the screen. If the dot on the screen reaches a certain point, I want to give a signal to the valve to open (something like pin.write(1) to turn on or pin.write(0) to turn it off). At the same time I want to be able to detect the touch sensor if the circuit is closed.

The issue is now that I need to somehow need to read the rotary encoder, process the data and send it to the valve, as well as reading the touch sensor simultaneously. So far I have not found a way how to achieve this as my code does not function.

At the moment I have custom code on My Arduino Mega and a StandardFirmata on the Arduino Uno, but I am open to other suggestions that could work.

Arduino Mega code:

/*
by Ben-Tommy Eriksen
https://github.com/BenTommyE/BenRotaryEncoder
*/

// Encoder connect to digital pin 2 and 3 on the Arduino.

int counter = 0;
//This variable will increase or decrease depending on the rotation of encoder

void setup() {
  Serial.begin (4600);
  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);
  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
}

void loop() {
  // Send the value of counter
  Serial.println (counter);
} 

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if(digitalRead(3)==LOW) {
    counter++;
  } else {
    counter--;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if(digitalRead(2)==LOW) {
    counter--;
  } else {
    counter++;
  }
}

Python code:

import pyfirmata
import serial
import time   

#Associate pyfirmata with python for my UNO board
port='COM5'
board= pyfirmata.Arduino(port)
#Use iterator thread to avoid buffer overflow
it = pyfirmata.util.Iterator(board)
it.start()

#Define pins (giving roles to pins: i.e. d=digital,7=pin number,i=input)
lickPin = board.get_pin('d:10:i') #records signal from the touch sensor
outPin1 = 12 #passes the signal to the valve 

s = serial.Serial('COM4',4600)
while time<60s #generalized:
    rotary = s.readline() #reads the counter of the rotary encoder form arduino

    #convert the rotary to an integer try/except is needed to work 
    try:
        var = long(rotary)
        last_var = var
    except:
        var = last_var
        pass

    value1 = lickpin.read()

    # Here I move the cursor up and down depending on the rotation of the encoder    
    # if the cursor moves above a certain value 
    if y>-18:  
        board.digital[12].write(1) #should open the valve

Unfortunately the code above does not trigger the valve to be opened, and I do not know why. Help is greatly appreciated. Thanks!

dda
  • 1,595
  • 1
  • 12
  • 17
Max
  • 31
  • 2

1 Answers1

-1

I wrote a simple sketch to read a KY-040 encoder with an Arduino UNO (or nano) board and to display the output in the Arduino IDE serial plotter (CTRL + SHIFT + L).

Here is the pinout:

ENCODER            ARDUINO UNO
====================================
GND            ⇒   GND
+              ⇒   +5V
SW  (button)   ⇒   pin D4 (PORT D4)
DT  (encoder)  ⇒   pin D3 (PORT D3)
CLK (encoder)  ⇒   pin D2 (PORT D2)

Here is a screenshot of the output in the serial plotter:

KY-040 encoder output in Arduino IDE serial plotter

Here is the picture of a project I am doing now (you need only the Arduino and the encoder for the sketch to work):

horloge cycles ultradiens Arduino nano + KY-040 encoder

And here is the code :

/*
LECTURE D’UN ENCODEUR ROTATIF KY-040
====================================
# DESCRIPTION DU PROGRAMME
Lecture d’un encodeur rotatif KY-040 pour affichage dans le traceur
série de l’IDE Arduino (CMD-SHIFT-L).
La rotation du bouton est détecté avec des interruptions sur les
broches 2 et 3 du port D.
Ce programme implémente un filtrage des rebond en deux étapes (voir
la procédure “lectureEncodeur”).
Ce programme est basé sur celui d’Oleg Mazurov
https://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino
Pour la gestion des interruptions, voir
https://sites.google.com/site/qeewiki/books/avr-guide/external-interrupts-on-the-atmega328
# RÉFÉRENCE DE L’ENCODEUR
http://www.banggood.com/5Pcs-5V-KY-040-Rotary-Encoder-Module-For-Arduino-AVR-PIC-p-951151.html
# CONNEXIONS DE L’ENCODEUR KY-040 SUR ARDUINO NANO
    GND            ⇒   GND
    +              ⇒   +5V
    SW  (bouton)   ⇒   pin D4 (PORT D4)
    DT  (encodeur) ⇒   pin D3 (PORT D3)
    CLK (encodeur) ⇒   pin D2 (PORT D2)
juin 2016, ouilogique.com
*/

#define ENC_A 2
#define ENC_B 3
#define ENC_C 4
#define ENC_PORT PIND
#define BtnRead  ! bitRead( ENC_PORT, ENC_C )

bool encodeurTourne = false;
byte ENC_PORT_VAL = 0;

// Modifier ici la sensibilité de l’encodeur pour qu’il ne réagisse
// pas trop vite. Cette valeur représente le nombre de millisecondes
// avant un changement sur la sortie.
static const long sensibiliteEncodeur = 10;

// Gamme de sortie de l’encodeur. À modifier en fonction de l’application.
static const int8_t minVal = 0;
static const int8_t maxVal = 10;


void setup()
{
  pinMode( ENC_A, INPUT_PULLUP );
  pinMode( ENC_B, INPUT_PULLUP );
  pinMode( ENC_C, INPUT_PULLUP );

  PCICR  |= ( 1<<PCIE2 );
  PCMSK2 |= ( 1<<PCINT18 );
  PCMSK2 |= ( 1<<PCINT19 );
  PCMSK2 |= ( 1<<PCINT20 );
  PCMSK2 |= ( 1<<PCINT21 );

  encodeurTourne = true;

  Serial.begin( 115200 );
}


void loop()
{
  static int8_t compteur = 0;

  // Lecture et affichage des valeurs de l’encodeur
  // dans le traceur série de l’IDE Arduino (CMD-SHIFT-L)
  if( encodeurTourne )
  {
    int8_t encodeurVal = lectureEncodeur();

    // Si le bouton est pressé, on remet le compteur à 0.
    if( encodeurVal == 2 )
    {
      compteur = 0;
      Serial.println( 0 );
      while( BtnRead ){ _delay_ms( 1 ); }
      _delay_ms( 20 );
    }

    // Sinon on met le compteur à jour en le gardant dans la gamme minVal..maxVal.
    else if( encodeurVal != 0 )
    {
      if( compteur < minVal || ( compteur == minVal && encodeurVal < 0 ) )
        { compteur = minVal; }
      else if( compteur > maxVal || ( compteur == maxVal && encodeurVal > 0 ) )
        { compteur = maxVal; }
      else
        { compteur = compteur + encodeurVal; }

      Serial.println( compteur );
    }
    encodeurTourne = false;
  }
}

/*
  lectureEncodeur() retourne
  -1 pour une rotation dans le sens anti-horaire
   0 pour une valeur impossible (rebond)
  +1 pour une rotation dans le sens horaire
  +2 si le bouton de l’encodeur est pressé
*/
int8_t lectureEncodeur()
{
  // Si le bouton est pressé, on quitte en retournant 2.
  if( ! bitRead( ENC_PORT_VAL, ENC_C ) )
  {
    return( 2 );
  }

  // Lecture des signaux de l’encodeur et comparaison
  // avec les valeurs possibles dans le code de Gray.
  // Ceci permet de filtrer la plupart des rebonds de l’encodeur.
  // Les valeurs à 0 représentent les transitions impossibles
  // et qui doivent être supprimées (resultat = 0).
  // Les valeurs à 1 représentent les transitions dans le sens horaire.
  // Les valeurs à -1 représentent les transitions dans le sens anti-horaire.
  static const int8_t enc_states[ 16 ] PROGMEM =
    { 0,-1, 1, 0, 1, 0, 0,-1,-1, 0, 0, 1, 0, 1,-1, 0 };
  static uint8_t old_AB = 0;

  old_AB <<= 2;
  bitWrite( old_AB, 0, bitRead( ENC_PORT_VAL, ENC_A ) );
  bitWrite( old_AB, 1, bitRead( ENC_PORT_VAL, ENC_B ) );
  uint8_t resultat = pgm_read_byte( &enc_states[ ( old_AB & 0x0F ) ] );

  // On accumule “maxVal” résulats dans un sens ou dans l’autre
  // avant de bouger. Ceci permet de supprimer les derniers rebonds
  // de l’encodeur qui n’ont pas été filtrés ci-dessus.
  if( resultat != 0 )
  {
    static int8_t resultatCumul = 0;
    const int8_t maxVal = 2;
    resultatCumul += resultat;
    if( resultatCumul >= maxVal )
    {
      resultatCumul = maxVal;
      resultat = 1;
    }
    else if( resultatCumul <= -maxVal )
    {
      resultatCumul = -maxVal;
      resultat = -1;
    }
    else
      { resultat = 0; }
  }

  // On rejete quelques lectures pour limiter la sensibilité de l’encodeur
  // et éviter ainsi qu’il ne tourne trop vite.
  static long lastT = millis();
  if( millis() - lastT < sensibiliteEncodeur )
    { resultat = 0; }
  else
    { lastT = millis(); }

  // On retourne le résultat.
  return( resultat );
}


ISR( PCINT2_vect )
{
  ENC_PORT_VAL = ENC_PORT;
  encodeurTourne = true;
}
nico
  • 249
  • 1
  • 5