I have a file with numbers called fginputs.txt
. For example it could be something like this:
4958
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4154
4958
I want python to send each number to arduino via serial port. After each number is received, arduino should print back an acknowledgment number, indicating that it got a valid number, and then store that number in a dynamic array, because I could create larger files. When there are no more numbers left, send a '-1' to finish transmission.
Here's my arduino code:
// save some unsigned ints
uint16_t SIZE, *inputList, cont = 0;
boolean inputsReady = false;
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
//free dynamic array memory
free(inputList);
//counter for how many numbers I've received starts at 0
cont = 0;
//This is true when there are no more numbers to receive, meanwhile false
inputsReady = false;
setupInputList();
}
/* If there's not enough space, resize the array by one unit and store the number
*/
void growAndInsert(int currentSize, int newInt){
if(currentSize > SIZE)
inputList = (uint16_t *)realloc(inputList, (currentSize + 1)*sizeof(uint16_t));
inputList[currentSize] = newInt;
}
/**
init inputList with 100 blocks
*/
void setupInputList(){
SIZE = 10;
inputList = (uint16_t *)malloc(sizeof(uint16_t) * SIZE);
}
void clearBuffer(){
while(Serial.available() > 0)
Serial.read();
}
/**
Listens in serial port for an integer that represents a new input and returns it.
If it doesn't get anything useful from serial, return 0
*/
int getNewInputFromSerial(){
if (Serial.available() > 0) {
delay(100);
// look for the next word
int cmd = Serial.parseInt();
clearBuffer();
if(cmd == 4958)
Serial.write("4");
else if(cmd == 4154)
Serial.write("5");
else
Serial.write("0");
return cmd;
}
return 0;
}
void loop()
{
if(!inputsReady){
int newInput = getNewInputFromSerial();
if(newInput == 0)
return;
if(newInput != -1)
growAndInsert(cont++, newInput);
else{
inputsReady = true;
//initTimer();
}
}
}
and the python script:
global arduino
PORT = '/dev/ttyACM0'
FILENAME = "fginputs.txt"
#Read file with inputs
with open(FILENAME) as f:
content = f.readlines()
#init serial port
arduino = serial.Serial(PORT, 9600, timeout=1);
time.sleep(2);
#write
for input in content:
arduino.flush()
arduino.write(input)
time.sleep(.1);
resp = arduino.read();
print "i got " + resp
#Finish transmission with -1
arduino.flush()
arduino.write("-1")
#done
arduino.close();
The fist time I execute the script I get this:
i got 4
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 5
i got 4
Which is great. But if I run it a second time I get this:
i got 0
i got 4
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
i got 0
Which is terribly wrong because the file hasn't changed. I don't know what is going on here. If I unplug and plug back in the USB cable, transmission works flawlessly again.
2 Answers 2
// save some unsigned ints
uint16_t SIZE, *inputList, cont = 0;
boolean inputsReady = false;
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
//free dynamic array memory
free(inputList);
You are freeing a NULL pointer which is (削除) an undefined operation (削除ここまで) not necessary here, since it was never allocated.
if (Serial.available() > 0) {
delay(100);
// look for the next word
int cmd = Serial.parseInt();
clearBuffer();
This is going to just throw data away, I'm not surprised stuff goes missing.
Read this: How to process incoming serial data without blocking - you need to get rid of the delay
, and the clearBuffer()
for a start.
Example code for reading from Serial without blocking and without using delay
:
// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 50;
void setup ()
{
Serial.begin (115200);
} // end of setup
// here to process incoming serial data after a terminator received
void process_data (const char * data)
{
// for now just display it
// (but you could compare it to some value, convert to an integer, etc.)
Serial.println (data);
} // end of process_data
void processIncomingByte (const byte inByte)
{
static char input_line [MAX_INPUT];
static unsigned int input_pos = 0;
switch (inByte)
{
case '\n': // end of text
input_line [input_pos] = 0; // terminating null byte
// terminator reached! process input_line here ...
process_data (input_line);
// reset buffer for next time
input_pos = 0;
break;
case '\r': // discard carriage return
break;
default:
// keep adding if not full ... allow for terminating null byte
if (input_pos < (MAX_INPUT - 1))
input_line [input_pos++] = inByte;
break;
} // end of switch
} // end of processIncomingByte
void loop()
{
// if serial data available, process it
while (Serial.available () > 0)
processIncomingByte (Serial.read ());
// do other stuff here like testing digital input (button presses) ...
} // end of loop
In process_data
in my example is where you would call atoi
to convert the incoming string into an int (or atol
if it is going to be longer).
-
free(NULL)
is ok; per man malloc revoid free(void *ptr)
, "If ptr is NULL, no operation is performed."James Waldby - jwpat7– James Waldby - jwpat72015年08月02日 22:42:46 +00:00Commented Aug 2, 2015 at 22:42 -
Ach, you are right. Still, a pointless thing to do in
setup
. Post amended.2015年08月02日 22:58:07 +00:00Commented Aug 2, 2015 at 22:58
You could have a look at this.
It's a python program which does record/playback of key-presses, through an UNO.
It already implements:
- serial communication with error checking
- ACK: each message has its own ID, so you can keep track of what was lost, should anything bad happen
- synchronization, in case your Arduino is powered up after the python program is started