I am sending three values from a Raspberry Pi via Serial (USB). I want these three values to control three different motors, the first is a servo and the second and third are DC-motors. When I send data from the Pi, it is in a string which is then split into it's parts into floats. When the Arduino sees that there is new data it sets newData = true
, and once it's all parsed it is reset to newData = false
. What I want to do is to make it so that if there has been no new data for the last 500 ms, then motor2
and motor3
should be set to zero, meaning that they are at a standstill. This is to protect the system in case of an interruption in the communication.
However, when i try to do as the following code at the bottom shows, then the output in the Serial Monitor looks something like:
motor1: 1
motor2: 2
motor3: 3
motor1: 4
motor2: 5
motor3: 6
motor1: 7
motor2: 8
motor3: 9
motor1: 7
motor2: 0
motor3: 0
motor1: 10
motor2: 11
motor3: 12
which is repeated and evenly spaced. So for some reason, the 0's sneak in even though the data is streamed continously 4 times per second with no interruption, which I've controlled in the terminal of the Pi. I don't quite see why it would behave like this. Also, if someone knows a solution to my issue I would gladly take it!
Code:
#include "Arduino.h"
#include <Servo.h>
#define motor1Pin 9
#define motor2Pin 10
#define motor3Pin 6
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
float motor1PWM = 0.0;
float motor2PWM = 0.0;
float motor3PWM = 0.0;
boolean newData = false;
Servo motor1; // create servo object to control rudder servo
Servo motor2;
Servo motor3;
int stillPWM = 50; // Motors are still at 50
unsigned long startMillis; // beginning of timing
unsigned long currentMillis;
const unsigned long period = 500; // how long one should wait before doing something
//============
void setup()
{
Serial.begin(9600);
startMillis = millis();
motor1.attach(motor1Pin);
motor2.attach(motor2Pin);
motor3.attach(motor3Pin);
stillPWM = map(stillPWM, 0, 100, 0, 180); // map the PWM so we use real PWM and not "servo PWM"
motor1.write(90);
motor2.write(stillPWM); // PWM initally set to 50, which is stand-still
motor3.write(stillPWM);
delay(3000); // delay to wait for ESC to calm down
}
//============
void recvWithStartEndMarkers() // Fix str to float
{
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false)
{
rc = Serial.read();
if (recvInProgress == true)
{
if (rc != endMarker)
{
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars)
{
ndx = numChars - 1;
}
}
else
{
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
currentMillis = millis();
}
}
else if (rc == startMarker)
{
recvInProgress = true;
}
}
}
//============
void parseData() // Fix str to float, split the data into its parts
{
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars,",");
motor1PWM = atof(strtokIndx); // convert this part to an float
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
motor2PWM = atof(strtokIndx); // convert this part to an float
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
motor3PWM = atof(strtokIndx); // convert this part to a float
}
//============
void showParsedData() // plot the received data
{
Serial.print("motor1: ");
Serial.println(motor1PWM);
Serial.print("motor2: ");
Serial.println(motor2PWM);
Serial.print("motor3: ");
Serial.println(motor3PWM);
}
//============
void runMotor1() // run the rudder servo
{
motor1.write(motor1PWM);
}
//============
void runMotor2()
{
motor2PWM = map(motor2PWM, 0, 100, 0, 180);
motor2.write(stillPWM+motor2PWM);
}
//============
void runMotor3()
{
motor3PWM = map(motor3PWM, 0, 100, 0, 180);
motor3.write(stillPWM+motor3PWM);
}
void loop()
{
// Expect a string like 10,10,10
recvWithStartEndMarkers();
if (newData == true)
{
strcpy(tempChars, receivedChars); // this temporary copy is necessary to protect the original data
parseData();
showParsedData(); // print the receieved data
newData = false; // Reset
}
if (currentMillis - startMillis >= period)
{
motor2PWM= 0;
motor3PWM = 0;
showParsedData();
startMillis = currentMillis;
}
runMotor1();
runMotor2();
runMotor3();
}
EDIT:
From
if (currentMillis - startMillis >= period)
{
motor2PWM= 0;
motor3PWM = 0;
parseData();
startMillis = currentMillis;
}
To
if (currentMillis - startMillis >= period)
{
motor2PWM= 0;
motor3PWM = 0;
showParsedData();
startMillis = currentMillis;
}