[SOLVED] Issue with serial and hardware interruption

Hello everyone !

I'm on a project: to hack a printer carriage to stop a foosball table ball (with image processing).

I have to transmit the position command to the arduino through serial but this interfere with my position servo control (I use a linear strip encoder)

My setpoint varies from 0 to 2000, for example I set 1000 and :

  • without serial the position servo control works well
  • with serial the carriage stops at 1300 (e. g.), it doesn't reverse to find the right position (1000).

Apparently it's a problem between hardware interruptions and serial.

Here's my entire code:

int pin_pwm = 11;
int pin_motor_1 = 9;
int pin_motor_2 = 10;

#define pin_encoder_I 2
#define pin_encoder_N 4

volatile int count; 

char serial_tab[32]; 

bool new_value = false;

int desired_position = 0; //global

void setup() {
 
 Serial.begin(115200);
 Serial.println("<Ready>");
 
 //pins motor
 pinMode(pin_motor_1, OUTPUT);
 pinMode(pin_motor_2, OUTPUT);
 pinMode(pin_pwm, OUTPUT);

 //pins encoder
 pinMode(pin_encoder_I, INPUT);
 attachInterrupt(0, handle_encoder, CHANGE);
 pinMode(pin_encoder_N, INPUT);
 
 count = 0;
}

void loop() {
 serial_communication();
 if (new_value == true) {
 desired_position = 0;
 desired_position = atoi(serial_tab);
 transfer_function(desired_position);
 new_value = false;
    }
}

void motor_function (int speed) { //
 if (speed == 0) {
 analogWrite(pin_pwm, speed);
 digitalWrite(pin_motor_1, HIGH);
 digitalWrite(pin_motor_2, LOW);
 }
 else if (speed > 0 ) {
 if (speed >= 255) {
 speed = 255;
 }
 speed = map( speed, 0, 255, 80, 255);
 analogWrite(pin_pwm, speed);
 digitalWrite(pin_motor_1, HIGH);
 digitalWrite(pin_motor_2, LOW);   
 }

 else {
 if (speed <= -255) {
 speed = -255;
 }
 speed = map (speed, -255, -1, -255, -80);
 analogWrite(pin_pwm, -1* speed);
 digitalWrite(pin_motor_1, LOW);
 digitalWrite(pin_motor_2, HIGH);
 }
}

void handle_encoder() {
 if(digitalRead(pin_encoder_I) == digitalRead(pin_encoder_N)) {
 count++;
 }
 else {
 count--;
 }
}

void transfer_function(int setpoint) { //a P servo yet, i'll replace with a pid
 float K = 0.2;
 int error = 0;
 
 error = setpoint - count;
 
 while (error >= 20 or error <= -20) {
 error = setpoint - count;
 int motor_speed = K * error;
 motor_function(motor_speed);
 }
 motor_function (0);

void serial_communication() {
 static byte k = 0;
 char delimiter = '!';
 char received_byte;
 
 if (Serial.available() > 0) {
 received_byte = Serial.read();
 
 if (received_byte != delimiter) {
 serial_tab[k] = received_byte;
 k++;
 }
 else {
 serial_tab[k] = '\0';
 k = 0;
 new_value = true;
 }
 }
}

I've searched all the internet and didn't find a correct answer to my issue :confused:

Thank you in advance

Sorry for my English, I'm French :stuck_out_tongue:

code.ino (2.11 KB)

Why do you attach the interrupt handler to pin 0 ? isn't that your serial communication ?

the code is missing a } before the serial_communication function definition ?
you should ensure you don't try to receive more than 31 characters - if you have a buffer overflow then you are in trouble;

how did you connect your power supply for the motor? any risk of interference with the Serial lines?

larrychance:
Sorry for my English, I'm French :stuck_out_tongue:

There is a french forum (but your english is totally fine)

paulvha:
Why do you attach the interrupt handler to pin 0 ? isn't that your serial communication ?

No that's correct. The 0 there is the interrupt number (for pin #2 - his pin_encoder_I )

that being said the recommended way to write this isattachInterrupt(digitalPinToInterrupt(pin), ISR, mode); // recommendedwhere you indeed pass the pin number

J-M-L:
the code is missing a } before the serial_communication function definition ?
you should ensure you don't try to receive more than 31 characters - if you have a buffer overflow then you are in trouble;

how did you connect your power supply for the motor? any risk of interference with the Serial lines?

There is a french forum (but your english is totally fine)

I already asked the french forum but did'nt get any accurate answer :confused:

i use a l293d chip and a simple switched-mode power supply of 12v (the nominal voltage is 23.5) and I don't think there can be any interferences.

for the buffer i'm supposed to transmit 5 char so a buffer of 31 should be sufficiant

There's nothing in the code to stop buffer-overrun on the serial_tab if no delimiters are received.

