بايثون، ويبوبي، وراسبيري باي
-
20-12-2019 - |
سؤال
أحاول التحكم في سيارتي Raspberry Pi عبر الاتصال اللاسلكي وwebiopi.تعمل الوظيفة الأساسية بشكل جيد - لديك واجهة حيث أنقر فوق fwd وستتحرك السيارة للأمام وعندما أحرر الزر ستتوقف.
أريد الآن دمج مستشعر المسافة بالموجات فوق الصوتية بحيث عندما أقود السيارة للأمام، يجب أن تتوقف السيارة عندما يكون هناك شيء أمامها.لقد قمت بذلك حيث عندما أنقر على الزر fwd، ستقود السيارة وتتوقف عندما يكون هناك شيء ما في النطاق ولكنها ستتوقف فقط عندما يكون هناك شيء ما في النطاق وليس عندما أحرر الزر.حلقة while الخاصة بي تتكرر بطريقة ما (عالقة) ولا تقرأ وظيفة زر التحرير من webiopi.
هل يمكن لأي شخص أن يساعدني - لقد كنت أقوم بذلك منذ أيام ولست متأكدًا من الخطأ الذي أرتكبه :-(
هذه هي الحلقة من برنامج python النصي الخاص بي:
def go_forward(arg):
global motor_stop, motor_forward, motor_backward, get_range
print "Testing"
print mousefwd()
while (arg) == "fwd":
print (arg)
direction = (arg)
dist = get_range()
print "Distance %.1f " % get_range()
if direction == "fwd" and get_range() < 30:
motor_stop()
return
else:
motor_forward()
وهنا هو الكود من استدعاء وظيفة webiopi الخاص بي:
function go_forward() {
var args = "fwd"
webiopi().callMacro("go_forward", args);
}
function stop1() {
var args = "stop"
webiopi().callMacro("go_forward", args);
webiopi().callMacro("stop");
}
هذه هي الطريقة التي أستخدمها الآن ولكني ما زلت لا أعمل (أنا مستجد تمامًا :-)) ) :
def go_forward(arg):
global motor_stop, motor_forward, motor_backward, get_range
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % get_range()
if get_range() < 30:
motor_stop()
elif direction == "fwd":
motor_forward()
else:
motor_stop()
ربما خطوة طفيفة إلى الأمام.تأكد من أن webipi يستخدم "الحلقة" الخاصة به وقمت بإضافة رمز الحلقة للتحقق من حالة GPIO للمحرك والمسافة وإذا كان المحرك يعمل وإذا كانت المسافة قصيرة جدًا فتوقف.تتحرك السيارة الآن عندما أضغط على الزر الأمامي وتتوقف عندما أتركه وعندما تتحرك للأمام وتكون المسافة أقل من 30 سم ستتوقف.المشكلة الوحيدة هي أنه عندما تكون المسافة قصيرة جدًا وأضغط على الزر "إعادة التوجيه بسرعة كبيرة" عدة مرات ، أحصل الآن على "gpio.output (Echo ، 1) _webiopi.gpio.invaliddirection:قناة GPIO ليست خطأ OUTPUT :-( .
يبدو الكود الآن كالتالي:
def go_forward(direction):
motor_forward()
def loop():
if get_range() < 30 and GPIO.digitalRead(M1) == GPIO.HIGH:
stop()
print "stop"
sleep(1)
المحلول
سأجيب على مشكلتك الرئيسية في دقيقة واحدة، ولكن أولاً أريد أن أذكر شيئًا تفعله كمبتدئ في لغة بايثون، وهو ما يجعل حياتك أكثر تعقيدًا مما ينبغي.
ليست هناك حاجة ل global
البيان الذي لديك في بداية وظيفتك.في بايثون، ما عليك سوى استخدام global
بيان إذا كنت تريد يكتب إلى متغير عالمي.إذا كان كل ما عليك فعله هو يقرأ المتغير، أو استدعاء الدالة، ثم ليست هناك حاجة ل global
إفادة.سيتم البحث عن أي أسماء مستخدمة في وظيفتك، سواء كانت أسماء متغيرات أو أسماء دوال، بالترتيب التالي:محلي، مغلق، عالمي، مدمج."محلي" يعني الأسماء المحددة داخل وظيفتك، مثل your direction
عامل."الإحاطة" هي قاعدة تستخدم عند تعريف دالة داخل دالة أخرى.يعد هذا مفيدًا في العديد من المواقف، ولكنه موضوع متقدم بعض الشيء ولا داعي للقلق بشأنه في الوقت الحالي."عام" يعني أسماء (المتغيرات أو الوظائف أو الفئات) المحددة في المستوى الأعلى لبرنامجك - مثل motor_stop
وظيفة من بين أمور أخرى.وأخيرًا، تعني كلمة "builtin" الأسماء المدمجة في لغة Python، مثل str
أو int
أو file
.
لذلك إذا تركت global
بيان، ثم ستبحث بايثون عن الاسم motor_stop
(وأسماء الوظائف الأخرى) على النحو التالي:
- محلي: هل يوجد
motor_stop
المحددة في هذه الوظيفة؟لا.المضي قدمًا. - أرفق: هل هذه الوظيفة محددة داخل وظيفة أخرى؟لا، لذا فإن قاعدة "الإرفاق" لا تنطبق.المضي قدمًا.
- عالمي: هل يوجد
motor_stop
المحددة في المستوى الأعلى للبرنامج؟نعم.وجدته. - (مدمج):لم يتم التحقق من هذه القاعدة مطلقًا، لأنه تم العثور على الاسم بواسطة القاعدة "العالمية".
يتم تعريف جميع وظائفك في المستوى الأعلى لبرنامجك، وبالتالي فإن القاعدة "العالمية" ستجدها دون الحاجة إلى global
إفادة.هذا ينبغي أن يجعل حياتك أسهل قليلا.
والآن بالنسبة لسؤالك الرئيسي:لماذا يتكرر الكود الخاص بك إلى الأبد.وذلك لأن شرط الاختبار الخاص بك while
لن تصبح الحلقة كاذبة أبدًا.أنت تقوم بالتكرار while direction == "fwd"
, والكود الموجود داخل while
الحلقة لا تغير أبدًا direction
عامل.لذلك في كل مرة تصل إلى نهاية الحلقة، فإنها تعود لاختبار الحالة مرة أخرى.ال direction
المتغير لا يزال يحتوي على السلسلة "fwd"
, ، وهكذا يتم تشغيل حلقة while مرة ثانية.ثم direction
المتغير لا يزال يحتوي على السلسلة "fwd"
, ، وهكذا يتم تشغيله للمرة الثالثة.وهلم جرا وهلم جرا.
طريقة واحدة للخروج while
حلقة عندما تريد الخروج سيكون لضبط direction
متغير إلى شيء آخر، مثل "stop"
, ، عندما تريد التوقف.(على سبيل المثال، بعد الاتصال motor_stop()
).هناك طريقة أخرى تتمثل في استخدام return
بيان للخروج من الوظيفة عند هذه النقطة.لكن اقتراحي سيكون استخدام break
البيان بدلاً من ذلك ، مما يعني "في هذه المرحلة ، الخروج على الفور من الحلقة التي أنا فيها." إنه يعمل على كليهما while
حلقات و for
الحلقات، وهي عبارة مفيدة جدًا يجب معرفتها.يبدو أنك تريد الخاص بك while
حلقة للخروج في أي وقت تتصل فيه motor_stop()
, ، إذن هناك مكانان يمكنك وضعهما break
إفادة:
def go_forward(arg):
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % get_range()
if get_range() < 30:
motor_stop()
break
elif direction == "fwd":
motor_forward()
# No break statement here, so the while loop continues
else:
motor_stop()
break
هناك بعض التغييرات الأخرى التي أقترح إجراؤها.أولا، اتصل get_range()
ثلاث مرات في حلقتك، لكنك في الحقيقة تحتاج إلى الاتصال بها مرة واحدة فقط.لقد قمت بالفعل بتعيين نتائجها إلى أ dist
متغير، فلماذا لا تستخدم هذا المتغير؟
def go_forward(arg):
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % dist
if dist < 30:
motor_stop()
break
elif direction == "fwd":
motor_forward()
# No break statement here, so the while loop continues
else:
motor_stop()
break
وثانياً، لا يوجد طريق إلى داخل while
حلقة ل direction
لا ليكون "fwd"، وبالتالي فإن النهائي else
غير ضروري، ويمكن أن تصبح وظيفتك:
def go_forward(arg):
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % dist
if dist < 30:
motor_stop()
break
else:
motor_forward()
وأخيرًا، لديك معلمة دالة مسماة arg
, ، وهو الاسم الذي لا يخبرك شيئًا عن الغرض من استخدامه.يمكنك تعيينه على الفور إلى متغير يسمى direction
, ، وهو اسم أفضل بكثير.فلماذا لا تستخدم ذلك كاسم المعلمة في المقام الأول؟لا توجد قاعدة تنص على معلمات الوظيفة يجب يُطلق عليه "arg" ؛يمكن تسميتها بأي شيء تريده (باستثناء إحدى الكلمات المحجوزة في Python مثل break
أو if
).لذلك دعونا نعطي وظيفتك اسم معلمة أكثر وضوحًا، وهذا من شأنه تبسيطها بشكل أكبر:
def go_forward(direction):
print "Testing"
while direction == "fwd":
print direction
dist = get_range()
print "Distance %.1f " % dist
if dist < 30:
motor_stop()
break
else:
motor_forward()
هناك.هذا أسهل بكثير في القراءة والفهم، ويجب أن يحل المشكلة التي كنت تراها في جهازك while
لا تخرج الحلقة عندما تقترب السيارة كثيرًا من جسم ما.
(لا تزال هناك مشكلة واحدة محتملة يمكنني رؤيتها، وهي أن الحلقة أثناء القيادة قد لا تخرج أثناء قيادة السيارة للأمام، على الرغم من أنك حررت زر "الأمام" - ولكن يجب أن أرى motor_forward()
رمز لمعرفة كيفية حل هذا واحد.قد يكون الأمر بسيطًا مثل وضع ملف break
بيان بعد motor_forward()
, ، وفي هذه الحالة لن تكون هناك حاجة حقًا إلى أ while
حلقة على الإطلاق - ولكن يجب أن أعرف كيف motor_forward()
يتفاعل الكود مع webiopi وكيفية عمل كود التعامل مع الأحداث الخاص بـ webiopi.لا أعرف أيًا منها الآن، لذا سأجيب على المشكلات التي يمكنني الإجابة عليها الآن حتى لو كانت إجابتي غير كاملة، بدلاً من تركك بدون إجابة على الإطلاق.)
تحرير بواسطة مارك: إليك رمز motor_forward:
def motor_forward():
GPIO.output(M1, GPIO.HIGH)
GPIO.output(M2, GPIO.LOW)
string = "echo 0=130 > /dev/servoblaster"
os.system(string)
نصائح أخرى
جرب هذا - تتوقف دائما على المدى ولكن قد ترغب في التوقف عن الاتجاه
giveacodicetagpre.btw أنت لا تحتاج إلى Arg (Arg) فقط عند الرجوع إليه
طباعة Arg
الشجاعة في توقيع المكالمات موجودة لإظهار لوحة لها وظيفة