Search code examples
pythonarduinopyserialarduino-c++usbserial

Arduino Serial Commands work independently, but when combined nothing happens


I have connected an Arduino to a raspberry pi so that a specific event is triggered when I send a signal(in this case a number). When I send a number with the script and tell it just to print in serial monitor it works, when I try and just have it run the motors on start it works fine, however when combining the two: having it run a specific command if a particular number is received nothing happens. If anyone could point to the flaw here, I would be very grateful. Python Code:

import serial, time
arduino = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
cmd = ''
while cmd != '0':
        cmd = input('Enter a cmd ')
        arduino.write(cmd.encode('ascii'))

Arduino Code:

#include <Arduino.h>

const byte MOTOR_A = 3;  // Motor 2 Interrupt Pin - INT 1 - Right Motor
const byte MOTOR_B = 2;  // Motor 1 Interrupt Pin - INT 0 - Left Motor
 
// Constant for steps in disk
const float stepcount = 20.00;  // 20 Slots in disk, change if different
 
// Constant for wheel diameter
const float wheeldiameter = 66.10; // Wheel diameter in millimeters, change if different
const float gear_ratio = 34;
const float PPR = 12;

// Integers for pulse counters
volatile int counter_A = 0;
volatile int counter_B = 0;
 
 
// Motor A
 
int enA = 10;
int in1 = 9;
int in2 = 8;
 
// Motor B
 
int enB = 5;
int in3 = 7;
int in4 = 6;
 
// Interrupt Service Routines
 
// Motor A pulse count ISR
void ISR_countA()  
{
  counter_A++;  // increment Motor A counter value
} 
 
// Motor B pulse count ISR
void ISR_countB()  
{
  counter_B++;  // increment Motor B counter value
}
 
// Function to convert from centimeters to steps
int CMtoSteps(float cm) 
{
  float circumference = (wheeldiameter * 3.14) / 10; // Calculate wheel circumference in cm
  
  return int(cm * gear_ratio * PPR / circumference); 
 
}
 
// Function to Move Forward
void MoveForward(int steps, int mspeed) 
{
   counter_A = 0;  //  reset counter A to zero
   counter_B = 0;  //  reset counter B to zero
   
   // Set Motor A forward
   digitalWrite(in1, HIGH);
   digitalWrite(in2, LOW);
 
   // Set Motor B forward
   digitalWrite(in3, HIGH);
   digitalWrite(in4, LOW);
   
   // Go forward until step value is reached
   while (steps > counter_A or steps > counter_B) {
   
    if (steps > counter_A) {
    analogWrite(enA, mspeed);
    } else {
    analogWrite(enA, 0);
    }
    if (steps > counter_B) {
    analogWrite(enB, mspeed);
    } else {
    analogWrite(enB, 0);
    }
   }
    
  // Stop when done
  analogWrite(enA, 0);
  analogWrite(enB, 0);
  counter_A = 0;  //  reset counter A to zero
  counter_B = 0;  //  reset counter B to zero 
 
}
 
// Function to Move in Reverse
void MoveReverse(int steps, int mspeed) 
{
   counter_A = 0;  //  reset counter A to zero
   counter_B = 0;  //  reset counter B to zero
   
   // Set Motor A reverse
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
 
  // Set Motor B reverse
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
   
   // Go in reverse until step value is reached
   while (steps > counter_A && steps > counter_B) {
   
    if (steps > counter_A) {
    analogWrite(enA, mspeed);
    } else {
    analogWrite(enA, 0);
    }
    if (steps > counter_B) {
    analogWrite(enB, mspeed);
    } else {
    analogWrite(enB, 0);
    }
    }
    
  // Stop when done
  analogWrite(enA, 0);
  analogWrite(enB, 0);
  counter_A = 0;  //  reset counter A to zero
  counter_B = 0;  //  reset counter B to zero 
 
}
 
