2016-09-30 5 views
12

मैं वर्तमान में है 2 बटन मेरी रास्पबेरी पाई (इन उन में एलईडी की अंगूठी के साथ होते हैं) और मैं को झुका इस कोडअजगर बटन कार्यों अजीब तरह से नहीं कर रही एक ही

#!/usr/bin/env python 
import RPi.GPIO as GPIO 
import time 

GPIO.setmode(GPIO.BCM) 
GPIO.setwarnings(False) 
GPIO.setup(17, GPIO.OUT) #green LED 
GPIO.setup(18, GPIO.OUT) #red LED 
GPIO.setup(4, GPIO.IN, GPIO.PUD_UP) #green button 
GPIO.setup(27, GPIO.IN, GPIO.PUD_UP) #red button 

def remove_events(): 
     GPIO.remove_event_detect(4) 
     GPIO.remove_event_detect(27) 

def add_events(): 
     GPIO.add_event_detect(4, GPIO.FALLING, callback=green, bouncetime=800) 
     GPIO.add_event_detect(27, GPIO.FALLING, callback=red, bouncetime=800) 

def red(pin): 
     remove_events() 
     GPIO.output(17, GPIO.LOW) 
     print "red pushed" 
     time.sleep(2) 
     GPIO.output(17, GPIO.HIGH) 
     add_events() 

def green(pin): 
     remove_events() 
     GPIO.output(18, GPIO.LOW) 
     print "green pushed" 
     time.sleep(2) 
     GPIO.output(18, GPIO.HIGH) 
     add_events() 

def main(): 
    while True: 
     print "waiting" 
     time.sleep(0.5) 

GPIO.output(17, GPIO.HIGH) 
GPIO.output(18, GPIO.HIGH) 
GPIO.add_event_detect(4, GPIO.FALLING, callback=green, bouncetime=800) 
GPIO.add_event_detect(27, GPIO.FALLING, callback=red, bouncetime=800) 

if __name__ == "__main__": 
    main() 

पर प्रदर्शन करने के लिए कोशिश कर रहा हूँ सतह यह एक काफी आसान लिपि की तरह दिखता है। जब एक बटन प्रेस का पता चला है:

  1. 2 सेकंड की घटनाओं को जोड़ने और

