RobotC VEX / Lego Programming: Как заставить робота выполнять несколько реакций параллельно?
Мне нужно, чтобы мой робот мог использовать ударные переключатели, чтобы любой из них можно было нажимать, и двигатель, соответствующий этому ударному переключателю, будет работать до тех пор, пока нажата ударная кнопка. Проблема в том, что светодиоды горят правильно. Пока работает кодовый блок ударного переключателя, мне нужно, чтобы светодиоды загорались и гасли семь раз на одну секунду каждый раз, когда значение датчика освещенности превышает 400. Как это сделать? Пожалуйста помоги! Мой код размещен ниже:
#pragma config(Sensor, in2, lightSensor, sensorReflection)
#pragma config(Sensor, dgtl3, bumpSwitch, sensorTouch)
#pragma config(Sensor, dgtl4, bumpSwitch2, sensorTouch)
#pragma config(Sensor, dgtl10, ledGreen, sensorLEDtoVCC)
#pragma config(Sensor, dgtl11, ledRed, sensorLEDtoVCC)
#pragma config(Motor, port1, leftMotor, tmotorVex269, openLoop)
#pragma config(Motor, port10, rightMotor, tmotorVex269, openLoop)
task main() {
while(true) {
if (SensorValue(lightSensor) > 400) {
int count = 0;
while (count < 7) {
turnLEDOn(ledGreen);
turnLEDOn(ledRed);
wait(1);
turnLEDOff(ledGreen);
turnLEDOff(ledRed);
count++;
}
}
while (SensorValue(bumpSwitch) == 0 && SensorValue(bumpSwitch2) == 0) {
stopMotor(rightMotor);
stopMotor(leftMotor);
}
while (SensorValue(bumpSwitch2) == 1) {
startMotor(rightMotor, 55);
startMotor(leftMotor, 55);
}
while (SensorValue(bumpSwitch) == 1){
startMotor(rightMotor, -55);
startMotor(leftMotor, -55);
}
}
}
2 ответа
Вы должны положить в подпрограмму.
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
task blink()
{
// Light sensor LED control code
if (SensorValue(lightSensor) > 400)
{
for (int i = 0; i < 7; ++i) {
turnLEDOn(ledGreen);
turnLEDOn(ledRed);
wait1Msec(71); // 1/14 second
turnLEDOff(ledGreen);
turnLEDOff(ledRed);
wait1Msec(71);
}
}
task main()
{
startTask(blink);
while (true)
{
// Light sensor LED control code ...
// Bumper/motor control
if (SensorValue(bumpSwitch) == 1) {
startMotor(rightMotor, -55);
startMotor(leftMotor, -55);
} else if (SensorValue(bumpSwitch2) == 1){
startMotor(rightMotor, 55);
startMotor(leftMotor, 55);
} else {
stopMotor(rightMotor);
stopMotor(leftMotor);
}
}
}
Опыт программирования роботов (хотя я не использовал Robot C) показывает, что для того, чтобы робот запускал две или более сенсорных реакций параллельно, вы должны структурировать программу совсем иначе, чем для одной реакции. Учебное пособие по Robot C не охватывает это и даже не вводит языковые и библиотечные функции, необходимые для этого.
В этом случае вы хотите, чтобы датчик освещенности запускал последовательность включения / выключения светодиода, которая длится в течение 1 секунды, в то время как датчики удара запускают действия двигателя, которые продолжаются до тех пор, пока эти датчики больше не будут сталкиваться.
Проблема здесь заключается в том, что внутреннее управление двигателем while
петли блокируют поток, в основном не давая ему обойтись, чтобы запустить цикл управления светодиодом. Цикл управления светодиодами также блокирует нить на 7 секунд, задерживая запуск контура управления двигателем.
В целом, каждая итерация цикла управления роботом должна считывать датчики, отправлять выходные команды, запоминать любое состояние, которое необходимо обработать позже, а затем повторять цикл, чтобы все части цикла управления запускались в каждом цикле (как можно чаще или при контролируемая скорость). Не блокируйте поток управления, оставаясь во внутренней while
петля, пока датчик не изменится.
Первым шагом является разблокировка контура управления двигателем:
while (true) {
// Light sensor LED control code ...
// Bumper/motor control
if (SensorValue(bumpSwitch) == 1) {
startMotor(rightMotor, -55);
startMotor(leftMotor, -55);
} else if (SensorValue(bumpSwitch2) == 1){
startMotor(rightMotor, 55);
startMotor(leftMotor, 55);
} else {
stopMotor(rightMotor);
stopMotor(leftMotor);
}
}
Теперь ваш текущий светодиодный контрольный код все еще вызывает wait(1)
7 раз. Согласно http://www.robotc.net/support/nxt/ROBOTC-for-Beginners/ wait(1)
ждет 1,0 секунды, поэтому выполнение этой части кода в настоящее время занимает 7 секунд. Это долгое время между проверкой выключателей.
Кроме того, в вашем коде нет существенной задержки между выключением и повторным включением светодиодов, поэтому вы фактически не заметите, что светодиоды погаснут до конца этой последовательности.
Таким образом, второй шаг состоит в том, чтобы исправить код управления светодиода от блокировки цикла управления. В основном есть два подхода (я не знаю, поддерживает ли Robot C первый выбор, но он проще):
- Когда датчик освещенности находится выше порогового значения, и он был ниже порогового значения в предыдущей итерации, то есть он только что перешел, тогда запускается [или "разветвляется"] нить (или задача) для запуска цикла включения / выключения светодиода. Эта нить должна зацикливаться 7 раз: {включите светодиоды,
wait(1.0/14.0)
секунд, выключите светодиоды, затемwait(1.0/14.0)
секунд}. Таким образом, 7 циклов вокруг цикла займут 7 * (1/14 + 1/14) = 1,0 секунды. Я написал это как1.0/14.0
скорее, чем1/14
потому что многие языки программирования вычисляют1/14
в целочисленной математике, уступая0
, в то время как1.0/14.0
использует математику с плавающей точкой. Я не знаю о Роботе С. Или, вы могли бы использоватьwait1Msec(71)
ждать 71 мсек, что составляет около 1/14 секунды. - Используйте переменные для отслеживания последовательности через петлю вспышки-светодиода. Каждый цикл вокруг основного цикла, используйте
if
чтобы проверить эти переменные, сделайте следующий шаг в цикле мигания светодиодов, если пришло время, и обновите эти переменные. Шаги: включите светодиоды, когда он был в исходном состоянии, а датчик освещенности находится выше порогового значения, выключите светодиоды, когда наступит 1/14 секунды, включите светодиоды, когда будет 1/14 секунды. позже... выключите и установите переменные отслеживания в исходное состояние после 14 из этих шагов. Простейшей переменной отслеживания будет счетчик от 0 (начальное состояние) до 14 (выполнение последней фазы индикатора "OFF") и значение системных часов с момента последнего изменения, чтобы вы могли определить, когда часы на 71 мс позже, чем тот. После завершения шага 14 вернитесь к 0. Существуют альтернативы для переменных отслеживания, например, 3 отдельные переменные для определения того, мигает ли он в данный момент, какой из 7 циклов мигания он выполняет в данный момент, находится ли он в фазе ON или OFF того цикл и чтение часов.
Подход №2 сложнее, потому что делать две вещи одновременно сложно. (Люди, которые думают, что могут многозадачны, переписываясь во время вождения, опасно ошибаются.)
Гораздо более простой подход работает, если роботу не нужно запускать контур управления бампером / двигателем во время мигания светодиодов, то есть если он не против не реагировать на бамперы во время мигания светодиодов в течение 1 секунды. Если эти датчики бампера удерживают робота от падения с конца стола, то, что он не отвечает в течение 1 секунды, является плохой новостью. Но если робот нормально нажимает на бампер в течение 1 секунды, пока мигает свет, то часть кода светодиода датчика может выглядеть примерно так:
while (true) {
// Light sensor LED control code
if (SensorValue(lightSensor) > 400) {
for (int i = 0; i < 7; ++i) {
turnLEDOn(ledGreen);
turnLEDOn(ledRed);
wait1Msec(71); // 1/14 second
turnLEDOff(ledGreen);
turnLEDOff(ledRed);
wait1Msec(71);
}
}
// Bumper/motor control code ...
}
Это делает еще одно упрощенное предположение: если датчик освещенности все еще светится после завершения 1-секундного цикла мигания светодиода, можно в следующий раз повторить еще один 1-секундный мигание вокруг основного цикла управления, что происходит очень скоро. Таким образом, пока световой датчик светится, светодиоды будут продолжать мигать, и двигатели будут проверять бамперы только один раз в секунду. Чтобы исправить это, используйте переменную, чтобы выяснить, когда датчик освещенности переходит от темного к яркому.