If the buffer overruns your other variables get stomped on and all bets are off as to the behaviour
of the code.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

If the encoder is producing a lot of pulses per second it may use up so much of the Arduino's CPU cycles that it is unable to keep up with serial input. Serial requires interrupts to be enabled and they are disabled in an ISR. Even though your ISR code is commendably short it may be enough to screw things up if there are a lot of encoder pulses.

...R

larrychance:
i use a l293d chip and a simple switched-mode power supply of 12v (the nominal voltage is 23.5) and I don't think there can be any interferences.

can you attach a diagram / describe your wiring? could you try powering the motor separately from the arduino?

larrychance:
for the buffer i'm supposed to transmit 5 char so a buffer of 31 should be sufficient

are you typing that in the Serial Console yourself or it comes from somewhere else?

paulvha:
Why do you attach the interrupt handler to pin 0 ? isn't that your serial communication ?

The interrupt handler is attached to interrupt 0, correctly. The first argument is NOT the pin number. It is the interrupt number.

Robin2:
Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

If the encoder is producing a lot of pulses per second it may use up so much of the Arduino's CPU cycles that it is unable to keep up with serial input. Serial requires interrupts to be enabled and they are disabled in an ISR. Even though your ISR code is commendably short it may be enough to screw things up if there are a lot of encoder pulses.

...R

indeed my encoder (i get it from a ink printer) produces a lot of impulses, but when i received a number ,the serial isr should be disabled or i missed something ?

J-M-L:
can you attach a diagram / describe your wiring? could you try powering the motor separately from the arduino?

are you typing that in the Serial Console yourself or it comes from somewhere else?

i've just done a fritzing one

i'm doing tests with the serial monitor but the aim is to send the setpoint with python (where i have the image processing code)

Your image: (seems it's twice the same)

since you read french, have a look at Le moteur à courant continu and check the part discussing the L293D

indeed my encoder (i get it from a ink printer) produces a lot of impulses

Are things working when the motor spins slowly? what is "a lot"?

J-M-L:
Your image: (seems it's twice the same)

since you read french, have a look at Le moteur à courant continu and check the part discussing the L293D
Are things working when the motor spins slowly? what is "a lot"?

my motor works well, in fact my problem is when I use the serial (without the serial transmission the servo is very reactive and goes to the right place (even if it is a P corrector))
when I put a small proportional gain: yes it works more or less but my goal is to put a strong gain for the speed and accuracy of the system

for the number of encoder values it depends on the baudrate but for a displacement of 20 ms I must have about 100 ms, there are 2000 positions on the encoder strip so it scrolls quickly on the serial monitor

Translated with DeepL Translate: The world's most accurate translator

there are 2000 positions on the encoder strip so it scrolls quickly on the serial monitor

get rid of the excess prints to the Serial monitor.. this is also using interrupts...

larrychance:
indeed my encoder (i get it from a ink printer) produces a lot of impulses, but when i received a number ,the serial isr should be disabled or i missed something ?

If the Arduino is busy checking the encoder it can miss incoming Serial data. There isn't any simple solution to that. Maybe get an encoder with fewer pulses per revolution.

How many pulses per second is the encoder generating?

You are using CHANGE for you encoder interrupts. Is that essential? if you use RISING or FALLING the number of interrupts will be halved.

Have you the option to pause the encoder and then ask for and receive the serial data while it is paused?

PLUS what @J-M-L said.

...R

Robin2:
If the Arduino is busy checking the encoder it can miss incoming Serial data. There isn't any simple solution to that. Maybe get an encoder with fewer pulses per revolution.

How many pulses per second is the encoder generating?

You are using CHANGE for you encoder interrupts. Is that essential? if you use RISING or FALLING the number of interrupts will be halved.

Have you the option to pause the encoder and then ask for and receive the serial data while it is paused?

PLUS what @J-M-L said.

...R

i dont know how fast is the encoder but i think it generates a lot of impulsions (maybe 500 per sec)
i can change to RSISNG or FALLING but the precision will be also halved (and my project need a good precision). At the reception of data yes i can pasue the encoder.

i havent the system at home but next week i'll try all your solutions

thank you for your precise answers everyone

larrychance:
At the reception of data yes i can pasue the encoder.

That is probably the simplest solution. Be aware, however, that what I have in mind is that the sending of Serial data will only start after the encoder is paused.

...R

Today i have tried your solutions but i've found a very simple one (I never thought about it)
I just moved my transfert_function out of the if isr and i lowered the baudrate to 9600.
Now the servo control is fully operational

Thank you for your answers, i set the thread to solved

Hello larrychance

larrychance:
.........
I just moved my transfert_function out of the if isr .....

I don't understand what you have done.
Could you explain more?

Regards,
bidouilleelec