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!
1 Answer 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;
}
-
What relevance does this have to the actual problem of the question?Chris Stratton– Chris Stratton2017年05月12日 17:22:45 +00:00Commented May 12, 2017 at 17:22
-
This sketch is the best I know to read KY-040 encoders, so I guess it is pretty relevant.nico– nico2017年05月12日 21:50:55 +00:00Commented May 12, 2017 at 21:50
-
No, the poster had already solved that problem. The question concerns a different problem.Chris Stratton– Chris Stratton2017年05月12日 21:56:06 +00:00Commented May 12, 2017 at 21:56
-
OK, never mind. At least you know where to find a good solution to read KY-040 encoders if you need that in the future.nico– nico2017年05月12日 22:58:16 +00:00Commented May 12, 2017 at 22:58
Explore related questions
See similar questions with these tags.
print()
s. Verify that you're even receiving the right value through the serial port.