Go Down

Topic: arduino restarts with incoming Serial data..help? (Read 2127 times) previous topic - next topic

StillaNoob

Nov 29, 2010, 02:28 pm Last Edit: Nov 29, 2010, 02:28 pm by keyvleon Reason: 1
hi! im doing an LED Matrix Email Notifier which involves using python script.

the python script fetches the number of unread emails from my Gmail account every few minutes, and then sends it to my arduino (through pySerial extension). The arduino identifies the data, converts it into displays.

the problem is:
whenever python sends serial data ,my Arduino freezes up and restarts itself, it didn't receive any data at all.

but it got the data fine when i tried sending some random values through the serial monitor.

help!any idea why this happened?

python script taken from: http://kodeclutz.blogspot.com/2009/02/gmail-notifier-on-arduino.html
Code: [Select]

import httplib
import getpass
import base64
import re
import time
import serial

INTERVAL = 1  # check every INTERVAL minutes

serv = 'mail.google.com'
path = '/mail/feed/atom'

auth = base64.encodestring(
               '%s:%s'%(raw_input('Username: '),
               getpass.getpass()))

def count(data):
matches = re.findall('<fullcount>([0-9]+)</fullcount>', data)
if len(matches) == 0:
    print 'Error in parsing feed, check user name and password are correct'
    return 0
return int(matches[0])

def getfeed():
print 'Checking...'
conn = httplib.HTTPSConnection(serv)
conn.putrequest('GET', path)
conn.putheader('Authorization', 'Basic %s'%auth)
conn.endheaders()
return conn.getresponse().read()

def writeSer(data):
try:
    ser = serial.Serial('COM6')
    ser.write(data)
except serial.serialutil.SerialException:
    print 'Error writing to serial device'
    raise

last_check = time.time() - INTERVAL*60 # subtract so that we check first time

while True:
   if time.time() - last_check < INTERVAL*60:
       continue
   last_check = time.time()
   msgs = count(getfeed())
   print type(msgs)
   print msgs,'mails'
   writeSer(str(msgs))




LED Matrix
Code: [Select]
//code courtesy of Hari Wiguna
//http://g33k.blogspot.com/

//-- Columns (Negative Cathodes) --
int latchPin1 = 2; //Arduino pin connected to Green Latch 12 ST_CP / RCK of 74HC595
int clockPin1 = 3; //Arduino pin connected to Yellow Clock 11 SH_CP / SCK of 74HC595
int dataPin1 = 4;  //Arduino pin connected to Blue Data 14 DS / SI of 74HC595

//-- Rows (Positive Anodes) --
int latchPin2 = 5; //Arduino pinn connected to Green Latch 12 ST_CP / RCK of 74HC595
int clockPin2 = 6; //Arduino pin connected to Yellow Clock 11 SH_CP / SCK of 74HC595
int dataPin2 = 7;  //Arduino pin connected to Blue Data 14 DS / SI of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[8][4]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8; // I will refer to each group of 8 columns (represented by one matrix) as a Zone.
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

//=== F O N T ===
// Font courtesy of aspro648
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203747843/22
// First char is @, next is A, B, etc.  Only lower case, no symbols.  
// The @ will display as space character.
byte alphabets[][5] = {
 {0,0,0,0,0},                  //'.' but replaced as 'blank,space'
 {1, 6, 8, 48, 64},            //'/'
 {62, 69, 73, 81, 62},         //0 - zero
 {0, 33, 127, 1, 0},           //1
 {49, 67, 69, 73, 49},         //2
 {34, 65, 73, 73, 54},         //3
 {24, 104, 8, 127, 8},         //4
 {114, 73, 73, 73, 70},        //5
 {62, 73, 73, 73, 38},         //6
 {64, 64, 71, 72, 112},        //7
 {54, 73, 73, 73, 54},         //8
 {50, 73, 73, 73, 62},         //9
 {0, 54, 54, 0, 0},            //:
 {0, 53, 54, 0, 0},            //;
 {8, 28, 54, 99, 65},          //<
 {34, 34, 34, 34, 34},         //=
 {65, 99, 54, 28, 8},          //>
 {32, 64, 77, 72, 48},         //?
 {62, 77, 85, 93, 60},        //@
 {31, 36, 68, 36, 31},            //A
 {127, 73, 73, 73, 54},      //B
 {62, 65, 65, 65, 34},            //C
 {127, 65, 65, 34, 28},      //D
 {127, 73, 73, 65, 65},        //E
 {127, 72, 72, 72, 64},      //F
 {62, 65, 65, 69, 38},            //G
 {127, 8, 8, 8, 127},            //H
 {0, 65, 127, 65, 0},            //I
 {2, 1, 1, 1, 126},            //J
 {127, 8, 20, 34, 65},            //K
 {127, 1, 1, 1, 1},            //L
 {127, 32, 16, 32, 127},      //M
 {127, 32, 16, 8, 127},      //N
 {62, 65, 65, 65, 62},            //O - not zero
 {127, 72, 72, 72, 48},      //P
 {62, 65, 69, 66, 61},            //Q
 {127, 72, 76, 74, 49},      //R
 {50, 73, 73, 73, 38},            //S
 {64, 64, 127, 64, 64},      //T
 {126, 1, 1, 1, 126},            //U
 {124, 2, 1, 2, 124},            //V
 {126, 1, 6, 1, 126},            //W
 {99, 20, 8, 20, 99},            //X
 {96, 16, 15, 16, 96},            //Y
 {67, 69, 73, 81, 97},            //Z
};

