Go Down

Topic: Processing -> Arduino code over serial only working with 850ms (Read 808 times) previous topic - next topic

foible

I'm making my first robot as the first step on a journey to make a more complex drive system. It's a very standard two wheeled setup using the Adafruit motor shield V2 to control the motors in addition to the Mega 2560. I'm using my Wireless XBox controller as an input device with a tank control scheme. The left and right stick positions are converted into floats on my computer, and then sent via USB-B serial with start and end chars to the Mega which interprets them, converts them to ints, and moves the motors. The receiving code is modified from Serial Input Basics.

Arduino Code:
Code: [Select]
#include <Wire.h>
#include <Adafruit_MotorShield.h>
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *motorA = AFMS.getMotor(3);
Adafruit_DCMotor *motorB = AFMS.getMotor(4);

const byte numChars = 128;
char receivedChars[numChars];

boolean newData = false;
double recvA;
double recvB;
int speedA;
int speedB;

void setup() {
    Serial.begin(9600);
    Serial.println("Lets roll");
    AFMS.begin(1600);
}

void loop() {
    recvProcessing();
    showSpeeds();
    moveMotorA();
    moveMotorB();
}

void recvProcessing() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMark = '#';
    char endMarkA = 'a';
    char endMarkB = 'b';
    char readChar;
   
 
    while (Serial.available() > 0 && newData == false) {
        readChar = Serial.read();

        if (recvInProgress == true) {
            if (readChar != endMarkA && readChar != endMarkB) {
                receivedChars[ndx] = readChar;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
               if (readChar == endMarkA){
               recvA = strtod(receivedChars,NULL);
               }
               else if (readChar == endMarkB){
               recvB = strtod(receivedChars,NULL);
               }
               
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (readChar == startMark) {
            recvInProgress = true;
        }
    }
}

void showSpeeds() {
    if (newData == true) {
        Serial.print("recvA: ");
        Serial.println(recvA);
        Serial.print("recvB: ");
        Serial.println(recvB);
        newData = false;
    }
}

void moveMotorA(){

  if((-0.1 < recvA) && (recvA < 0.1)){
    motorA->setSpeed(0);
    motorA->run(RELEASE);
  }
 
  if(recvA > 0.1){
     
      motorA->run(FORWARD);
      speedA = recvA*255;
      motorA->setSpeed(speedA);
     
    }

  if(recvA < -0.1){
     
      motorA->run(BACKWARD);
      speedA = recvA*-1*255;
      motorA->setSpeed(speedA);
     
    }
 
}
void moveMotorB(){

  if((-0.1 < recvB) && (recvB < 0.1)){
    motorB->setSpeed(0);
    motorB->run(RELEASE);
  }
 
  if(recvB > 0.1){
     
      motorB->run(FORWARD);
      speedB = recvB*255;
      motorB->setSpeed(speedB);
     
    }

  if(recvB < -0.1){
     
      motorB->run(BACKWARD);
      speedB = recvB*-1*255;
      motorB->setSpeed(speedB);
     
    }
 
}


Processing Code:
Code: [Select]
import processing.serial.*;
import net.java.games.input.*;
import org.gamecontrolplus.*;
import org.gamecontrolplus.gui.*;
import cc.arduino.*;
import org.firmata.*;

ControlDevice cont;
ControlIO control;
Arduino arduino;
float aPower;
float bPower;
String aSend;
String bSend;
Serial myPort;
String startChar = "#";
String endAChar = "a";
String endBChar = "b";

void setup() {
  size(360, 200);
  control = ControlIO.getInstance(this);
  cont = control.getMatchedDevice("LRCont");
  myPort = new Serial(this, Serial.list()[0], 9600);

  if (cont == null) {
    println("not today chump");
    System.exit(-1);
  }
 
}

void draw() {
  aPower = cont.getSlider("leftStick").getValue();
  aSend = str(aPower);
  aSend = startChar+aSend+endAChar;
  println(aSend);
  myPort.write(aSend);
 
  bPower = cont.getSlider("rightStick").getValue();
  bSend = str(bPower);
  bSend = startChar+bSend+endBChar;
  println(bSend);
  myPort.write(bSend);
                          delay(1000);
 

 
}


The delay at the very end of the processing code is the crux of the issue. With that delay, the whole system works, albeit only reading stick inputs once a second. Without the delay, the motors don't move at all. The Processing code writes everything it sends over serial to the Processing console as well, and it seems to be working fine at any speed. When I send values manually through the Arduino Serial Monitor, it works fine. I even made an AHK script to spam random speed values 100 times per second via the Serial Monitor, and the code interprets them and updates the motor speed just fine.
As far as I can tell, the problem is somewhere between after Processing spits out the serial data and when Arduino picks it up, but I can't tell where or how I can fix it.
I have a feeling that this is a common problem that other people have experienced. While searching for others with the same issue, I came across one user who reported example Processing -> Arduino code working perfectly fine with his Uno, but exhibiting similar behavior to my setup when he tried it on his Mega. I hope there's something obvious I'm missing, but until then I'm just going to lower the delay to 840 (840 works, 839 and it stops completely, splitting the delay between the two Serial.writes also doesn't work) and deal with the delay.

alexs_tech

Hi
Try moving the delay to setup() in processing
and give it a good nice value like 1500 or so

void setup() {
 size(360, 200);
 control = ControlIO.getInstance(this);
 cont = control.getMatchedDevice("LRCont");
 myPort = new Serial(this, Serial.list()[0], 9600);
delay(3000);
}

For some reason you need some time between initialising the port and sending the data.

Had similar issues with mega and thats how i solved it.

Hope it helps

Robin2

Please post an example of the message sent by Processing.

Why have you changed numChars to 128, having in mind that the Arduino Serial Input Buffer is 64 bytes?

I am not familiar with Processing but it seems as if you are sending the two joystick values separately. If so it would be better to send them both in a single message, for example <123, 456> because then the Arduino can never get mixed up as to which is for which axis

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

sterretje

For some reason you need some time between initialising the port and sending the data.
Most Arduino's will reset and the bootloader will kick in when opening the serial port; only when the bootloader times out and the sketch starts running ou will be able to communicate.

You can have a look if processing offers the option to suppress DTR when opening the serial port. There are terminal programs that provide that option as well ( serial monitor is not one of them ;) ).
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

alexs_tech

Most Arduino's will reset and the bootloader will kick in when opening the serial port; only when the bootloader times out and the sketch starts running ou will be able to communicate.
Actually yes it makes sense , just took a closer look at my setup and it does reset the arduino after serial connection. Weird i didnt even notice this before =)).

Anyway i took the original poster's code and replicated it with what i had at hand (i did need to strip down the control stuff cause i dont have the hardware , however i simulated some inputs).

After moving the delay in setup , comunications went smooth , but of course , the point is for the OP to test and see if it works

Go Up