الكود البرمجي للأردوينو
قم برفع البرنامج التالي على الاردوينو:
لتحميل الكود البرمجي اضغط هنا
#include <Servo.h>
Servo leftRightServo; // set a variable to map the servo
int leftRightPos = 0; // set a variable to store the servo position
const int numReadings = 10; // set a variable for the number of readings to take
int index = 0; // the index of the current reading
int total = 0; // the total of all readings
int average = 0; // the average
int echoPin = 11; // the SRF05's echo pin
int initPin = 10; // the SRF05's init pin
unsigned long pulseTime = 0; // variable for reading the pulse
unsigned long distance = 0; // variable for storing distance
/* setup the pins, servo and serial port */
void setup() {
leftRightServo.attach(9);
// make the init pin an output:
pinMode(initPin, OUTPUT);
// make the echo pin an input:
pinMode(echoPin, INPUT);
// initialize the serial port:
Serial.begin(9600);
}
void loop() {
for(leftRightPos = 0; leftRightPos < 180; leftRightPos++) { // going left to right.
leftRightServo.write(leftRightPos);
average=Avg();
Serial.print("X"); // print leading X to mark the following value as degrees
Serial.print(leftRightPos); // current servo position
Serial.print("V"); // preceeding character to separate values
Serial.println(average); // average of sensor readings
}
/*
start going right to left after we got to 180 degrees
*/
for(leftRightPos = 180; leftRightPos > 0; leftRightPos--) { // going right to left
leftRightServo.write(leftRightPos);
average=Avg();
Serial.print("X");
Serial.print(leftRightPos);
Serial.print("V");
Serial.println(average);
}
}
long Avg()
{
for (index = 0; index<=numReadings;index++) {
digitalWrite(initPin, LOW);
delayMicroseconds(50);
digitalWrite(initPin, HIGH);
delayMicroseconds(50);
digitalWrite(initPin, LOW);
pulseTime = pulseIn(echoPin, HIGH);
distance = pulseTime/58;
total = total + distance;
delay(10);
}
average = total/numReadings; // create average reading
if (index >= numReadings) { // reset the counts when at the last item of the array
index = 0;
total = 0;
}
return average;
}
لمحة عن الكود :
يقوم محرك السيرفو بالدوران من 0 إلى 180 درجة و العكس ، ومن خلاله يقوم مستشعر الموجات فوق الصوتية بالمسح الأرضي و الجوي لما يجري داخل منطقة محدودة وهي ابعد ما يستطيع المستشعر التعامل معه.
دالة for تقوم بتغير قيمة زاوية الدوران للمحرك :
for(leftRightPos = 0; leftRightPos < 180; leftRightPos++) {
}
for(leftRightPos = 180; leftRightPos > 0; leftRightPos--){
}
تقوم الدالة ()AVG اعتمادا على القيم التي يتلقاها حساس الموجات فوق الصوتية بحساب المسافة التي يبعد عنها الجسم عن الحساس :
long Avg()
{
for (index = 0; index<=numReadings;index++) {
digitalWrite(initPin, LOW);
delayMicroseconds(50);
digitalWrite(initPin, HIGH);
delayMicroseconds(50);
digitalWrite(initPin, LOW);
pulseTime = pulseIn(echoPin, HIGH);
distance = pulseTime/58;
total = total + distance;
delay(10);
}
average = total/numReadings; // create average reading
if (index >= numReadings) { // reset the counts when at the last item of the array
index = 0;
total = 0;
}
return average;
}
* يمكنك الاطلاع على مشروع نظام الحسّاسات لاصطفاف السيارة لفهم الكود المتعلق بحساس الموجات فوق الصوتية و حساب المسافة , و الدرس الخامس عشر للاطلاع على شرح الكود المتعلق بمحرك السيرفو.
يتم ارسال قيمة المسافة و الزاوية عند هذة القيمة إلى الحاسوب فيقوم البرنامج (Processing IDE) برسم خطوط الرادار باستعمال الدوال المثلثة طبقا للمعلومات المستقبله.
Serial.print("X");
Serial.print(leftRightPos);
Serial.print("V");
Serial.println(average);
برمجة الواجهة الرسومية
الحاسوب بعد ارسال قيم الزاوية و المسافة من الاردوينو الى (processing IDE) ، يتم استقبالها بإستخدام دالة ()SerialEvent .
تقوم ()SerialEvent بقراءة البيانات من المنفذ التسلسلي (serial port) ثم نقوم بوضع قيم الزاوية و المسافة في متغيرات (degree, value). هذة المتغيرات سيتم استخدامها لرسم الرادار، و الخطوط، و الكشف عن الأجسام ، وتغير النصوص .
لعرض البيانات على الشاشة يتم انشاء Arrays لتخزين القيم الحديثة على newValue Array و عمل تحديث للقيم القديمة على oldValue Array . لأن الموقع اتباعا لحركة محرك السيرفو يتغير بإستمرار ، فسنفقد البيانات القديمة التي سيتم عرضها على الشاشة.
int[] newValue = new int[181];
int[] oldValue = new int[181];
لرسم الرادار سيتم كتابة الداله ()drawRadar التي تتكون من دوال ()arc و ()line.
void drawRadar() {
for (int i = 0; i <=6; i++){
noFill();
strokeWeight(1);
stroke(0, 255-(30*i), 0);
arc(radius, radius, (100*i), (100*i),PI,TWO_PI);
fill(250, 103, 0);
noStroke();
text(Integer.toString(radarDist+50), 380, (305-radarDist), 50, 50);
radarDist+=50;
}
radarDist = 0;
for (int i = 0; i <= 6; i++) {
strokeWeight(1);
stroke(0, 55, 0);
line(radius, radius, radius + cos(radians(180+(30*i)))*w, radius + sin(radians(180+(30*i)))*w);
fill(153, 153, 153);
noStroke();
if (180+(30*i) >= 300) {
text(Integer.toString(180+(30*i)), (radius+10) + cos(radians(180+(30*i)))*(w+10), (radius+10) + sin(radians(180+(30*i)))*(w+10), 25,50);
}
else {
text(Integer.toString(180+(30*i)), radius + cos(radians(180+(30*i)))*w, radius + sin(radians(180+(30*i)))*w, 60,40);
}
}
}
ليتم عمل مسح للرادار يتم رسم الخط الذي يتحرك جنب إلى جنب اتباعا لحركة محرك السيرفو بإستخدام الدالة ()setupSweep .
تستخدم الدالة ()setupSweep الدالة ()line التي تستخدم المتغير degree لإعادة رسم الخط لكل درجة.
void setupSweep(){
strokeWeight(7);
if (motion == 0) {
for (int i = 0; i <= 20; i++) {
stroke(0, (10*i), 0);
line(radius, radius, radius + cos(radians(degree+(180+i)))*w, radius + sin(radians(degree+(180+i)))*w);
}
} else { // if going right to left
for (int i = 20; i >= 0; i--) {
stroke(0,200-(10*i), 0);
line(radius, radius, radius + cos(radians(degree+(180+i)))*w, radius + sin(radians(degree+(180+i)))*w);
}
}
}
لإعداد تحديث الأشكال يتم عمل الدالة ()SetupShapes . سنقوم بإستخدام الدالة For loop للتحرك بين القيم التي تم تخزينها بالـ (Arrays (newValue, oldValue
void SetupShapes(){
noStroke();
fill(0,50,0);
beginShape();
for (int i = 0; i < 180; i++) {
x = radius + cos(radians((180+i)))*((oldValue));
y = radius + sin(radians((180+i)))*((oldValue));
vertex(x, y);
}
endShape();
fill(0,110,0);
beginShape();
for (int i = 0; i < 180; i++) {
x = radius + cos(radians((180+i)))*(newValue);
y = radius + sin(radians((180+i)))*(newValue);
vertex(x, y);
}
endShape();
fill(0,170,0);
beginShape();
for (int i = 0; i < 180; i++) {
x = radius + cos(radians((180+i)))*((newValue+oldValue)/2);
y = radius + sin(radians((180+i)))*((newValue+oldValue)/2);
vertex(x, y);
}
endShape();
}
لرسم موقع الاجسام التي تم رصدها ، نقوم بعمل الدالة ()drawObject .التي تستخدم المسافة الملتقطة من مستشعر الموجات فوق الصوتية و بالاشتراك مع الزاوية لرسم الجسم على الرادار.
void drawObject() {
if (firstRun >= 360) {
stroke(250,103,0);
strokeWeight(1);
noFill();
for (int i = 0; i < 180; i++) { if (oldValue - newValue > 35 || newValue - oldValue > 35) {
x = radius + cos(radians((180+i)))*(newValue);
y = radius + sin(radians((180+i)))*(newValue);
ellipse(x, y, 10, 10);
}
}
}
}
وللإطلاع على القيم التي تم استقبالها و النصوص تم إنشاء الدالة ()drawText .
يمكنك تنزيل كود الـ (Processing) المتعلق بالواجهة الرسومية للرادار من هنـا.