//=== S E T U P ===

void setup() {
 
 Serial.begin(9600);
 
 pinMode(latchPin1, OUTPUT);
 pinMode(clockPin1, OUTPUT);
 pinMode(dataPin1, OUTPUT);

 pinMode(latchPin2, OUTPUT);
 pinMode(clockPin2, OUTPUT);
 pinMode(dataPin2, OUTPUT);
 
 //-- Clear bitmap --
 for (int row = 0; row < 8; row++) {
   for (int zone = 0; zone <= maxZoneIndex; zone++) {
     bitmap[row][zone] = 0;
   }
 }
}

//=== F U N C T I O N S ===

// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
 for (int row = 0; row < 8; row++) {
   int rowbit = 1 << row;
   digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
   shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

   //-- Start sending column bytes --
   digitalWrite(latchPin1, LOW);  //Hold latchPin LOW for as long as we're transmitting data

   //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
   for (int zone = maxZoneIndex; zone >= 0; zone--) {
     shiftOut(dataPin1, clockPin1, MSBFIRST, bitmap[row][zone]);
   }

   //-- Done sending Column bytes, flip both latches at once to eliminate flicker
   digitalWrite(latchPin1, HIGH);  //Return the latch pin high to signal chip that it no longer needs to listen for information
   digitalWrite(latchPin2, HIGH);  //Return the latch pin high to signal chip that it no longer needs to listen for information
   
   //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
   delayMicroseconds(500);
   
 }
}

// Converts row and column to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
 int zone = col / 8;
 int colBitIndex = col % 8;
 byte colBit = 1 << colBitIndex;
 if (isOn)
   bitmap[row][zone] =  bitmap[row][zone] | colBit;
 else
   bitmap[row][zone] =  bitmap[row][zone] & (~colBit);
}

// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup(){
 
 byte email;
 
 if (Serial.available() > 0) {email = Serial.read();}
 else {email = 0;}
 
 char msg[6];
 sprintf ( msg, "%d mails", email );

 for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
 {
   int alphabetIndex = msg[charIndex] - '.';          // The Fonts starts from ascii table of '/' until 'Z'. refer to ascii table here - http://www.asciitable.com
   if (alphabetIndex < 0) alphabetIndex=0;
   
   //-- Draw one character of the message --
   // Each character is only 5 columns wide, but I loop two more times to create 2 pixel space betwen characters
   for (int col = 0; col < 7; col++)
   {
     for (int row = 0; row < 8; row++)
     {
       // Set the pixel to what the alphabet say for columns 0 thru 4, but always leave columns 5 and 6 blank.
       bool isOn = 0;
       if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 7-row ) == 1;
       Plot( numCols-1, row, isOn); // We ALWAYS draw on the rightmost column, the shift loop below will scroll it leftward.
     }
     
     //-- The more times you repeat this loop, the slower it would scroll --
     for (int refreshCount=0; refreshCount < 10; refreshCount++)
       RefreshDisplay();

     //-- Shift the bitmap one column to left --
     for (int row=0; row<8; row++)
     {
       for (int zone=0; zone < numZones; zone++)
       {
         // This right shift would show as a left scroll on display because leftmost column is represented by least significant bit of the byte.
         bitmap[row][zone] = bitmap[row][zone] >> 1;
         
         // Roll over lowest bit from the next zone as highest bit of this zone.
         if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 7, bitRead(bitmap[row][zone+1],0));
       }
     }
   }
 }
}

//=== L O O P ===

void loop() {
 AlphabetSoup();
}


oh,and pardon for the bad english =P



billroy

The Arduino restarts when you open the serial port, from Python or any other PC side code.  This is to facilitate reflashing.  Search the forum here, there are many posts.

If you delay in the Python script for a short time (perhaps 1000 ms) before performing IO to the port it may help.

-br
http://bitlash.net
http://entropymouse.com

James C4S

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.com

StillaNoob

#3
Nov 29, 2010, 03:40 pm Last Edit: Nov 29, 2010, 03:41 pm by keyvleon Reason: 1
Quote
The Arduino restarts when you open the serial port, from Python or any other PC side code.  This is to facilitate reflashing.  Search the forum here, there are many posts.

If you delay in the Python script for a short time (perhaps 1000 ms) before performing IO to the port it may help.


open port > delay > and sends IO when arduino done resetting itself?

if so where should i put the delay function? i don't write/understand any python script myself, need a little help here?

Quote
Disable the auto-reset.

