can't control motors via Arduino and max

R_Gol's icon

I have the following Max patch:
and the following arduino code:

for some reason I can't control the motors, probably something with my code that I can't figure out. Anyone is seeing what I'm doing wrong?

Max Patch
Copy patch and select New From Clipboard in Max.


const int NUM_PWM_MOTORS = 4;
const int pwm_motor_pins[] = {3, 5, 6, 9};
const char pwm_motor_ids[] = {'A', 'B', 'C', 'D'};
const int NUM_DIGITAL_MOTORS = 4;
const int digital_motor_pins[] = {2, 4, 7, 8};
const char digital_motor_ids[] = {'W', 'X', 'Y', 'Z'};
unsigned long heartbeatMillis;
int heartbeatLED = 13;
void setup() {
for (int i = 0; i < NUM_PWM_MOTORS; i++) {
    pinMode(pwm_motor_pins[i], OUTPUT);
  }
  for (int i = 0; i < NUM_DIGITAL_MOTORS; i++) {
    pinMode(digital_motor_pins[i], OUTPUT);
  }
  Serial.begin(115200);
  pinMode(heartbeatLED, OUTPUT);
}
void loop() {
  checkHeartbeatTIMER();
  motorsControl();
}
void motorsControl()
{
  if (Serial.available() > 0) {
    char id = Serial.read();
    int state = Serial.parseInt();
    for (int i = 0; i < NUM_PWM_MOTORS; i++) {
      if (id == pwm_motor_ids[i]) {
        analogWrite(pwm_motor_pins[i], state);
        break;
      }
    }
    for (int i = 0; i < NUM_DIGITAL_MOTORS; i++) {
      if (id == digital_motor_ids[i]) {
        digitalWrite(digital_motor_pins[i], state);
        break;
      }
    }
  }
}
void checkHeartbeatTIMER()
{
  if (millis() - heartbeatMillis >= 500ul)
  {
    //restart this TIMER
    heartbeatMillis = millis();
//toggle the heartbeatLED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }
}
Source Audio's icon

you should start in the waters that you understand.
not copying parts from several sources without knowing how to link them.
1- make sure pins you assign are PWM capable.
2- start with 1 motor, no matter analog or digital.
send message from max and see if it works.

As beginner it is better to write longer code untill you learn how to
parse messages using for loop etc,
what I mean is use single statements
if incoming char is A then next int is pwm value for that motor,
if char is W than it is on /off for digital out
etc

R_Gol's icon

I have found my mistake. I needed to take out the integer 10 from [t 10 l]
I think it is because new line (ascii 10) is not needed because in my arduino code there is break; after each loop iteration

Source Audio's icon

without line feed (ascii 10) you will have 1000 ms delay which is caused by
Serial.Parseint() waiting for termination of digits stream.
means if you move slider from 0 - 122, it will stop at 121, wait
1000ms, and then output 122.
line feed can not be the cause of your motors not being controlled
with or without breaks, which anyway are not needed.

So you either leave line feed there, or
set serial timeout to shorter time, like 10 ms.
--------
here is reduced code with adjusted timeout to 10 ms
and arduino prints back received and parsed values.


const int NUM_PWM_MOTORS = 4;
const int pwm_motor_pins[] = {3, 5, 6, 9};
const char pwm_motor_ids[] = {'A', 'B', 'C', 'D'};
const int NUM_DIGITAL_MOTORS = 4;
const int digital_motor_pins[] = {2, 4, 7, 8};
const char digital_motor_ids[] = {'W', 'X', 'Y', 'Z'};
unsigned long heartbeatMillis;
int heartbeatLED = 13;

void setup() {Serial.setTimeout(10); Serial.begin(115200);}

void loop() {checkHeartbeatTIMER();motorsControl();}

void motorsControl(){if (Serial.available() > 0) {char id = Serial.read();
int state = Serial.parseInt(); for (int i = 0; i < NUM_PWM_MOTORS; i++) {
if (id == pwm_motor_ids[i]) {analogWrite(pwm_motor_pins[i], state);
Serial.print(id); Serial.print(" "); Serial.println(state);}}

for (int i = 0; i < NUM_DIGITAL_MOTORS; i++) {if (id == digital_motor_ids[i])
{digitalWrite(digital_motor_pins[i], state);
Serial.print(id);Serial.print(" ");Serial.println(state);}}}}

void checkHeartbeatTIMER(){if (millis() - heartbeatMillis >= 500){
heartbeatMillis = millis(); digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));}}

and max patch

Max Patch
Copy patch and select New From Clipboard in Max.

if you remove Serial.setTimeout(10); you will see what I mean

you can remove serial print back to max once everything gets confirmed to work.

R_Gol's icon

Thanks!

So you either leave line feed there, or
set serial timeout to shorter time, like 10 ms.

this is done with the message [open, poll 10) to the Serial object? that [poll 10) is replacing [t 10 l] from the other patch?

Source Audio's icon

no, poll message is to let serial object output received data from arduino,
same as if you would connect metro with 10ms interval.
open - opens the port, poll 10 starts polling data.
if you leave Serial.setTimeout(10); in arduino code,
no need to send ascii 10.

you should read Serial.parseInt(); tutorial somewhere
to understand the problem.

https://www.programmingelectronics.com/parseint/