// Function to Spin Right
void SpinRight(int steps, int mspeed) 
{
   counter_A = 0;  //  reset counter A to zero
   counter_B = 0;  //  reset counter B to zero
   
   // Set Motor A reverse
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
 
  // Set Motor B forward
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
   
   // Go until step value is reached
   while (steps > counter_A && steps > counter_B) {
   
    if (steps > counter_A) {
    analogWrite(enA, mspeed);
    } else {
    analogWrite(enA, 0);
    }
    if (steps > counter_B) {
    analogWrite(enB, mspeed);
    } else {
    analogWrite(enB, 0);
    }
   }
    
  // Stop when done
  analogWrite(enA, 0);
  analogWrite(enB, 0);
  counter_A = 0;  //  reset counter A to zero
  counter_B = 0;  //  reset counter B to zero 
 
}
 
// Function to Spin Left
void SpinLeft(int steps, int mspeed) 
{
   counter_A = 0;  //  reset counter A to zero
   counter_B = 0;  //  reset counter B to zero
   
   // Set Motor A forward
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
 
  // Set Motor B reverse
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
   
   // Go until step value is reached
   while (steps > counter_A && steps > counter_B) {
   
    if (steps > counter_A) {
    analogWrite(enA, mspeed);
    } else {
    analogWrite(enA, 0);
    }
    if (steps > counter_B) {
    analogWrite(enB, mspeed);
    } else {
    analogWrite(enB, 0);
    }
  }
    
  // Stop when done
  analogWrite(enA, 0);
  analogWrite(enB, 0);
  counter_A = 0;  //  reset counter A to zero
  counter_B = 0;  //  reset counter B to zero 
 
}
 
void setup() 
{
  Serial.begin(9600);
  // Attach the Interrupts to their ISR's
  pinMode(MOTOR_A,INPUT);
  pinMode(MOTOR_B,INPUT);
  pinMode(in1,OUTPUT);
  pinMode(in2,OUTPUT);
  pinMode(in3,OUTPUT);
  pinMode(in4,OUTPUT);
  pinMode(enA,OUTPUT);
  pinMode(enB,OUTPUT);
  
  attachInterrupt(digitalPinToInterrupt (MOTOR_A), ISR_countA, RISING);  // Increase counter A when speed sensor pin goes High
  attachInterrupt(digitalPinToInterrupt (MOTOR_B), ISR_countB, RISING);  // Increase counter B when speed sensor pin goes High

} 
 
 
void loop()
{
  delay(100);
  int compareOne = 1;
  int compareTwo = 2;
  int compareThree = 3;
  if (Serial.available() > 0){
    String stringFromSerial = Serial.readString();
    if (stringFromSerial.toInt() == compareOne){
      Serial.println("Forward");
      MoveForward(CMtoSteps(50), 255);  // Forward half a metre at 255 speed
    }
    if (stringFromSerial.toInt() == compareTwo){
       Serial.println("Spin Right");
       SpinRight(CMtoSteps(10), 255);  // Right half a metre at 255 speed
    } 
    if (stringFromSerial.toInt() == compareThree){
      Serial.println("Spin Left");
      SpinLeft(CMtoSteps(10), 255);  // Right half a metre at 255 speed
    }
    else {
      Serial.println("Not equal");
    }
  }
  Put whatever you want here!
   MoveReverse(CMtoSteps(25.4),255);  // Reverse 25.4 cm at 255 speed
}

UPDATE: I have changed the loop so that it compares ints instead of strings as per @GrooverFromHolland suggestion. Still, nothing happens when I input from python but it is printed in the serial monitor. Why the motors spin when I just trigger it in the loop directly for testing, but not when commanded to via serial monitor is my issue. As well as this, I have discovered that the interrupts are not working for some reason. Any help appreciated.


Solution

  • I see that you are using digital I/O interrupts in RISING mode. On a Arduino Duemilanove that I have here, a RISING mode interrupt will trigger continuously if the pin is not connected (i.e. high-Z). So, your observations could be explained if your motor hardware is not loading the input pins sufficiently, and so the counters A,B are incrementing "immediately". In this case, the motor functions (MoveForward(), etc) would exit very quickly because counter_A > steps, basically as soon as the function is called. It would appear that nothing happened, even though the function was executed.

    You could test this theory by connecting pins 2,3 to GND. Then the motors should run indefinitely (the counters will not increment). You can also print the value of counter_A and counter_B to the Serial monitor.

    Also, you may need to take care with the connection of the signals to the interrupt pins. Some de-glitching capacitors, pull-up resistors, or other signal conditioning might be needed. Printing the counter values will help with this also.