Сегодня образовательная робототехника становится все более популярной среди школьников, в связи со своей ярко выраженной практической направленностью. Обучающийся не только формирует свое «инженерное» мышление, связанное со сборкой моделей роботов, но и развивают алгоритмическую компетентность в следствии интегрированного изучения принципов программирования робота и принципов его сборки.
Одной из интересных задач начального уровня становится задача передвижения робота по комнате. В качестве базовой основы возьмем робототехнический комплект Vex IQ и язык программирования RobotC.
Для решения задач по передвижению робота будем использовать стандартную модель Clawbot IQ With Sensors.
Расположение моторов и датчиков.
Motor Ports:
VEX IQ Port 1: leftMotor VEX IQ Port 6: rightMotor VEX IQ Port 10: armMotor VEX IQ Port 11: clawMotor
Sensor Ports:
VEX IQ Port 2: touchLED (Touch LED) VEX IQ Port 3: colorDetector (Color Sensor/Hue Mode) VEX IQ Port 4: gyroSensor (Gyro) VEX IQ Port 7: distanceMM (Distance) VEX IQ Port 8: bumpSwitch (Bumper Switch)
Для путешествия поднимем руку-схват робота, освободив датчик touchLED (Touch LED).
Задание 1
Ехать вперед пока не уткнемся в препятствие. После обнаружения препятствия остановиться.
Дополнительные требования
Обращение к датчикам и моторам осуществите по их именам. К порту 2 присоединён датчик touchLED (Touch LED). Робот начнет ехать после нажатия на данный датчик (1 — нажат, 0 — не нажат). После нажатия на touchLED раздается звуковой сигнал. К порту 8 подсоединён датчик bumpSwitch (Bumper Switch). Робот должен ехать вперед пока не уткнется датчиком bumpSwitch в препятствие, в этом случае датчик bumpSwitch будет нажат и значение переменной данного сенсора будет равно единице (в не нажатом состоянии оно равно 0).
Вариант решения
task main() { while (getTouchLEDValue(touchLED) == 0 {} playSound(soundAirWrench); while(getBumperValue(bumpSwitch) == 0) { setMotorSpeed(leftMotor, 127); setMotorSpeed(rightMotor, 127); sleep(2000); } }
Задание 2
При обнаружении препятствия робот должен развернуться и поехать вперед. Перед разворотом робот должен немного отъехать назад.
Вариант решения
task main() { while (getTouchLEDValue(touchLED) == 0) {} playSound(soundAirWrench); repeat (forever) { if(getBumperValue(bumpSwitch) == 0) { setMotorSpeed(leftMotor, 127); setMotorSpeed(rightMotor, 127); sleep(20); } else { setMotorSpeed(leftMotor, -127); setMotorSpeed(rightMotor, -127); sleep(500); setMotorSpeed(leftMotor, 127); setMotorSpeed(rightMotor, 0); sleep(1500); } } }
Задание 3
Обращение к датчикам и моторам осуществите по их портам. Встретив препятствие, робот отъедет назад и развернется влево.
Вариант решения
task main() { repeat(forever) { if (SensorValue[port8]==0) { motor[port1] = 127; motor[port6]=127; wait1Msec(100); } else { motor[port1] = -60; motor[port6]=-60; wait1Msec(400); motor[port1] = 60; motor[port6]=-60; wait1Msec(400); } } }
Задание 4
Для упрощения программного кода, используйте возможности функций в программном коде. Осуществите поворот случайным образом, скорости моторов при каждом новом развороте должны завесить от случайных чисел.
Дополнительно
Используйте функции:
Srand
void srand(const long nSeedValue)
Генератор псевдослучайных чисел инициализируется с использованием аргумента, переданного как nSeedValue. Для каждого другого начального значения, используемого при вызове srand, можно ожидать, что генератор псевдослучайных чисел генерирует другую последовательность результатов в последующих вызовах rand.
srand (nSysTime) — аргументом генерации может выступить системное время.
Rand
word rand()
Возвращает псевдослучайное целое число в диапазоне от 0 до не менее 32 767 (в зависимости от платформы). Типичным способом генерации псевдослучайных чисел в определенном диапазоне с использованием rand является использование по модулю возвращаемого значения диапазоном диапазона и добавление начального значения диапазона:
- ◦ (значение% 100) находится в диапазоне от 0 до 99
- ◦ (значение% 100 + 1) находится в диапазоне от 1 до 100
- ◦ (значение% 30 + 1985) находится в диапазоне от 1985 до 2014 года
Обратите внимание, однако, что эта модульная операция не генерирует по-настоящему равномерно распределенное случайное число в промежутке, но, как правило, это хорошее приближение для коротких промежутков.
Вариант решения
void move(long lm, long rm, long tm) motor[port1] = lm; motor[port6]= rm; wait1Msec(tm); task main() repeat(forever) { if (SensorValue[port8]==0) { move(127,127,100); } else { move(-60,-60,400); srand(nSysTime); move(rand() % 61 ,-1*rand() % 61,400); } }
Задание 5
Используйте конструкцию робота, в котором датчик расстояния прямо смотрит на правую сторону. Возможно использование Clawbot IQ With Sensors. Переставьте местами датчики colorDetector (Color Sensor/Hue Mode)и distanceMM (Distance). Раздвиньте щупальца схвата, чтобы они не мешали датчику. Зайдите в раздел «Motor and Sensor Setup» и отметьте произведенные изменения. В более идеальном варианте желательно переделать конструкцию чтобы датчик прямо смотрел на стену.
Новая конфигурация датчиков:
#pragma config(Sensor, port2, touchLED, sensorVexIQ_LED) #pragma config(Sensor, port3, distanceMM, sensorVexIQ_Distance) #pragma config(Sensor, port4, gyroSensor, sensorVexIQ_Gyro) #pragma config(Sensor, port7, colorDetector, sensorVexIQ_ColorHue) #pragma config(Sensor, port8, bumpSwitch, sensorVexIQ_Touch) #pragma config(Motor, motor1, leftMotor, tmotorVexIQ, openLoop, driveLeft, encoder) #pragma config(Motor, motor6, rightMotor, tmotorVexIQ, openLoop, reversed, driveRight, encoder) #pragma config(Motor, motor10, armMotor, tmotorVexIQ, openLoop, encoder) #pragma config(Motor, motor11, clawMotor, tmotorVexIQ, openLoop, encoder)
Робот должен двигаться вдоль стенки на заданном расстоянии, которое определяется в момент старта. Датчик расстояния направлен на стенку справа.
Вариант решения
task main() { float u, k=1; int L=SensorValue[port3]; // замер первоначального расстояния while(true) { u=k*(SensorValue[port3]-L); // управляющее воздействие motor[motor1]=60+u; motor[motor6]=60-u; wait1Msec(1); } }
Если SensorValue[port3] = L то робот едет прямо, иначе его скорость корректируется.
Для более устойчивого движения предлагается следующий вариант.
task main() { float u, k1=2, k2=10; int Sold, L; Sold=L=SensorValue[port3]; while(true) { u= k1*(SensorValue[port3]-L) + k2*(SensorValue[port3]-Sold); motor[motor1]=60+u; motor[motor6]=60-u; Sold=SensorValue[port3]; wait1Msec(1); } }
Таким образом, предложенные варианты являются базовыми заданиями, которые можно изучить при решении задач, связанных с передвижением робота. Учащиеся могут экспериментировать с большим количеством вариантов, совершенствуя решения, связанные с функционированием робота.