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:
#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:
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.