2009-07-07 15 views
15

मेरे पास एक लूप चलाने वाले मेरे कंप्यूटर से जुड़ा एक Arduino है, प्रत्येक 100   एमएस कंप्यूटर पर सीरियल पोर्ट पर एक मूल्य भेज रहा है।pyserial - एक सीरियल डिवाइस से भेजे गए अंतिम पंक्ति को कैसे पढ़ा जाए

मैं एक पायथन स्क्रिप्ट बनाना चाहता हूं जो केवल कुछ ही सेकंड में सीरियल पोर्ट से पढ़ेगा, इसलिए मैं सिर्फ Arduino से भेजी गई आखिरी चीज़ को देखना चाहता हूं।

आप इसे पिसेरियल में कैसे करते हैं?

यहां कोड है जो मैंने कोशिश की है जो काम नहीं करता है। यह अनुक्रमिक रूप से लाइनों को पढ़ता है।

import serial 
import time 

ser = serial.Serial('com4',9600,timeout=1) 
while 1: 
    time.sleep(10) 
    print ser.readline() #How do I get the most recent line sent from the device? 

उत्तर

27

शायद मैं आपके सवाल का गलत समझ रही है, लेकिन के रूप में यह एक सीरियल लाइन है, तो आप Arduino क्रमिक रूप से से भेजे गए सब कुछ पढ़ने के लिए होगा - यह Arduino में बफ़र हो जाएगा जब तक आप पढ़ सकते हैं यह।

यदि आप एक स्टेटस डिस्प्ले रखना चाहते हैं जो नवीनतम चीज़ को भेजता है - एक थ्रेड का उपयोग करें जो आपके प्रश्न में कोड को शामिल करता है (नींद से कम), और अंतिम पूर्ण रेखा को Arduino से नवीनतम पंक्ति के रूप में पढ़ें।

अद्यतन:mtasic के उदाहरण कोड काफी अच्छा है, लेकिन अगर Arduino जब inWaiting() कहा जाता है एक आंशिक लाइन भेज दिया गया है, तो आप एक छोटा लाइन मिल जाएगा। इसके बजाय, आप क्या करना चाहते हैं अंतिम लाइन last_received में डालना है, और आंशिक रेखा buffer में रखें ताकि इसे लूप के चारों ओर अगली बार जोड़ा जा सके। कुछ इस तरह:

def receiving(ser): 
    global last_received 

    buffer_string = '' 
    while True: 
     buffer_string = buffer_string + ser.read(ser.inWaiting()) 
     if '\n' in buffer_string: 
      lines = buffer_string.split('\n') # Guaranteed to have at least 2 entries 
      last_received = lines[-2] 
      #If the Arduino sends lots of empty lines, you'll lose the 
      #last filled line, so you could make the above statement conditional 
      #like so: if lines[-2]: last_received = lines[-2] 
      buffer_string = lines[-1] 

readline() के उपयोग के बारे में: यहाँ Pyserial प्रलेखन कहने के लिए (थोड़ा स्पष्टता के लिए और() readlines के एक उल्लेख के साथ संपादित) है है:

सावधान का उपयोग करते समय रहो " पढ़ने के लिए लाइन"। सीरियल पोर्ट खोलते समय एक टाइमआउट निर्दिष्ट करें, अन्यथा यह को हमेशा के लिए ब्लॉक कर सकता है यदि कोई न्यूलाइन वर्ण प्राप्त नहीं हुआ है। यह भी ध्यान रखें कि "रीडलाइन()" केवल टाइमआउट के साथ काम करता है। यह एक टाइमआउट होने पर निर्भर करता है और व्याख्या करता है कि ईओएफ (फ़ाइल का अंत) के रूप में।

जो मेरे लिए काफी उचित लगता है!

10
from serial import * 
from threading import Thread 

last_received = '' 

def receiving(ser): 
    global last_received 
    buffer = '' 

    while True: 
     # last_received = ser.readline() 
     buffer += ser.read(ser.inWaiting()) 
     if '\n' in buffer: 
      last_received, buffer = buffer.split('\n')[-2:] 

if __name__ == '__main__': 
    ser = Serial(
     port=None, 
     baudrate=9600, 
     bytesize=EIGHTBITS, 
     parity=PARITY_NONE, 
     stopbits=STOPBITS_ONE, 
     timeout=0.1, 
     xonxoff=0, 
     rtscts=0, 
     interCharTimeout=None 
    ) 

    Thread(target=receiving, args=(ser,)).start() 
+0

खैर कि क्या प्राप्त बफर में है की कुल राशि में पढ़ता है। मेरी धारणा यह है कि पूछताछ यह है कि arduino न्यूलाइन द्वारा क्या भेज रहा है, यह संभवतः प्राप्त बफर आकार से मेल नहीं खाएगा। – JosefAssad

+0

तो आखिरी_रेसेव के पास हमेशा मुझे क्या चाहिए? क्या रीडलाइन के साथ ऐसा करने का कोई तरीका है? – Greg

+0

सही है, आपके प्रश्न के अनुसार – mtasic85