जो आम तौर पर महान जब बाहर काम करता है पर एलईडी की पीठ चालू करने से पहले की घटनाओं

  • प्रिंट संदेश
  • इंतजार को दूर मैं हरा बटन दबाता हूं। मैंने उत्तराधिकार में कई बार कोशिश की और यह असफल होने के बिना काम करता है। लाल के साथ, हालांकि, यह पहली बार अच्छी तरह से काम करता है, और दूसरी बार, लेकिन इसे पूरा करने के बाद यह दूसरा लाल (पिन) चक्र स्क्रिप्ट बस बंद हो जाता है।

    दोनों घटनाओं को ध्यान में रखते हुए काफी समान हैं, मैं यह नहीं समझा सकता कि यह दूसरे लाल बटन के अंत में क्यों विफल रहता है।

    संपादित करें: मैंने क्रमशः लाल और हरे रंग से पिन बदल दिए हैं (या तो अलग पिन के पूरी तरह से या उन्हें स्वैप करें)। किसी भी तरह से, यह हमेशा लाल बटन कोड (वास्तव में अब हरा बटन) एक त्रुटि का कारण बनता है। तो ऐसा लगता है कि यह एक भौतिक लाल बटन समस्या नहीं है, न ही पिन समस्या है, यह सिर्फ गलती के लिए कोड छोड़ देता है ...

  • +0

    शायद 'GPIO.output' कॉलों में से एक ने अपवाद उठाया और फिर' add_events() 'को फिर कभी नहीं बुलाया गया था? – zvone

    +0

    इस मामले पर आपके विचार के लिए धन्यवाद। मैंने क्लॉज को छोड़कर जोड़ा है लेकिन वे ट्रिगर नहीं हुए थे। ऐसा लगता है कि यह नहीं था। – user5740843

    +0

    यह भी समझाएगा कि यह एक बार अच्छा क्यों काम करता है लेकिन हमेशा दूसरे चक्र के अंत में विफल रहता है ... – user5740843

    उत्तर

    9

    मैं अपनी समस्या को अपने रास्पबेरी पीआई 1, मॉडल बी द्वारा पुन: उत्पन्न करने में सक्षम था लाल स्क्रिप्ट प्रेस अनुकरण करने के लिए अपनी स्क्रिप्ट चलाकर जमीन और जीपीआईओ 27 के बीच एक जम्पर केबल को जोड़ना। (वे मेरे विशेष पीआई मॉडल पर पिन 25 और 13 हैं।)

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

    मुझे संदेह है कि आप ईवेंट हैंडलर को हटा रहे हैं और फिर से जोड़ रहे हैं क्योंकि आप उस समय के दौरान कॉलबैक प्राप्त करने के बारे में चिंतित हैं जब आप बटन दबा रहे हैं। ऐसा करने की कोई आवश्यकता नहीं है। जीपीआईओ मॉड्यूल जीपीआईओ कार्यक्रमों की निगरानी के लिए एक एकल मतदान थ्रेड को फैलाता है, और आप कॉल करने वाले जीपीआईओ कार्यक्रमों की संख्या के बावजूद, किसी अन्य कॉल करने से पहले वापस लौटने के लिए एक कॉलबैक की प्रतीक्षा करेंगे।

    मेरा सुझाव है कि आप अपनी स्क्रिप्ट शुरू होने के साथ ही add_event_detect पर अपनी कॉल करें, और कॉलबैक को कभी भी न हटाएं। बस अपनी स्क्रिप्ट से add_events और remove_events (और उनके आमंत्रण) को हटाकर समस्या को ठीक कर दिया जाएगा।

    यदि आप GPIO मॉड्यूल में समस्या के विवरण में रुचि रखते हैं, तो आप C source code for that module पर एक नज़र डाल सकते हैं। RPi.GPIO-0.6.2/source/event_gpio.c फ़ाइल में run_callbacks और remove_callbacks पर एक नज़र डालें। ध्यान दें कि इन दोनों कार्यों में struct callback नोड्स की वैश्विक श्रृंखला का उपयोग किया जाता है। run_callbacks एक नोड को पकड़कर, कॉलबैक का आह्वान करके कॉलबैक श्रृंखला चलाता है, और उसके बाद श्रृंखला में अगले कॉलबैक के उस नोड के लिंक का पालन करता है। remove_callbacks एक ही कॉलबैक श्रृंखला चलेंगे, और एक विशेष जीपीआईओ पिन पर कॉलबैक से जुड़े स्मृति को मुक्त करेगा।यदि remove_callbacks को run_callbacks के बीच में बुलाया जाता है, तो वर्तमान में run_callbacks द्वारा आयोजित नोड को मुक्त किया जा सकता है (और इसकी याददाश्त संभावित रूप से पुन: उपयोग और ओवरराइट की जाती है) अगले नोड को पॉइंटर से पहले किया जाता है।

    कारण आप देख ही लाल बटन के लिए इस समस्या को add_event_detect और remove_event_detect के लिए कॉल के आदेश के कारण होने की संभावना है स्मृति पहले लाल बटन के लिए कॉलबैक नोड द्वारा प्रयोग किया जाता किसी अन्य उद्देश्य के लिए पुन: दावा और पहले ओवरराइट किया जा करने के लिए कारण बनता है हरे रंग के बटन कॉलबैक नोड से उपयोग की गई स्मृति की तुलना में समान रूप से पुनः दावा किया जाता है। हालांकि, आश्वस्त रहें कि समस्या दोनों बटनों के लिए मौजूद है - यह केवल भाग्य है कि पॉइंटर को अगले कॉलबैक नोड पर आने से पहले हरे रंग के बटन कॉलबैक से जुड़ी मेमोरी नहीं बदली जाती है।

    आम तौर पर, वहाँ सामान्य रूप में GPIO मॉड्यूल में कॉलबैक श्रृंखला उपयोग चारों ओर धागा तुल्यकालन के विषय में कमी है, और मैं भी घटनाओं यदि संदेह है इसी तरह की समस्याओं हो सकता है अगर remove_event_detect या add_event_detect कहा जाता है जबकि एक ईवेंट हैंडलर चल रहा है, एक और थ्रेड से हटा दिया जाता है! मैं सुझाव दूंगा कि RPi.GPIO मॉड्यूल के लेखक को यह सुनिश्चित करने के लिए कुछ सिंक्रनाइज़ेशन का उपयोग करना चाहिए कि कॉलबैक श्रृंखला को कॉलबैक के दौरान संशोधित नहीं किया जा सकता है। (शायद, देखना हो श्रृंखला मतदान धागा पर ही संशोधित किया जा रहा है के अलावा, pthread_mutex_lock और pthread_mutex_unlock कॉलबैक श्रृंखला को संशोधित करते हुए इसे मतदान धागा द्वारा उपयोग में है से अन्य धागे को रोकने के लिए इस्तेमाल किया जा सकता है।)

    दुर्भाग्य से , जो वर्तमान में मामला नहीं है, और इस कारण से मेरा सुझाव है कि आप remove_event_detect को पूरी तरह से कॉल करने से बचें यदि आप इससे बच सकते हैं।

    +0

    अच्छा डिबगिंग। आप उल्लेख कर सकते हैं कि आप एक segfault में दुभाषिया को पकड़ने में सक्षम थे, लेकिन अन्यथा यह बहुत पूर्ण जानकारी है। कुछ हद तक क्योंकि जीपीआईओ केवल एक ही समय में एक कार्यक्रम की सेवा करता है, किसी ईवेंट हैंडलर में सोना अच्छा नहीं है। समाधान एक घटना अंत-समय सेट करना है और फिर स्कैनिंग रखना है। कई घटनाओं से बचने का तरीका परीक्षण-और-स्वैप आदेशों का उपयोग करना है, जो एआरएमवी 6 (रास्पबेरी पीआई 1) पर और बाद में स्ट्रेक्स और एलडीआरईएक्स हैं: http://infocenter.arm.com/help/topic/com.arm। doc.dht0008a/DHT0008A_arm_synchronization_primitives.pdf शायद पीआई और पायथन के लिए एक रैपर है। –

    संबंधित मुद्दे