that would mean i have to modify my arduino.
if possible, id like to avoid doing that =(

Grumpy_Mike

Quote
if possible, id like to avoid doing that

The only way this is not possible is if you rewrite the serial port drivers on your PC. A task that is probably beyond you.

Graynomad

I've never seen a single line of python code in my life so take this with a grain of salt, but looking at the following lines

   ser = serial.Serial('COM6')
   ser.write(data)

Does the first one open the port? If so add the delay after that and before the write.

______
Rob

Rob Gray aka the GRAYnomad www.robgray.com

JimmyDB

Here is the modified code:
Code: [Select]

import httplib
import getpass
import base64
import re
import time
import serial

ser = serial.Serial()
ser.port = 'COM6'

try:
   ser.open()
   time.sleep(1.5) # run some test to find the proper delay here
except serial.serialutil.SerialException:
   print 'Error opening serial port',ser.port
   raise

INTERVAL = 1  # check every INTERVAL minutes

serv = 'mail.google.com'
path = '/mail/feed/atom'

auth = base64.encodestring('%s:%s'%(raw_input('Username: '),getpass.getpass()))

def count(data):
   matches = re.findall('<fullcount>([0-9]+)</fullcount>', data)
   if len(matches) == 0:
       print 'Error in parsing feed, check user name and password are correct'
       return 0
   return int(matches[0])

def getfeed():
   print 'Checking...'
   conn = httplib.HTTPSConnection(serv)
   conn.putrequest('GET', path)
   conn.putheader('Authorization', 'Basic %s'%auth)
   conn.endheaders()
   return conn.getresponse().read()

def writeSer(data):
   try:
        #ser = serial.Serial('COM6')
        ser.write(data)
   except serial.serialutil.SerialException:
        print 'Error writing to serial device'
        raise

last_check = time.time() - INTERVAL*60 # subtract so that we check first time

while True:
   if time.time() - last_check < INTERVAL*60:
       continue
   last_check = time.time()
   msgs = count(getfeed())
   print type(msgs)
   print msgs,'mails'
   writeSer(str(msgs))



You will probably want to close the serial before the program closes in case the program fails and hangs your serial port, but I will leave that up to you.


JimmyDB

I wrote a little program to test how long it takes for an Uno to begin writing to the serial port after it is reset using the ugly code below.  The results showed that it took from 1.1089 to 1.1093 seconds +- 0.0001 seconds for the Arduino Uno to startup and begin running a small amount of code.  I have no doubt that the longer the code is, the longer the uC will take to initialize it.  So, if this hasn't been documented before, expect an Uno to take AT LEAST 1.11 seconds to initialize.

Python
Code: [Select]

# Written to determine how long an Arduino Uno takes
# to initialize from a RESET.

import serial
import time

# Configure Serial Port Settings
ser = serial.Serial()
ser.baudrate = 115200
ser.timeout = 1
ser.writeTimeout = 2
ser.port = 'COM25'

# Initialize Variables
a = []
b = 0

for x in range(0,25):          # Run test 25 times
   start = time.time()
   ser.open()
   while ser.inWaiting()==0:
       time.sleep(0.0001)     # Look for Serial data every 0.0001 seconds
   finish = time.time()       # Determine how long the reset took
   ser.close()
   a.append(finish-start)     # Add this runs time to the list

a.sort()                       # Sort list from low to high
for item in a:
   b += item
print "Average Time:",b / len(a)
print "Lowest Time :",a[0]
print "Highest Time:",a[-1]


Arduino
Code: [Select]

void setup() {
 Serial.begin(115200);
}

void loop() {
 Serial.println("x");
}



So, for real world testing, you may want to change your code as below just for testing and then comment out my added line later...

Arduino
Code: [Select]

 byte email;
 Serial.println("x"); // Comment this out later
 if (Serial.available() > 0) {email = Serial.read();}
 else {email = 0;}

Bobnova

First a disclaimer:  This is going to require causing physical damage to your arduino if you do it my way.  On my boards (BBB and RBBB) i could mod the USB-BUB adapter.

What you'll need to do if you want to do it in hardware is find the trace that goes from the FTDI chip (or the small atmega chip on the Uno) to the reset wiring of the atmega.  Once you find it, cut it.  Make sure you cut between FTDI and the rest of the reset wiring, otherwise you may well disable the reset button as well.  Presto!  No more auto reset.
Downside:  You have to manually hit the reset button to upload a sketch now :(

It'd be nice to have a jumper or a little switch to set whether it auto-resets or not, maybe that'll be included in the Uno2.

MobileWill

#9
Dec 02, 2010, 05:28 am Last Edit: Dec 02, 2010, 05:29 am by wgarrido Reason: 1
I have found that using serial proxy for some reason doesn't cause the Arduino to reset on connection. But if you use it make sure and use the tinkerproxy version that has all the fixes.
Current Projects:                    Arduinos:
Security Robot Tank               Uno
Security Robot II 4WD            Mega2560

http://mobilewill.blogspot.com

StillaNoob

Thanks JimmyDB you rock! your modified code works out well and i do not have to modify my arduino! i'll make sure credit you for your help when my project is done =).

and id like to thank everybody as well for the great response, this is a great community =)

Go Up