2

टाइमआउट तक रीडलाइन() अवरुद्ध करने के लिए अंतिम कॉल के साथ आपको भेजे गए सभी को पढ़ने के लिए लूप की आवश्यकता होगी। तो:

def readLastLine(ser): 
    last_data='' 
    while True: 
     data=ser.readline() 
     if data!='': 
      last_data=data 
     else: 
      return last_data 
2

थोड़ा सा संशोधन & विनय Sajip के कोड mtasic रहे हैं: जब मैं एक ऐसी ही आवेदन के लिए मुझे के लिए इस कोड काफी उपयोगी पाया

, मैं सभी लाइनों एक धारावाहिक डिवाइस से वापस आ रहा जरूरत है कि समय-समय पर जानकारी भेज देंगे।

मैंने शीर्ष पर पहला तत्व पॉप करने, इसे रिकॉर्ड करने का विकल्प चुना, और फिर शेष तत्वों को नए बफर के रूप में फिर से जुड़ने और वहां से जारी रखने का विकल्प चुना।

मुझे एहसास है कि यह नहीं है जो ग्रेग पूछ रहा था, लेकिन मैंने सोचा कि यह एक साइड नोट के रूप में साझा करने लायक था।

def receiving(ser): 
    global last_received 

    buffer = '' 
    while True: 
     buffer = buffer + ser.read(ser.inWaiting()) 
     if '\n' in buffer: 
      lines = buffer.split('\n') 
      last_received = lines.pop(0) 

      buffer = '\n'.join(lines) 
7

ये समाधान वर्णों की प्रतीक्षा करते समय CPU को हॉग करेंगे।

आप कम से कम एक अवरुद्ध कॉल कर (1)

while True: 
    if '\n' in buffer: 
     pass # skip if a line already in buffer 
    else: 
     buffer += ser.read(1) # this will block until one more char or timeout 
    buffer += ser.read(ser.inWaiting()) # get remaining buffered chars 

को पढ़ने के लिए चाहिए ... और पहले की तरह विभाजित काम करते हैं।

2

एक अनंत लूप के अंदर .inWaiting() का उपयोग समस्याग्रस्त हो सकता है। यह कार्यान्वयन के आधार पर पूरे CPU को हॉग कर सकता है। इसके बजाय, मैं पढ़ने के लिए डेटा के एक विशिष्ट आकार का उपयोग करने की सिफारिश करेंगे। इसलिए इस मामले में निम्नलिखित उदाहरण के लिए किया जाना चाहिए:

ser.read(1024) 
3

यह विधि आपको अलग से अतिरिक्त तर्ज पर इंतजार कर के लिए प्रत्येक पंक्ति के लिए सभी डेटा एकत्र करने के लिए समय समाप्त, और एक अलग टाइमआउट को नियंत्रित करने के लिए अनुमति देता है।

# get the last line from serial port 
lines = serial_com() 
lines[-1]    

def serial_com(): 
    '''Serial communications: get a response''' 

    # open serial port 
    try: 
     serial_port = serial.Serial(com_port, baudrate=115200, timeout=1) 
    except serial.SerialException as e: 
     print("could not open serial port '{}': {}".format(com_port, e)) 

    # read response from serial port 
    lines = [] 
    while True: 
     line = serial_port.readline() 
     lines.append(line.decode('utf-8').rstrip()) 

     # wait for new data after each line 
     timeout = time.time() + 0.1 
     while not serial_port.inWaiting() and timeout > time.time(): 
      pass 
     if not serial_port.inWaiting(): 
      break 

    #close the serial port 
    serial_port.close() 
    return lines 
+0

इसके लिए धन्यवाद। मुझे कोई अन्य जवाब नहीं मिला जो वास्तव में सीरियल प्रतिक्रिया से सभी लाइनों को वापस कर देगा। – Timmay

2

आप ser.flushInput() उपयोग करने वाले सभी धारावाहिक डेटा बफर में है कि बाहर फ्लश करने के लिए कर सकते हैं।

पुराने डेटा को साफ़ करने के बाद, आप सीरियल डिवाइस से नवीनतम डेटा प्राप्त करने के लिए उपयोगकर्ता ser.readline() कर सकते हैं।

मुझे लगता है कि यह यहां अन्य प्रस्तावित समाधानों की तुलना में थोड़ा सा सरल है। मेरे लिए काम किया, उम्मीद है कि यह आपके लिए उपयुक्त है।

2

बहुत ज्यादा जटिलताओं

कारण न्यू लाइन द्वारा या अन्य सरणी जोड़तोड़ से बाइट्स वस्तु विभाजित करने के लिए क्या है? मैं सरलतम विधि है, जो आपकी समस्या का समाधान होगा लिखें:

import serial 
s = serial.Serial(31) 
s.write(bytes("ATI\r\n", "utf-8")); 
while True: 
    last = '' 
    for byte in s.read(s.inWaiting()): last += chr(byte) 
    if len(last) > 0: 
     # Do whatever you want with last 
     print (bytes(last, "utf-8")) 
     last = ''