Stepper motor - Steps are very slow - Via Serial

I want to control my stepper motor connected to my Arduino from my Raspberry Pi via serial communication. My problem is that the steps are very slow.

Arduino:

#define dirPin 51
#define stepPin 50

void setup() {
  Serial.begin(2000000);
  Serial.setTimeout(0);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    
    int x = Serial.read();
    
    if (x == '1') {
      digitalWrite(dirPin, HIGH);
      Serial.println(x);
    }
    
    else if (x == '2') {
      digitalWrite(dirPin, LOW);
      Serial.println(x);
    }
    
    else if (x == '3') {
      digitalWrite(stepPin, HIGH);
      Serial.println(x);
    }
    else if (x == '4') {
      digitalWrite(stepPin, LOW);
      Serial.println(x);
    }

  }
}

Raspberry Py (Python):

import serial
import time

ser = serial.Serial("/dev/ttyUSB0", 2000000, timeout=0)

while True:
  i = 0
  if i == 0:
      ser.write(b'3')
      ser.write(b'4')

It's just an example in python, but, it's supposed to spin infinitely, it does, but, very slow...

It does it fast when from the Arduino I put: else if (x == '3') {

#define dirPin 51
#define stepPin 50

void setup() {
  Serial.begin(2000000);
  Serial.setTimeout(0);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    
    int x = Serial.read();
    
    if (x == '1') {
      digitalWrite(dirPin, HIGH);
      Serial.println(x);
    }
    
    else if (x == '2') {
      digitalWrite(dirPin, LOW);
      Serial.println(x);
    }
    
    else if (x == '3') {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(300);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(200);
      Serial.println(x);
    }


  }
}

I don't reckon it's practical to send individual steps over a serial connection. Much better to send a message to the Arduino telling it how many steps to move and allow the Arduino to take care of the individual step timing.

And if you are sending individual steps you should not send a separate message for HIGH and LOW. Just send a message for a step and let the Arduino do HIGH followed by a LOW. Most stepper drivers only need a very short duration pulse - less than 10 microsecs.

...R Serial Input Basics - simple reliable non-blocking ways to receive data. Simple Python - Arduino demo Stepper Motor Basics Simple Stepper Code

I did that as 2nd option, that is, I told Arduino
1st: number of steps to take.
2nd: the time it should take to take the steps (to control the speed).

The code is the following:

String Num1,Num2,Data;
#define led 12
#define stepPin 50
#define dirPin 51

void setup() {
  Serial.begin(2000000);
  Serial.setTimeout(0);
  pinMode(led, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {

  Serial.println("Insert Num1");
  while (Serial.available() == 0) {}
  Num1 = Serial.readString();
  Serial.println(Num1);
  
  Serial.println("Insert Num2");
  while (Serial.available() == 0) {}
  Num2 = Serial.readString();
  Serial.println(Num2);

  Serial.println("Insert case");
  while (Serial.available() == 0) {}
  Data = Serial.readString();
  char dothis = Data.toInt();
      
  switch(dothis) {

  case 1:
    digitalWrite(led, HIGH);
    digitalWrite(dirPin, HIGH);
    Serial.println("Dir changed / left");
    for (int i = 0; i < Num1.toInt(); i++) {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Num2.toInt());
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Num2.toInt());
    }
    break;
    
  case 2:
    digitalWrite(led, LOW);
    digitalWrite(dirPin, LOW);
    Serial.println("Dir changed / right");
    for (int i = 0; i < Num1.toInt(); i++) {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Num2.toInt());
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Num2.toInt());
    }
    break;

  default: 
    Serial.println("Invalid Selection");
  break;
  }
}

But, the most it goes through is 400 steps with 2 milliseconds after HIGH and after LOW.
I feel like it would take a long time to react.

Knowing all that, do you know a better way to do it?

I think the only solution is to do it direct on Arduino.

I want the Arduino to do two tasks: 1. Let 2 motors be controlled automatically with data from one sensor. 2. Manually control the stepper mtors.

My question for you is: Can I have a loop with arduino to automatically control the motors and at the same time, in the background, control the motors via serial?

I am new to Arduino, I know that with a Raspberry pi you can because it has a lot of capacity, but, I don't know if it is on an Arduino.

Referring to Reply #2 ... You seem to be sending 3 values to the Arduino but you have not told us what they are and the performance of the motor depends on the values.

Serial.readString() can be very slow. It would make a lot more sense to send all three values in one message. Have you looked at the parse example in Serial Input Basics. Which also has the advantage of not using the String class.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

...R

raym3d: I think the only solution is to do it direct on Arduino.

Please slow down. Allow time for us to answer one question before asking another.

Can I have a loop with arduino to automatically control the motors and at the same time, in the background, control the motors via serial?

Please explain what you want to happen in more detail. I don't understand how motors could operate automatically and manually at the same time - surely it must be one or the other?

It's much easier to give useful advice if you tell us what your project is all about.

...R

It's certainly possible to control a motor with serial input and sensor or other program input or routines. You have already been directed to Serial Input Basics

It is important that to keep the program responsive you want to eliminate long for() loops, and delay(). The code needs to be "non blocking" and there are plenty of tutorials. For example Demonstration Code for Several Things at the Same Time.

But, the most it goes through is 400 steps with 2 milliseconds after HIGH and after LOW.

I'm not clear about what you mean, but if the program is halting after the constantly repeated String.toInt operations it's not a surprise.

I am new to Arduino, I know that with a Raspberry pi you can because it has a lot of capacity, but, I don't know if it is on an Arduino.

An Arduino has very limited capacity compared to a Raspberry Pi but there are programming techniques to use with the Arduino which can take you a long way.

raym3d: I will put an example, it does not mean that it is what I will do, it is just an example:

When you feel able to tell us what you really want to do I will see if I can help.

When people are coy about their projects I assume they are either illegal, anti-social or a commercial developer looking to make more profit from free advice.

...R

Check out my projects Stepper Speed Control Library for Arduino which combines a stepper library with a simple user Serial menu and Simple Multitasking Arduino on any board without using an RTOS which includes a stepper motor example and includes a section on "Getting User Input without blocking"

However I would now recommend using my SafeString library's non-blocking reads for handling user input. The SafeString library has multiple examples of parsing commands from Serial inputs (non-blocking of course)