I didn't even see your reply when I posted earlier.
I will give it a go this weekend and report back on my findings.
Yes, I know how much this stuff is a pain in the butt between 2.7 and 3.4. Documentation is sketchy at best and for someone like me that has never touched Python before, it is extremely difficult to find solutions that work.
Well, the errors are gone, however, this is what happens...
"Arduino is ready" is printed on the PI side.
PI sends the command and prints (Sent from PC = Loop NUM 0 ........)
Arduino responds with (Reply Received Msg LED1 NewFlash 200 .......)
PI sends the command and prints ("Sent from PC = LOOP NUM 1......)
And it does nothing more at this point in time.
I suspect it is hanging in the watingForReply loop at this time.
I Installed the NOOBS package which is Rasbian (Graphical User Interface) on the PI 3.
Here is the python program
#=====================================
# Function Definitions
#=====================================
def sendToArduino(sendStr):
#ser.write(sendStr) # python 2.7
ser.write(sendStr.encode('utf-8')) #python 3.4
#======================================
def recvFromArduino():
global startMarker, endMarker
ck = ""
x = "z" # any value that is not an end- or startMarker
byteCount = -1 # to allow for the fact that the last increment will be one too many
# wait for the start character
while ord(x) != startMarker:
x = ser.read()
# save data until the end marker is found
while ord(x) != endMarker:
if ord(x) != startMarker:
#ck = ck + x #python 2.7
ck = ck + x.decode("utf-8")
byteCount += 1
x = ser.read()
return(ck)
#============================
def waitForArduino():
# wait until the Arduino sends 'Arduino Ready' - allows time for Arduino reset
# it also ensures that any bytes left over from a previous message are discarded
global startMarker, endMarker
msg = ""
while msg.find("Arduino is ready") == -1:
while ser.inWaiting() == 0:
pass
msg = recvFromArduino()
print(msg)
print()
#======================================
def runTest(td):
numLoops = len(td)
waitingForReply = False
n = 0
while n < numLoops:
teststr = td[n]
if waitingForReply == False:
sendToArduino(teststr)
print ("Sent from PC -- LOOP NUM " + str(n) + " TEST STR " + teststr)
waitingForReply = True
if waitingForReply == True:
while ser.inWaiting() == 0:
pass
dataRecvd = recvFromArduino()
print( "Reply Received " + dataRecvd)
n += 1
waitingForReply = False
print( "===========")
time.sleep(5)
#======================================
# THE DEMO PROGRAM STARTS HERE
#======================================
import serial
import time
print()
print()
# NOTE the user must ensure that the serial port and baudrate are correct
#ser = serial.Serial("/dev/ttyS0",9600, timeout =1)
serPort = "/dev/ttyS0"
baudRate = 9600
ser = serial.Serial(serPort, baudRate)
print( "Serial port " + serPort + " opened Baudrate " + str(baudRate))
startMarker = 60
endMarker = 62
waitForArduino()
testData = []
testData.append("<LED1,200,0.2>")
testData.append("<LED1,800,0.7>")
testData.append("<LED2,800,0.5>")
testData.append("<LED2,200,0.2>")
testData.append("<LED1,200,0.7>")
runTest(testData)
ser.close
And here is the ARDUINO program
#include <Servo.h>
Servo myServo;
byte servoPin = 8;
byte servoMin = 10;
byte servoMax = 170;
byte servoPos = 0;
byte newServoPos = servoMin;
const byte numLEDs = 2;
byte ledPin[numLEDs] = {12, 13};
unsigned long LEDinterval[numLEDs] = {200, 400};
unsigned long prevLEDmillis[numLEDs] = {0, 0};
const byte buffSize = 40;
char inputBuffer[buffSize];
const char startMarker = '<';
const char endMarker = '>';
byte bytesRecvd = 0;
boolean readInProgress = false;
boolean newDataFromPC = false;
char messageFromPC[buffSize] = {0};
int newFlashInterval = 0;
float servoFraction = 0.0; // fraction of servo range to move
unsigned long curMillis;
unsigned long prevReplyToPCmillis = 0;
unsigned long replyToPCinterval = 1000;
//=============
void setup() {
Serial.begin(9600);
// flash LEDs so we know we are alive
for (byte n = 0; n < numLEDs; n++) {
pinMode(ledPin[n], OUTPUT);
digitalWrite(ledPin[n], HIGH);
}
delay(500); // delay() is OK in setup as it only happens once
for (byte n = 0; n < numLEDs; n++) {
digitalWrite(ledPin[n], LOW);
}
// initialize the servo
myServo.attach(servoPin);
moveServo();
// tell the PC we are ready
Serial.println("<Arduino is ready>");
}
//=============
void loop() {
curMillis = millis();
getDataFromPC();
updateFlashInterval();
updateServoPos();
replyToPC();
flashLEDs();
moveServo();
}
//=============
void getDataFromPC() {
// receive data from PC and save it into inputBuffer
if(Serial.available() > 0) {
char x = Serial.read();
// the order of these IF clauses is significant
if (x == endMarker) {
readInProgress = false;
newDataFromPC = true;
inputBuffer[bytesRecvd] = 0;
parseData();
}
if(readInProgress) {
inputBuffer[bytesRecvd] = x;
bytesRecvd ++;
if (bytesRecvd == buffSize) {
bytesRecvd = buffSize - 1;
}
}
if (x == startMarker) {
bytesRecvd = 0;
readInProgress = true;
}
}
}
//=============
void parseData() {
// split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(inputBuffer,","); // get the first part - the string
strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
newFlashInterval = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
servoFraction = atof(strtokIndx); // convert this part to a float
}
//=============
void replyToPC() {
if (newDataFromPC) {
newDataFromPC = false;
Serial.print("<Msg ");
Serial.print(messageFromPC);
Serial.print(" NewFlash ");
Serial.print(newFlashInterval);
Serial.print(" SrvFrac ");
Serial.print(servoFraction);
Serial.print(" SrvPos ");
Serial.print(newServoPos);
Serial.print(" Time ");
Serial.print(curMillis >> 9); // divide by 512 is approx = half-seconds
Serial.println(">");
}
}
//============
void updateFlashInterval() {
// this illustrates using different inputs to call different functions
if (strcmp(messageFromPC, "LED1") == 0) {
updateLED1();
}
if (strcmp(messageFromPC, "LED2") == 0) {
updateLED2();
}
}
//=============
void updateLED1() {
if (newFlashInterval > 100) {
LEDinterval[0] = newFlashInterval;
}
}
//=============
void updateLED2() {
if (newFlashInterval > 100) {
LEDinterval[1] = newFlashInterval;
}
}
//=============
void flashLEDs() {
for (byte n = 0; n < numLEDs; n++) {
if (curMillis - prevLEDmillis[n] >= LEDinterval[n]) {
prevLEDmillis[n] += LEDinterval[n];
digitalWrite( ledPin[n], ! digitalRead( ledPin[n]) );
}
}
}
//=============
void updateServoPos() {
byte servoRange = servoMax - servoMin;
if (servoFraction >= 0 && servoFraction <= 1) {
newServoPos = servoMin + ((float) servoRange * servoFraction);
}
}
//=============
void moveServo() {
if (servoPos != newServoPos) {
servoPos = newServoPos;
myServo.write(servoPos);
}
}
Just go away, your idea of helping isn't what anyone wants. If you feel like slinging insults, go down to the nearest biker bar and pick a fight there. I am sure it will be much more enjoyable.
I have no experience with RaspberryPIs so I'm really shooting in the dark.
I assume your Uno is connected to the RPi using the USB connection?
Have you any means to send data from your Arduino to a PC while the Arduino is connected to the RPi? For example have you a USB-TTL cable or another Arduino?
The UNO is connected to the PI via I/O pins which are marked for TX/RX so they are (should be) hardware UARTS. Currently getting the serial port (of any type) on the PI to work is a bit of a mystery and requires changing a number of config files etc. I know I got through that part because it does communicate (most of the time).
I will dig around and find something to use with a PC and do some further experimenting. I have another UNO on order as a back-up so I could use that too. I also have a logic analyzer around here somewhere. Have not used it in years but that should allow me to see what the signals are actually sending.
I suspect this could be hardware related as well. Once I get the new UNO and PI back-ups, I am going to run the same tests and trials on them to see if they behave differently.
Thank you very much for all your help and assistance on this crazy problem. Thanks also for your patience!
It will probably be a couple of weeks before I can try all these other things. If I find anything that is conclusive I will report back here with the details.
Chris_D:
The UNO is connected to the PI via I/O pins which are marked for TX/RX so they are (should be) hardware UARTS.
That is probably a help. For testing you could create a SoftwareSerial port on the Uno and use two other pins to communicate with the RPI. That will leave HardwareSerial free for sending debug messages to the PC.
If you create an instance of SoftwareSerial called (say) SoftSerial then in the existing Arduino code change ALL the references from Serial to SoftSerial.
Then just add a line Serial.println(messageFromPC); so it sends the data to your PC (not the Pi) before your call parseData() (because parseData() will modify the data.
If you create an instance of SoftwareSerial called (say) SoftSerial then in the existing Arduino code change ALL the references from Serial to SoftSerial.
Or, say, pi, since that is what you are talking to, not a SoftSerial...
PaulS:
Or, say, pi, since that is what you are talking to, not a SoftSerial...
I know where you are coming from but in the circumstances I think "SoftSerial" is less confusing. I assume the OP will revert to HardwareSerial when he has things figured out.
Just wanted to update you on what I hope is the final outcome.
I have tried two different UNO's and two different Raspberry Pi, all yielded the same results, some good data mixed in with a lot of bad data.
After a lot of searching on Google and the various forums, I found what appears to be the cause and solution to the problem.
It is all on the PI side of things. Apparently, on the PI 3, they "engineers" decided to add bluetooth which also affected the functionality of the UART. There were a couple of workarounds, one that required setting the core frequency to 250 (normal is MUCH higher). The other workaround was to edit a number of files and add a patch file which re-directs the serial ports but doesn't require slowing down the core frequency.
Once all this was done, UART serial communications runs like it should, fast, reliable, and simple.