সুচিপত্র:
- ধাপ 1: উপাদান সংগ্রহ
- ধাপ 2: রাস্পবেরি পাইতে ওপেনসিভি ইনস্টল করা এবং রিমোট ডিসপ্লে সেট আপ করা
- ধাপ 3: একসাথে অংশগুলি সংযুক্ত করা
- ধাপ 4: প্রথম পরীক্ষা
- ধাপ 5: লেন লাইন সনাক্ত করা এবং শিরোনাম লাইন গণনা করা
- ধাপ 6: পিডি কন্ট্রোল প্রয়োগ করা
- ধাপ 7: ফলাফল
ভিডিও: রাস্পবেরি পাই এবং ওপেনসিভি ব্যবহার করে স্বায়ত্তশাসিত লেন-কিপিং গাড়ি: 7 টি ধাপ (ছবি সহ)
2024 লেখক: John Day | [email protected]. সর্বশেষ পরিবর্তিত: 2024-01-30 08:00
এই নির্দেশাবলীতে, একটি স্বায়ত্তশাসিত লেন রাখার রোবট বাস্তবায়িত হবে এবং নিম্নলিখিত ধাপগুলি অতিক্রম করবে:
- অংশ সংগ্রহ
- সফ্টওয়্যারের পূর্বশর্তগুলি ইনস্টল করা
- হার্ডওয়্যার সমাবেশ
- প্রথম টেস্ট
- লেন লাইন সনাক্ত করা এবং ওপেনসিভি ব্যবহার করে গাইড লাইন প্রদর্শন করা
- একটি পিডি নিয়ামক বাস্তবায়ন
- ফলাফল
ধাপ 1: উপাদান সংগ্রহ
উপরের ছবিগুলি এই প্রকল্পে ব্যবহৃত সমস্ত উপাদান দেখায়:
- আরসি গাড়ি: আমি আমার দেশের একটি স্থানীয় দোকান থেকে খনি পেয়েছি। এটি 3 টি মোটর (থ্রোটলিংয়ের জন্য 2 এবং স্টিয়ারিংয়ের জন্য 1) দিয়ে সজ্জিত। এই গাড়ির প্রধান অসুবিধা হল যে স্টিয়ারিং "নো স্টিয়ারিং" এবং "ফুল স্টিয়ারিং" এর মধ্যে সীমাবদ্ধ। অন্য কথায়, এটি একটি নির্দিষ্ট কোণে চালিত হতে পারে না, সার্ভো-স্টিয়ারিং আরসি গাড়ির বিপরীতে। আপনি এখান থেকে বিশেষভাবে রাস্পবেরি পাই এর জন্য ডিজাইন করা অনুরূপ গাড়ির কিট খুঁজে পেতে পারেন।
- রাস্পবেরি পাই 3 মডেল বি+: এটি গাড়ির মস্তিষ্ক যা অনেক প্রক্রিয়াকরণ পর্যায় পরিচালনা করবে। এটি একটি কোয়াড কোর 64-বিট প্রসেসরের উপর ভিত্তি করে 1.4 গিগাহার্জ ক্লক করা হয়েছে। আমি এখান থেকে আমার পেয়েছি।
- রাস্পবেরি পাই 5 এমপি ক্যামেরা মডিউল: এটি 1080p @ 30 fps, 720p @ 60 fps এবং 640x480p 60/90 রেকর্ডিং সমর্থন করে। এটি সিরিয়াল ইন্টারফেসকে সমর্থন করে যা সরাসরি রাস্পবেরি পাইতে প্লাগ করা যায়। ইমেজ প্রসেসিং অ্যাপ্লিকেশনগুলির জন্য এটি সর্বোত্তম বিকল্প নয় তবে এটি এই প্রকল্পের জন্য যথেষ্ট এবং এটি খুব সস্তা। আমি এখান থেকে আমার পেয়েছি।
- মোটর ড্রাইভার: ডিসি মোটরের দিক এবং গতি নিয়ন্ত্রণ করতে ব্যবহৃত হয়। এটি 1 টি বোর্ডে 2 ডিসি মোটরের নিয়ন্ত্রণ সমর্থন করে এবং 1.5 এ সহ্য করতে পারে।
- পাওয়ার ব্যাংক (alচ্ছিক): রাস্পবেরি পাই আলাদাভাবে পাওয়ার জন্য আমি একটি পাওয়ার ব্যাংক (5V, 3A রেটযুক্ত) ব্যবহার করেছি। 1 টি উৎস থেকে রাস্পবেরি পাই পাওয়ার জন্য একটি স্টেপ ডাউন কনভার্টার (বক কনভার্টার: 3A আউটপুট কারেন্ট) ব্যবহার করা উচিত।
- 3s (12 V) LiPo ব্যাটারি: লিথিয়াম পলিমার ব্যাটারিগুলি রোবটিক্স ক্ষেত্রে তাদের চমৎকার পারফরম্যান্সের জন্য পরিচিত। এটি মোটর চালককে শক্তি দিতে ব্যবহৃত হয়। আমি এখান থেকে আমার কিনেছি।
- পুরুষ থেকে পুরুষ এবং মহিলা থেকে মহিলা জাম্পার তার।
- ডবল পার্শ্বযুক্ত টেপ: আরসি গাড়িতে উপাদানগুলি মাউন্ট করতে ব্যবহৃত হয়।
- নীল টেপ: এটি এই প্রকল্পের একটি অত্যন্ত গুরুত্বপূর্ণ উপাদান, এটি দুটি লেন লাইন তৈরিতে ব্যবহৃত হয় যার মধ্যে গাড়ি চলবে। আপনি যে কোন রং বেছে নিতে পারেন কিন্তু আমি আশেপাশের পরিবেশের চেয়ে ভিন্ন রং বেছে নেওয়ার পরামর্শ দিচ্ছি।
- জিপ টাই এবং কাঠের বার।
- স্ক্রু ড্রাইভার।
ধাপ 2: রাস্পবেরি পাইতে ওপেনসিভি ইনস্টল করা এবং রিমোট ডিসপ্লে সেট আপ করা
এই পদক্ষেপটি কিছুটা বিরক্তিকর এবং কিছু সময় লাগবে।
ওপেনসিভি (ওপেন সোর্স কম্পিউটার ভিশন) একটি ওপেন সোর্স কম্পিউটার ভিশন এবং মেশিন লার্নিং সফটওয়্যার লাইব্রেরি। লাইব্রেরিতে 2500 এরও বেশি অপ্টিমাইজড অ্যালগরিদম রয়েছে। আপনার রাস্পবেরি পাইতে ওপেনসিভি ইনস্টল করার পাশাপাশি রাস্পবেরি পাই ওএস ইনস্টল করার জন্য এটি খুব সহজবোধ্য গাইডটি অনুসরণ করুন (যদি আপনি এখনও না করেন)। অনুগ্রহ করে মনে রাখবেন যে ওপেনসিভি তৈরির প্রক্রিয়াটি একটি ভাল শীতল ঘরে প্রায় 1.5 ঘন্টা সময় নিতে পারে (যেহেতু প্রসেসরের তাপমাত্রা খুব বেশি হবে!) তাই কিছু চা পান করুন এবং ধৈর্য ধরে অপেক্ষা করুন: ডি।
দূরবর্তী প্রদর্শনের জন্য, আপনার উইন্ডোজ/ম্যাক ডিভাইস থেকে আপনার রাস্পবেরি পাইতে দূরবর্তী অ্যাক্সেস সেটআপ করার জন্য এই নির্দেশিকাটি অনুসরণ করুন।
ধাপ 3: একসাথে অংশগুলি সংযুক্ত করা
উপরের ছবিগুলি রাস্পবেরি পাই, ক্যামেরা মডিউল এবং মোটর ড্রাইভারের মধ্যে সংযোগ দেখায়। দয়া করে মনে রাখবেন যে আমি যে মোটরগুলি ব্যবহার করেছি সেগুলি প্রতিটি 9 V এ 0.35 A শোষণ করে যা মোটর চালকের জন্য একই সময়ে 3 টি মোটর চালানো নিরাপদ করে তোলে। এবং যেহেতু আমি 2 থ্রোটলিং মোটরের গতি (1 পিছন এবং 1 সামনে) ঠিক একইভাবে নিয়ন্ত্রণ করতে চাই, আমি তাদের একই বন্দরের সাথে সংযুক্ত করেছি। আমি মোটর চালককে ডাবল টেপ ব্যবহার করে গাড়ির ডান দিকে বসিয়েছি। ক্যামেরা মডিউলের জন্য, আমি উপরের চিত্রটি দেখানোর মতো স্ক্রু হোলগুলির মধ্যে একটি জিপ টাই ertোকালাম। তারপরে, আমি ক্যামেরাটিকে একটি কাঠের দণ্ডে ফিট করি যাতে আমি ক্যামেরার অবস্থানকে আমার ইচ্ছামত সামঞ্জস্য করতে পারি। যতটা সম্ভব গাড়ির মাঝখানে ক্যামেরা বসানোর চেষ্টা করুন। আমি ক্যামেরাটি মাটির কমপক্ষে 20 সেন্টিমিটার উপরে রাখার পরামর্শ দিচ্ছি যাতে গাড়ির সামনে দৃশ্যের ক্ষেত্রটি আরও ভাল হয়। Fritzing পরিকল্পিত নিচে সংযুক্ত করা হয়।
ধাপ 4: প্রথম পরীক্ষা
ক্যামেরা পরীক্ষা:
একবার ক্যামেরা ইনস্টল হয়ে গেলে, এবং ওপেনসিভি লাইব্রেরি তৈরি হয়ে গেলে, আমাদের প্রথম ছবিটি পরীক্ষা করার সময় এসেছে! আমরা পাই ক্যাম থেকে একটি ছবি তুলব এবং এটি "original.jpg" হিসাবে সংরক্ষণ করব। এটি 2 উপায়ে করা যেতে পারে:
1. টার্মিনাল কমান্ড ব্যবহার করা:
একটি নতুন টার্মিনাল উইন্ডো খুলুন এবং নিম্নলিখিত কমান্ডটি টাইপ করুন:
raspistill -o original.jpg
এটি একটি স্থির চিত্র নেবে এবং এটি "/pi/original.jpg" ডিরেক্টরিতে সংরক্ষণ করবে।
2. কোন পাইথন IDE ব্যবহার করে (আমি IDLE ব্যবহার করি):
একটি নতুন স্কেচ খুলুন এবং নিম্নলিখিত কোড লিখুন:
আমদানি cv2
ভিডিও = cv2. VideoCapture (0) যখন True: ret, frame = video.read () frame = cv2.flip (frame, -1) # ছবিটি উল্লম্বভাবে cv2.imshow ('original', frame) cv2 imwrite ('original.jpg', frame) key = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()
আসুন দেখি এই কোডে কি ঘটেছে। প্রথম লাইনটি আমাদের ওপেনসিভি লাইব্রেরি আমদানি করছে যাতে এর সমস্ত ফাংশন ব্যবহার করা যায়। ভিডিওক্যাপচার (0) ফাংশন এই ফাংশন দ্বারা নির্ধারিত উৎস থেকে একটি লাইভ ভিডিও স্ট্রিমিং শুরু করে, এই ক্ষেত্রে এটি 0 যার অর্থ রাস্পি ক্যামেরা। আপনার যদি একাধিক ক্যামেরা থাকে তবে বিভিন্ন নম্বর স্থাপন করা উচিত। video.read () ক্যামেরা থেকে আসা প্রতিটি ফ্রেম পড়বে এবং "ফ্রেম" নামে একটি ভেরিয়েবলে সংরক্ষণ করবে। ফ্লিপ () ফাংশনটি ই-অক্ষ (উল্লম্বভাবে) এর সাথে ছবিটি ফ্লিপ করবে যেহেতু আমি আমার ক্যামেরাটি বিপরীতভাবে মাউন্ট করছি। imshow () "আসল" শব্দটির নেতৃত্বে আমাদের ফ্রেমগুলি প্রদর্শন করবে এবং imwrite () আমাদের ছবিটি original-j.webp
আমি ওপেনসিভি ফাংশনগুলির সাথে পরিচিত হওয়ার জন্য আপনার ছবিটি দ্বিতীয় পদ্ধতিতে পরীক্ষা করার সুপারিশ করছি। ছবিটি "/pi/original.jpg" ডিরেক্টরিতে সংরক্ষিত আছে। আমার ক্যামেরায় তোলা আসল ছবিটি উপরে দেখানো হয়েছে।
টেস্টিং মোটর:
এই ধাপটি প্রতিটি মোটরের ঘূর্ণনের দিক নির্ধারণের জন্য অপরিহার্য। প্রথমে, মোটর ড্রাইভারের কাজের নীতি সম্পর্কে একটি সংক্ষিপ্ত ভূমিকা দেওয়া যাক। উপরের ছবিতে মোটর ড্রাইভার পিন-আউট দেখায়। A সক্ষম করুন, ইনপুট 1 এবং ইনপুট 2 মোটর A নিয়ন্ত্রণের সাথে যুক্ত। B সক্রিয় করুন, ইনপুট 3 এবং ইনপুট 4 মোটর B নিয়ন্ত্রণের সাথে যুক্ত। দিকনির্দেশনা নিয়ন্ত্রণ "ইনপুট" অংশ দ্বারা এবং গতি নিয়ন্ত্রণ "সক্রিয়" অংশ দ্বারা প্রতিষ্ঠিত হয়। উদাহরণস্বরূপ মোটর A এর দিকনির্দেশনা নিয়ন্ত্রণ করতে, ইনপুট 1 থেকে HIGH (এই ক্ষেত্রে 3.3 V যেহেতু আমরা রাস্পবেরি পাই ব্যবহার করছি) এবং ইনপুট 2 কে LOW সেট করুন, মোটর একটি নির্দিষ্ট দিকে ঘুরবে এবং বিপরীত মানগুলি সেট করে ইনপুট 1 এবং ইনপুট 2 এ, মোটর বিপরীত দিকে ঘুরবে। ইনপুট 1 = ইনপুট 2 = (উচ্চ বা নিম্ন), মোটর চালু হবে না। পিনগুলি সক্ষম করুন রাস্পবেরি (0 থেকে 3.3 V) থেকে একটি পালস প্রস্থ মডুলেশন (PWM) ইনপুট সংকেত নিন এবং সেই অনুযায়ী মোটরগুলি চালান। উদাহরণস্বরূপ, 100% PWM সংকেত মানে আমরা সর্বোচ্চ গতিতে কাজ করছি এবং 0% PWM সংকেত মানে মোটর ঘুরছে না। নিচের কোডটি মোটরের দিকনির্দেশ নির্ধারণ এবং তাদের গতি পরীক্ষা করতে ব্যবহৃত হয়।
আমদানির সময়
RPi. GPIO কে GPIO GPIO.setwarnings (মিথ্যা) হিসাবে আমদানি করুন # স্টিয়ারিং মোটর পিন স্টিয়ারিং_ সক্ষম = 22 # ফিজিক্যাল পিন 15 ইন 1 = 17 # ফিজিক্যাল পিন 11 ইন 2 = 27 # ফিজিক্যাল পিন 13 # থ্রটল মোটর পিন থ্রোটল_এনেবল = 25 # ফিজিক্যাল পিন 22 ইন 3 = 23 # ফিজিক্যাল পিন 16 ইন 4 = 24 # ফিজিক্যাল পিন 18 GPIO.setmode (GPIO. BCM) # GPIO.setup (in1, GPIO.out) GPIO.setup (in2, GPIO.out) GPIO এর পরিবর্তে GPIO নম্বর ব্যবহার করুন। সেটআপ (in3, GPIO.out) GPIO.setup (in4, GPIO.out) GPIO.setup (throttle_enable, GPIO.out) GPIO.setup (steering_enable, GPIO.out) # স্টিয়ারিং মোটর কন্ট্রোল GPIO.output (in1, GPIO উচ্চ) GPIO.output (in2, GPIO. LOW) স্টিয়ারিং = GPIO. PWM (স্টিয়ারিং_এবল, 1000) # সুইচিং ফ্রিকোয়েন্সি 1000 Hz স্টিয়ারিং এ সেট করুন। (স্টপ).output (in4, GPIO. LOW) থ্রোটল = GPIO. PWM (থ্রোটল_এনেবল, 1000) # সুইচিং ফ্রিকোয়েন্সি 1000 Hz থ্রোটলে সেট করুন। % PWM সংকেত-> (0.25 * ব্যাটারি ভোল্টেজ) - চালকের লস স্টিয়ারিং স্টার্ট (100) # মোটর 100% পিডব্লিউএম সিগন্যালে শুরু করে>
এই কোডটি 3 সেকেন্ডের জন্য থ্রোটলিং মোটর এবং স্টিয়ারিং মোটর চালাবে এবং তারপর তাদের বন্ধ করবে। (চালকের ক্ষতি) একটি ভোল্টমিটার ব্যবহার করে নির্ধারণ করা যেতে পারে। উদাহরণস্বরূপ, আমরা জানি যে 100% PWM সংকেত মোটরের টার্মিনালে সম্পূর্ণ ব্যাটারির ভোল্টেজ দিতে হবে। কিন্তু, PWM 100%এ সেট করে, আমি দেখতে পেলাম যে ড্রাইভার 3 V ড্রপ সৃষ্টি করছে এবং মোটর 12 V এর পরিবর্তে 9 V পাচ্ছে (ঠিক আমার যা দরকার!)। ক্ষতি রৈখিক নয় অর্থাৎ 100% ক্ষতি 25% ক্ষতি থেকে খুব আলাদা। উপরের কোডটি চালানোর পরে, আমার ফলাফলগুলি নিম্নরূপ ছিল:
থ্রোটলিং ফলাফল: যদি in3 = HIGH এবং in4 = LOW, থ্রোটলিং মোটরগুলির একটি ক্লক-ওয়াইজ (CW) ঘূর্ণন থাকবে অর্থাৎ গাড়ি এগিয়ে যাবে। অন্যথায়, গাড়ি পিছন দিকে সরে যাবে।
স্টিয়ারিং ফলাফল: যদি in1 = HIGH এবং in2 = LOW হয়, স্টিয়ারিং মোটর তার সর্বোচ্চ বাম দিকে ঘুরবে অর্থাৎ গাড়ি বাম দিকে স্টিয়ার করবে। অন্যথায়, গাড়িটি সঠিকভাবে চালিত হবে। কিছু পরীক্ষা -নিরীক্ষার পর, আমি দেখেছি যে PWM সিগন্যাল 100% না হলে স্টিয়ারিং মোটরটি চালু হবে না (যেমন মোটর সম্পূর্ণভাবে ডান দিকে বা সম্পূর্ণভাবে বাম দিকে চালিত হবে)।
ধাপ 5: লেন লাইন সনাক্ত করা এবং শিরোনাম লাইন গণনা করা
এই ধাপে, গাড়ির চলাচল নিয়ন্ত্রণ করবে এমন অ্যালগরিদম ব্যাখ্যা করা হবে। প্রথম ছবিটি পুরো প্রক্রিয়াটি দেখায়। সিস্টেমের ইনপুট হল ইমেজ, আউটপুট হল থেটা (ডিগ্রীতে স্টিয়ারিং এঙ্গেল)। মনে রাখবেন, প্রসেসিং 1 ইমেজে সম্পন্ন হয়েছে এবং সব ফ্রেমে পুনরাবৃত্তি হবে।
ক্যামেরা:
ক্যামেরা (320 x 240) রেজোলিউশনের সাথে একটি ভিডিও রেকর্ড করা শুরু করবে। আমি রেজোলিউশন কমানোর পরামর্শ দিচ্ছি যাতে আপনি ভাল ফ্রেম রেট (fps) পেতে পারেন কারণ প্রতিটি ফ্রেমে প্রসেসিং টেকনিক প্রয়োগ করার পর fps ড্রপ হবে। নীচের কোডটি প্রোগ্রামের মূল লুপ হবে এবং এই কোডের প্রতিটি ধাপ যোগ করবে।
আমদানি cv2
np video = cv2. VideoCapture (0) video.set (cv2. CAP_PROP_FRAME_WIDTH, 320) # হিসাবে প্রস্থ সেট করুন সত্য: ret, frame = video.read () frame = cv2.flip (frame, -1) cv2.imshow ("original", frame) key = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()
এখানে কোডটি ধাপ 4 এ প্রাপ্ত মূল চিত্রটি দেখাবে এবং উপরের চিত্রগুলিতে প্রদর্শিত হবে।
HSV কালার স্পেসে রূপান্তর করুন:
এখন ক্যামেরা থেকে ফ্রেম হিসেবে ভিডিও রেকর্ডিং নেওয়ার পর, পরবর্তী ধাপ হল প্রতিটি ফ্রেমকে হিউ, স্যাচুরেশন এবং ভ্যালু (HSV) কালার স্পেসে রূপান্তর করা। এটি করার প্রধান সুবিধা হল তাদের আলোকসজ্জার স্তর দ্বারা রঙের মধ্যে পার্থক্য করতে সক্ষম হওয়া। এবং এখানে HSV কালার স্পেসের একটি ভাল ব্যাখ্যা। এইচএসভিতে রূপান্তর নিম্নলিখিত ফাংশনের মাধ্যমে সম্পন্ন করা হয়:
def convert_to_HSV (ফ্রেম):
hsv = cv2.cvtColor (ফ্রেম, cv2. COLOR_BGR2HSV) cv2.imshow ("HSV", hsv) রিটার্ন hsv
এই ফাংশনটি প্রধান লুপ থেকে বলা হবে এবং HSV রঙের স্থানে ফ্রেমটি ফিরিয়ে দেবে। HSV কালার স্পেসে আমার দ্বারা প্রাপ্ত ফ্রেমটি উপরে দেখানো হয়েছে।
নীল রঙ এবং প্রান্ত সনাক্ত করুন:
ইমেজটিকে HSV কালার স্পেসে রূপান্তর করার পর, আমাদের যে রঙটি সম্পর্কে আগ্রহী তা সনাক্ত করার সময় এসেছে (যেমন নীল রঙ যেহেতু এটি লেন লাইনের রঙ)। একটি HSV ফ্রেম থেকে নীল রঙ বের করার জন্য, রঙ, স্যাচুরেশন এবং মান একটি পরিসীমা নির্দিষ্ট করা উচিত। HSV মান সম্পর্কে আরও ভাল ধারণা পেতে এখানে পড়ুন। কিছু পরীক্ষা -নিরীক্ষার পর নীচের কোডে নীল রঙের উপরের এবং নিচের সীমা দেখানো হয়েছে। এবং প্রতিটি ফ্রেমের সামগ্রিক বিকৃতি কমাতে, প্রান্তগুলি কেবল ক্যানি এজ ডিটেক্টর ব্যবহার করে সনাক্ত করা হয়। ক্যানি এজ সম্পর্কে আরও পাওয়া যায় এখানে। একটি নিয়ম হল 1: 2 বা 1: 3 অনুপাত সহ ক্যানি () ফাংশনের পরামিতি নির্বাচন করা।
def detect_edges (ফ্রেম):
lower_blue = np.array ([90, 120, 0], dtype = "uint8") # নীল রঙের নিম্ন সীমা আপার_ব্লু = np.array ([150, 255, 255], dtype = "uint8") # উপরের সীমা নীল রঙের মাস্ক = cv2.in রেঞ্জ (hsv, নিম্ন_ব্লু, উপরের_ব্লু) # এই মুখোশ সব কিছু ফিল্টার করবে কিন্তু নীল # সনাক্ত প্রান্তের প্রান্ত = cv2। ক্যানি (মুখোশ, 50, 100)
এই ফাংশনটি মূল লুপ থেকেও বলা হবে যা এইচএসভি রঙের স্থান ফ্রেমকে একটি প্যারামিটার হিসাবে নেয় এবং প্রান্তিক ফ্রেমটি ফেরত দেয়। আমি যে প্রান্তের ফ্রেমটি পেয়েছি তা উপরে পাওয়া গেছে।
আগ্রহের অঞ্চল নির্বাচন করুন (ROI):
আগ্রহের অঞ্চল নির্বাচন করা শুধুমাত্র ফ্রেমের 1 টি অঞ্চলে ফোকাস করার জন্য গুরুত্বপূর্ণ। এই ক্ষেত্রে, আমি চাই না যে গাড়িটি পরিবেশে প্রচুর আইটেম দেখুক। আমি শুধু চাই গাড়ীটি লেন লাইনে ফোকাস করুক এবং অন্য কিছু উপেক্ষা করুক। P. S: সমন্বয় ব্যবস্থা (x এবং y অক্ষ) উপরের বাম কোণ থেকে শুরু হয়। অন্য কথায়, পয়েন্ট (0, 0) উপরের বাম কোণ থেকে শুরু হয়। y- অক্ষ হচ্ছে উচ্চতা এবং x- অক্ষ হচ্ছে প্রস্থ। নীচের কোডটি শুধুমাত্র ফ্রেমের নিচের অর্ধেকের দিকে ফোকাস করার জন্য আগ্রহের অঞ্চল নির্বাচন করে।
def region_of_interest (প্রান্ত):
উচ্চতা, প্রস্থ = প্রান্ত। আকৃতি # প্রান্তের ফ্রেমের উচ্চতা এবং প্রস্থ বের করুন মাস্ক = np.zeros_like (প্রান্ত) # প্রান্তের ফ্রেমের একই মাত্রা সহ একটি খালি ম্যাট্রিক্স তৈরি করুন # শুধুমাত্র পর্দার নিচের অর্ধেক ফোকাস করুন # এর স্থানাঙ্ক নির্দিষ্ট করুন 4 পয়েন্ট (নীচের বাম, উপরের বাম, উপরের ডান, নীচের ডান) বহুভুজ = np.array (
এই ফাংশনটি প্রান্তিক ফ্রেমটিকে প্যারামিটার হিসেবে গ্রহণ করবে এবং pre টি প্রিসেট পয়েন্ট সহ একটি বহুভুজ আঁকবে। এটি কেবল বহুভুজের ভিতরে কী আছে তার উপর ফোকাস করবে এবং এর বাইরে সবকিছু উপেক্ষা করবে। আমার আগ্রহের ফ্রেমের অঞ্চল উপরে দেখানো হয়েছে।
লাইন বিভাগগুলি সনাক্ত করুন:
হাফ ট্রান্সফর্ম একটি এজ ফ্রেম থেকে লাইন সেগমেন্ট সনাক্ত করতে ব্যবহৃত হয়। হাফ ট্রান্সফর্ম হল গাণিতিক আকারে কোন আকৃতি সনাক্ত করার একটি কৌশল। এটি কিছু সংখ্যক ভোটের ভিত্তিতে বিকৃত হলেও প্রায় কোনো বস্তু সনাক্ত করতে পারে। হাফ ট্রান্সফর্মের জন্য একটি দুর্দান্ত রেফারেন্স এখানে দেখানো হয়েছে। এই অ্যাপ্লিকেশনের জন্য, cv2. HoughLinesP () ফাংশনটি প্রতিটি ফ্রেমে লাইন সনাক্ত করতে ব্যবহৃত হয়। এই ফাংশনটি গ্রহণ করা গুরুত্বপূর্ণ পরামিতিগুলি হল:
cv2. HoughLinesP (ফ্রেম, rho, theta, min_threshold, minLineLength, maxLineGap)
- ফ্রেম: যে ফ্রেমে আমরা লাইন সনাক্ত করতে চাই।
- rho: এটি পিক্সেলের দূরত্বের স্পষ্টতা (সাধারণত এটি = 1)
- থেটা: রেডিয়ানে কৌণিক স্পষ্টতা (সর্বদা = np.pi/180 ~ 1 ডিগ্রী)
- min_threshold: সর্বনিম্ন ভোট এটি একটি লাইন হিসাবে বিবেচনা করা উচিত
- minLineLength: পিক্সেলে লাইনের সর্বনিম্ন দৈর্ঘ্য। এই সংখ্যার চেয়ে ছোট কোনো লাইনকে একটি লাইন বলে মনে করা হয় না।
- maxLineGap: 2 লাইনের মধ্যে পিক্সেলের সর্বোচ্চ ফাঁক 1 লাইন হিসাবে গণ্য করা হবে। (এটি আমার ক্ষেত্রে ব্যবহৃত হয় না যেহেতু আমি যে লেন লাইন ব্যবহার করছি তাতে কোন ফাঁক নেই)।
এই ফাংশনটি একটি লাইনের শেষ বিন্দুগুলি প্রদান করে। হাফ ট্রান্সফর্ম ব্যবহার করে লাইন সনাক্ত করতে আমার প্রধান লুপ থেকে নিম্নলিখিত ফাংশনটি বলা হয়:
def detect_line_segments (cropped_edges):
rho = 1 theta = np.pi / 180 min_threshold = 10 line_segments = cv2. HoughLinesP (cropped_edges, rho, theta, min_threshold, np.array (), minLineLength = 5, maxLineGap = 0) return line_segments
গড় opeাল এবং বাধা (মি, খ):
মনে রাখবেন যে লাইনের সমীকরণ y = mx + b দ্বারা দেওয়া হয়েছে। যেখানে m হল লাইনের opeাল এবং b হল y- ইন্টারসেপ্ট। এই অংশে, হাফ ট্রান্সফর্ম ব্যবহার করে সনাক্ত করা লাইন সেগমেন্টগুলির গড় interাল এবং ইন্টারসেপ্ট গণনা করা হবে। এটি করার আগে, আসুন উপরে দেখানো আসল ফ্রেম ফটোটি দেখে নিই। বাম লেনটি wardsর্ধ্বমুখী বলে মনে হচ্ছে তাই এটি একটি নেতিবাচক opeাল আছে (সমন্বয় সিস্টেম শুরু বিন্দু মনে রাখবেন?)। অন্য কথায়, বাম লেন লাইনে x1 <x2 এবং y2 x1 এবং y2> y1 আছে যা একটি ইতিবাচক opeাল দেবে। সুতরাং, ধনাত্মক opeাল সহ সমস্ত লাইন ডান লেন পয়েন্ট হিসাবে বিবেচিত হয়। উল্লম্ব রেখার ক্ষেত্রে (x1 = x2), opeাল হবে অনন্ত। এই ক্ষেত্রে, আমরা একটি ত্রুটি পেতে প্রতিরোধ করার জন্য সমস্ত উল্লম্ব লাইন এড়িয়ে যাব। এই সনাক্তকরণে আরও নির্ভুলতা যোগ করার জন্য, প্রতিটি ফ্রেম 2 টি সীমানা রেখার মাধ্যমে দুটি অঞ্চলে (ডান এবং বাম) বিভক্ত। সমস্ত প্রস্থ বিন্দু (x- অক্ষ বিন্দু) ডান সীমানা রেখার চেয়ে বড়, ডান লেন গণনার সাথে যুক্ত। এবং যদি সমস্ত প্রস্থ বিন্দু বাম সীমানা রেখার চেয়ে কম হয়, সেগুলি বাম লেন গণনার সাথে যুক্ত। নিম্নোক্ত ফাংশনটি প্রক্রিয়াকরণের অধীনে ফ্রেম নেয় এবং হাফ ট্রান্সফর্ম ব্যবহার করে সনাক্ত করা লেন সেগমেন্টগুলি এবং দুটি লেন লাইনের গড় slাল এবং বাধা প্রদান করে।
def average_slope_intercept (ফ্রেম, লাইন_ সেগমেন্ট):
লেন_লাইনস line_segments এ line_segment এর প্রস্থ * সীমানা: x1, y1, x2, y2 for line_segment: if x1 == x2: print ("skipping vertical lines (slope = infinity)") ফিট = np.polyfit ((x1, x2) চালিয়ে যান, (y1, y2), 1) opeাল = (y2 - y1) / (x2 - x1) বাধা = y1 - (*াল * x1) যদি opeাল <0: যদি x1 <left_region_boundary এবং x2 right_region_boundary এবং x2> right_region_boundary: right_fit। যোগ করুন ((opeাল, বাধা)) left_fit_average = np.average (left_fit, axis = 0) যদি len (left_fit)> 0: lane_lines.append (make_points (frame, left_fit_average)) right_fit_average = np.average (right_fit, axis = 0) যদি len (right_fit)> 0: lane_lines.append (make_points (frame, right_fit_average)) # lane_lines হল একটি 2-D অ্যারে যা ডান এবং বাম লেনের লাইনগুলির সমন্বয় নিয়ে গঠিত # উদাহরণস্বরূপ: lan e_lines =
make_points () গড়_স্লোপ_ইনটারসেপ্ট () ফাংশনের জন্য একটি সহায়ক ফাংশন যা লেন লাইনগুলির সীমাবদ্ধ স্থানাঙ্কগুলি (নীচে থেকে ফ্রেমের মাঝখানে) ফিরিয়ে দেবে।
def make_points (ফ্রেম, লাইন):
উচ্চতা, প্রস্থ, _ = ফ্রেম। peাল, ইন্টারসেপ্ট = লাইন y1 = উচ্চতা # ফ্রেমের নীচে y2 = int (y1 / 2) # ofাল == 0: opeাল = 0.1 x1 = ফ্রেমের মাঝখান থেকে পয়েন্ট তৈরি করুন। int ((y1 - intercept) / slope) x2 = int ((y2 - intercept) / slope) return
0 দ্বারা বিভাজন রোধ করতে, একটি শর্ত উপস্থাপন করা হয়। যদি opeাল = 0 যার অর্থ y1 = y2 (অনুভূমিক রেখা), তাহলে opeালকে 0 এর কাছাকাছি মান দিন। এটি অ্যালগরিদমের কার্যকারিতা প্রভাবিত করবে না এবং এটি অসম্ভব কেস (0 দ্বারা বিভাজন) প্রতিরোধ করবে।
ফ্রেমে লেন লাইন প্রদর্শন করতে, নিম্নলিখিত ফাংশনটি ব্যবহার করা হয়:
def display_lines (ফ্রেম, লাইন, লাইন_ কালার = (0, 255, 0), লাইন_উইথ = 6): # লাইনের রঙ (B, G, R)
line_image = np.zeros_like (ফ্রেম) যদি লাইনগুলো না হয়: লাইনের লাইনের জন্য: x1, y1, x2, y2 লাইনের জন্য: cv2.line (line_image, (x1, y1), (x2, y2), line_color, line_width) line_image = cv2.addWeighted (frame, 0.8, line_image, 1, 1) return line_image
cv2।
cv2.addWeighted (image1, alpha, image2, beta, gamma)
এবং নিম্নলিখিত সমীকরণ ব্যবহার করে আউটপুট ইমেজ গণনা করে:
আউটপুট = আলফা * ইমেজ 1 + বিটা * ইমেজ 2 + গামা
Cv2.addWeighted () ফাংশন সম্পর্কে আরো তথ্য এখানে প্রাপ্ত হয়েছে।
শিরোনাম লাইন গণনা এবং প্রদর্শন করুন:
আমরা আমাদের মোটরগুলিতে গতি প্রয়োগ করার আগে এটি চূড়ান্ত পদক্ষেপ। শিরোনাম লাইনটি স্টিয়ারিং মোটরকে যে দিকে ঘুরাতে হবে এবং থ্রোটলিং মোটরগুলিকে যে গতিতে তারা চালাবে তা দিতে দায়বদ্ধ। শিরোনাম রেখা গণনা করা হচ্ছে বিশুদ্ধ ত্রিকোণমিতি, ট্যান এবং আতন (টান^-1) ত্রিকোণমিতিক ফাংশন ব্যবহার করা হয়। কিছু চরম ঘটনা হল যখন ক্যামেরা শুধুমাত্র একটি লেন লাইন সনাক্ত করে বা যখন এটি কোন লাইন সনাক্ত করে না। এই সমস্ত ক্ষেত্রে নিম্নলিখিত ফাংশনে দেখানো হয়েছে:
def get_steering_angle (ফ্রেম, লেন_লাইন):
উচ্চতা, প্রস্থ, _ = frame.shape যদি len (lane_lines) == 2: # যদি দুটি লেন লাইন সনাক্ত হয় _, _, left_x2, _ = lane_lines [0] [0] # lane_lines অ্যারে থেকে বাম x2 বের করুন _, _, right_x2, _ = lane_lines [1] [0] # এক্সট্রাক্ট ডান x2 লেন_লাইন অ্যারে মধ্য = int (প্রস্থ / 2) x_offset = (left_x2 + right_x2) / 2 - মধ্য y_offset = int (উচ্চতা / 2) এলিফ লেন (lane_lines) == 1: # যদি শুধুমাত্র একটি লাইন ধরা পড়ে x1, _, x2, _ = lane_lines [0] [0] x_offset = x2 - x1 y_offset = int (height / 2) elif len (lane_lines) == 0: # যদি কোন লাইন ধরা না পড়ে x_offset = 0 y_offset = int (height / 2) angle_to_mid_radian = math.atan (x_offset / y_offset) angle_to_mid_deg = int (angle_to_mid_radian * 180.0 / math.pi) steering_angle = angle_to_mid_deg + 90 return
প্রথম ক্ষেত্রে x_offset হল গড় ((ডান x2 + বাম x2) / 2) পর্দার মাঝখান থেকে কতটা আলাদা। y_offset সর্বদা উচ্চতা / 2 হিসেবে নেওয়া হয়। angle_to_mid_radians উপরের শেষ ছবিতে দেখানো "থেটা" এর মতই। যদি স্টিয়ারিং_এঙ্গেল = 90 হয়, এর মানে হল যে গাড়ির একটি শিরোনাম রেখা "উচ্চতা / 2" রেখার উপর লম্ব আছে এবং স্টিয়ারিং ছাড়াই গাড়ি এগিয়ে যাবে। যদি স্টিয়ারিং_এঙ্গল> 90 হয়, তাহলে গাড়িটি ডানদিকে স্টিয়ার করা উচিত অন্যথায় এটি বাম দিকে চালানো উচিত। শিরোনাম লাইন প্রদর্শন করতে, নিম্নলিখিত ফাংশন ব্যবহার করা হয়:
def display_heading_line (ফ্রেম, স্টিয়ারিং_এঙ্গেল, লাইন_ কালার = (0, 0, 255), লাইন_উইথ = 5)
head_image = np.zeros_like (frame) উচ্চতা, প্রস্থ, _ = frame.shape steering_angle_radian = steering_angle / 180.0 * math.pi x1 = int (width / 2) y1 = height x2 = int (x1 - height / 2 / math.tan (steering_angle_radian)) y2 = int (height / 2) cv2.line (head_image, (x1, y1), (x2, y2), line_color, line_width) head_image = cv2.addWeighted (frame, 0.8, head_image, 1, 1) শিরোনাম_ চিত্র ফিরিয়ে দিন
উপরের ফাংশনটি সেই ফ্রেমটি গ্রহণ করে যেখানে শিরোনাম লাইনটি আঁকা হবে এবং ইনপুট হিসাবে স্টিয়ারিং কোণ। এটি হেডিং লাইনের ইমেজ ফিরিয়ে দেয়। আমার ক্ষেত্রে নেওয়া শিরোনাম লাইন ফ্রেম উপরের ছবিতে দেখানো হয়েছে।
সমস্ত কোড একসাথে একত্রিত করা:
কোড এখন একত্রিত করার জন্য প্রস্তুত। নিম্নলিখিত কোড প্রতিটি ফাংশন কলিং প্রোগ্রামের প্রধান লুপ দেখায়:
আমদানি cv2
np video = cv2 হিসাবে ভিডিও আমদানি করুন। ফ্রেম, -1) #ফাংশন কল করা hsv = convert_to_HSV (ফ্রেম) প্রান্ত = detect_edges (hsv) roi = region_of_interest (প্রান্ত) line_segments = detect_line_segments (roi) lane_lines = average_slope_intercept (ফ্রেম, line_segments) lane_lines_lines_line_line_image_line = get_steering_angle (ফ্রেম, লেন_লাইনস) head_image = display_heading_line (lane_lines_image, steering_angle) key = cv2.waitKey (1) if key == 27: break video.release () cv2.destroyAllWindows ()
ধাপ 6: পিডি কন্ট্রোল প্রয়োগ করা
এখন আমাদের মোটরগুলিতে খাওয়ানোর জন্য আমাদের স্টিয়ারিং এঙ্গেল প্রস্তুত আছে। পূর্বে উল্লিখিত হিসাবে, যদি স্টিয়ারিং কোণ 90 এর বেশি হয়, গাড়িটি ডানদিকে ঘুরতে হবে অন্যথায় এটি বাম দিকে ঘুরতে হবে। আমি একটি সাধারণ কোড প্রয়োগ করেছি যা স্টিয়ারিং মোটরকে ডানদিকে ঘুরিয়ে দেয় যদি কোণটি 90 এর উপরে থাকে এবং স্টিয়ারিং কোণটি 90 এর কম হলে (10% PWM) গতিতে থ্রোটলিং গতিতে থাকে কিন্তু আমি অনেক ত্রুটি পেয়েছি। আমি যে প্রধান ত্রুটিটি পেয়েছি তা হল গাড়ি যখন কোন মোড়ের কাছে আসে, স্টিয়ারিং মোটর সরাসরি কাজ করে কিন্তু থ্রোটলিং মোটর জ্যাম হয়ে যায়। আমি থ্রোটলিং স্পিড বাড়ানোর চেষ্টা করেছি (20% PWM) মোড়ে কিন্তু রোবটটি লেন থেকে বের হওয়ার সাথে সাথে শেষ হয়েছে। আমার এমন কিছু দরকার ছিল যা স্টিয়ারিং এঙ্গেল খুব বড় হলে থ্রোটলিং স্পিড অনেক বাড়িয়ে দেয় এবং স্টিয়ারিং এঙ্গেলটি বড় না হলে স্পিড কিছুটা বাড়িয়ে দেয় তারপর গাড়িটি 90 ডিগ্রী (সোজা গতিতে) এগিয়ে যাওয়ার সাথে সাথে প্রাথমিক মানের গতি কমিয়ে দেয়। সমাধান ছিল একটি পিডি নিয়ামক ব্যবহার করা।
পিআইডি কন্ট্রোলার মানে আনুপাতিক, ইন্টিগ্রাল এবং ডেরিভেটিভ কন্ট্রোলার। এই ধরণের রৈখিক নিয়ামক ব্যাপকভাবে রোবটিক্স অ্যাপ্লিকেশনে ব্যবহৃত হয়। উপরের ছবিটি সাধারণ PID প্রতিক্রিয়া নিয়ন্ত্রণ লুপ দেখায়। এই কন্ট্রোলারের লক্ষ্য হল "অন -অফ" কন্ট্রোলারের বিপরীতে সবচেয়ে কার্যকর উপায়ে "সেটপয়েন্ট" এ পৌঁছানো যা কিছু শর্ত অনুযায়ী প্ল্যান্ট চালু বা বন্ধ করে। কিছু কীওয়ার্ড জানা উচিত:
- সেটপয়েন্ট: কাঙ্ক্ষিত মান যা আপনি আপনার সিস্টেমে পৌঁছাতে চান।
- প্রকৃত মূল্য: সেন্সর দ্বারা অনুভূত প্রকৃত মূল্য।
- ত্রুটি: সেটপয়েন্ট এবং প্রকৃত মানের মধ্যে পার্থক্য (ত্রুটি = সেটপয়েন্ট - প্রকৃত মান)।
- নিয়ন্ত্রিত পরিবর্তনশীল: এর নাম থেকে, যে ভেরিয়েবল আপনি নিয়ন্ত্রণ করতে চান।
- Kp: আনুপাতিক ধ্রুবক।
- Ki: অবিচ্ছেদ্য ধ্রুবক।
- Kd: ডেরিভেটিভ ধ্রুবক।
সংক্ষেপে, পিআইডি নিয়ন্ত্রণ ব্যবস্থা লুপ নিম্নরূপ কাজ করে:
- ব্যবহারকারী সিস্টেম পৌঁছানোর জন্য প্রয়োজনীয় সেটপয়েন্ট নির্ধারণ করে।
- ত্রুটি গণনা করা হয় (ত্রুটি = সেটপয়েন্ট - প্রকৃত)।
- P নিয়ামক ত্রুটির মান সমানুপাতিক একটি কর্ম উৎপন্ন করে। (ত্রুটি বৃদ্ধি পায়, পি কর্মও বৃদ্ধি পায়)
- আমি নিয়ামক সময়ের সাথে ত্রুটি সংহত করব যা সিস্টেমের স্থির অবস্থা ত্রুটি দূর করে কিন্তু তার ওভারশুট বৃদ্ধি করে।
- ডি কন্ট্রোলারটি কেবল ত্রুটির জন্য সময় ডেরিভেটিভ। অন্য কথায়, এটি ত্রুটির slাল। এটি ত্রুটির ডেরিভেটিভের সমানুপাতিক একটি ক্রিয়া করে। এই নিয়ামক সিস্টেমের স্থায়িত্ব বৃদ্ধি করে।
- কন্ট্রোলারের আউটপুট হবে তিনটি কন্ট্রোলারের যোগফল। ত্রুটি 0 হলে কন্ট্রোলারের আউটপুট 0 হয়ে যাবে।
পিআইডি কন্ট্রোলারের একটি দুর্দান্ত ব্যাখ্যা এখানে পাওয়া যাবে।
লেন কিপিং গাড়িতে ফিরে গিয়ে, আমার নিয়ন্ত্রিত পরিবর্তনশীল গতি থ্রোটলিং ছিল (যেহেতু স্টিয়ারিংয়ে ডান বা বাম দুটি মাত্র রাজ্য রয়েছে)। এই উদ্দেশ্যে একটি পিডি কন্ট্রোলার ব্যবহার করা হয় যেহেতু ডি অ্যাকশন থ্রোটলিং স্পিড অনেক বাড়িয়ে দেয় যদি ত্রুটি পরিবর্তন খুব বড় হয় (অর্থাৎ বড় বিচ্যুতি) এবং গাড়ির গতি কমিয়ে দেয় যদি এই ত্রুটি পরিবর্তন আসে 0. আমি একটি পিডি বাস্তবায়নের জন্য নিম্নলিখিত পদক্ষেপগুলি করেছি নিয়ামক:
- সেটপয়েন্ট 90 ডিগ্রীতে সেট করুন (আমি সবসময় চাই গাড়ি সোজা চলুক)
- মধ্য থেকে বিচ্যুতি কোণ গণনা করা হয়েছে
- বিচ্যুতি দুটি তথ্য দেয়: ত্রুটি কত বড় (বিচ্যুতির মাত্রা) এবং স্টিয়ারিং মোটরকে কোন দিকে নিতে হবে (বিচ্যুতির চিহ্ন)। যদি বিচ্যুতি ইতিবাচক হয়, তাহলে গাড়িটি ডানদিকে চালানো উচিত অন্যথায় এটি বাম দিকে চালানো উচিত।
- যেহেতু বিচ্যুতি হয় নেতিবাচক বা ইতিবাচক, তাই একটি "ত্রুটি" পরিবর্তনশীল সংজ্ঞায়িত করা হয় এবং সর্বদা বিচ্যুতির পরম মানের সমান।
- ত্রুটি একটি ধ্রুবক Kp দ্বারা গুণিত হয়।
- ত্রুটিটি সময় ভেদ করে এবং একটি ধ্রুবক কেডি দ্বারা গুণিত হয়।
- মোটর গতি আপডেট করা হয় এবং লুপ আবার শুরু হয়।
থ্রোটলিং মোটরের গতি নিয়ন্ত্রণের জন্য নিচের কোডটি প্রধান লুপে ব্যবহৃত হয়:
গতি = 10 # অপারেটিং গতি % PWM তে
# পরিবর্তনশীল প্রতিটি লুপ শেষ করা হবে angel_to_mid_deg পরিবর্তনশীল ত্রুটি = abs (বিচ্যুতি) যদি বিচ্যুতি -5: # 10 -ডিগ্রী ত্রুটি পরিসীমা বিচ্যুতি = 0 ত্রুটি = 0 GPIO.output (in1, GPIO. LOW) GPIO.output (in2, GPIO. LOW) স্টিয়ারিং.স্টপ () এলিফ বিচ্যুতি> 5: # বিচ্যুতি ইতিবাচক হলে GPIO.output (in1, GPIO. LOW) GPIO.output (in2, GPIO. HIGH) স্টিয়ারিং। স্টার্ট (100) এলিফ বিচ্যুতি < -5: # বিচ্যুতি নেতিবাচক হলে GPIO.output (in1, GPIO. HIGH) GPIO.output (in2, GPIO. LOW) স্টিয়ারিং। স্টার্ট (100) ডেরিভেটিভ = কেডি * (ত্রুটি - শেষ ত্রুটি) / * ত্রুটি PD = int (গতি + ডেরিভেটিভ + আনুপাতিক) spd = abs (PD) যদি spd> 25: spd = 25 throttle.start (spd) lastError = error lastTime = time.time ()
যদি ত্রুটি খুব বড় হয় (মাঝখান থেকে বিচ্যুতি বেশি), আনুপাতিক এবং ডেরিভেটিভ ক্রিয়াগুলি উচ্চ হয় যার ফলে উচ্চ থ্রোটলিং গতি হয়। যখন ত্রুটি 0 (মধ্যম থেকে বিচ্যুতি কম), ডেরিভেটিভ ক্রিয়া বিপরীতভাবে কাজ করে (opeাল নেতিবাচক) এবং সিস্টেমের স্থিতিশীলতা বজায় রাখার জন্য থ্রোটলিং গতি কম হয়। সম্পূর্ণ কোড নিচে সংযুক্ত করা হয়েছে।
ধাপ 7: ফলাফল
উপরের ভিডিওগুলি আমার প্রাপ্ত ফলাফল দেখায়। এটির আরও টিউনিং এবং আরও সমন্বয় প্রয়োজন। আমি আমার এলসিডি ডিসপ্লে স্ক্রিনে রাস্পবেরি পাই সংযুক্ত করছিলাম কারণ আমার নেটওয়ার্কে ভিডিও স্ট্রিমিংয়ের উচ্চ বিলম্ব ছিল এবং এটি কাজ করতে খুব হতাশাজনক ছিল, সেই কারণেই ভিডিওতে রাস্পবেরি পাইয়ের সাথে তারের সংযোগ রয়েছে। আমি ট্র্যাক আঁকতে ফেনা বোর্ড ব্যবহার করেছি।
আমি এই প্রকল্পটি আরও ভাল করার জন্য আপনার সুপারিশ শোনার জন্য অপেক্ষা করছি! যেহেতু আমি আশা করি যে এই নির্দেশিকাগুলি আপনাকে কিছু নতুন তথ্য দেওয়ার জন্য যথেষ্ট ভাল ছিল।
প্রস্তাবিত:
রাস্পবেরি পাই এবং ওপেনসিভি ব্যবহার করে রিয়েল-টাইম রুবিক্স কিউব চোখ বাঁধা সমাধানকারী: 4 টি পদক্ষেপ
রাস্পবেরি পাই এবং ওপেনসিভি ব্যবহার করে রিয়েল-টাইম রুবিক্স কিউব ব্লাইন্ডফোল্ড সলভার: এটি চোখের বেঁধে সমাধানের জন্য তৈরি রুবিকের কিউব টুলের দ্বিতীয় সংস্করণ। প্রথম সংস্করণটি জাভাস্ক্রিপ্ট দ্বারা তৈরি করা হয়েছিল, আপনি দেখতে পারেন RubiksCubeBlindfolded1 প্রকল্পটি আগেরটির মতো, এই সংস্করণটি রং সনাক্ত করতে ওপেনসিভি লাইব্রেরি ব্যবহার করে এবং
রাস্পবেরি পাই - ওপেনসিভি অবজেক্ট ট্র্যাকিং সহ স্বায়ত্তশাসিত মার্স রোভার: 7 টি ধাপ (ছবি সহ)
রাস্পবেরি পাই - ওপেনসিভি অবজেক্ট ট্র্যাকিং সহ স্বায়ত্তশাসিত মার্স রোভার: রাস্পবেরি পাই 3 দ্বারা চালিত, ওপেন সিভি অবজেক্ট রিকগনিশন, অতিস্বনক সেন্সর এবং গিয়ার ডিসি মোটর। এই রোভার ট্রেনিং করা যেকোন বস্তুকে ট্র্যাক করতে পারে এবং যে কোনো ভূখণ্ডে চলে যেতে পারে
রাস্পবেরি পাই এবং AIS328DQTR ব্যবহার করে পাইথন ব্যবহার করে ত্বরণ পর্যবেক্ষণ: 6 টি ধাপ
রাস্পবেরি পাই এবং AIS328DQTR ব্যবহার করে পাইথন ব্যবহার করে ত্বরণ পর্যবেক্ষণ করা: অ্যাক্সিলারেশন সীমিত, আমি মনে করি পদার্থবিজ্ঞানের কিছু আইন অনুসারে।- টেরি রিলি একটি চিতা তাড়া করার সময় আশ্চর্যজনক ত্বরণ এবং গতিতে দ্রুত পরিবর্তন ব্যবহার করে। দ্রুততম প্রাণীটি একবারে উপকূলে শিকারের জন্য তার সর্বোচ্চ গতি ব্যবহার করে। দ্য
HDMI ছাড়া রাস্পবেরি পাই 3 বি তে রাস্পবিয়ান ইনস্টল করা - রাস্পবেরি পাই 3B দিয়ে শুরু করা - আপনার রাস্পবেরি পাই 3: 6 ধাপ সেট আপ করা হচ্ছে
HDMI ছাড়া রাস্পবেরি পাই 3 বি তে রাস্পবিয়ান ইনস্টল করা | রাস্পবেরি পাই 3B দিয়ে শুরু করা | আপনার রাস্পবেরি পাই 3 সেট আপ করা: আপনারা কেউ কেউ জানেন যে রাস্পবেরি পাই কম্পিউটারগুলি বেশ দুর্দান্ত এবং আপনি কেবলমাত্র একটি ছোট বোর্ডে পুরো কম্পিউটারটি পেতে পারেন। 1.2 GHz এ ঘড়ি। এটি পাই 3 কে মোটামুটি 50 রাখে
পুল পাই গাই - এআই চালিত অ্যালার্ম সিস্টেম এবং রাস্পবেরি পাই ব্যবহার করে পুল মনিটরিং: 12 টি ধাপ (ছবি সহ)
পুল পাই গাই - এআই চালিত অ্যালার্ম সিস্টেম এবং রাস্পবেরি পাই ব্যবহার করে পুল মনিটরিং: বাড়িতে একটি পুল থাকা মজাদার, তবে বড় দায়িত্ব নিয়ে আসে। আমার সবচেয়ে বড় দুশ্চিন্তা হল কেউ যদি পুলের কাছাকাছি না থাকে (বিশেষ করে ছোট বাচ্চারা) পর্যবেক্ষণ করে। আমার সবচেয়ে বড় বিরক্তি হল নিশ্চিত করা যে পুলের পানির লাইন কখনই পাম্পের নিচে যাবে না