LeJOS: програма дистанційно керованого робота 2


Статей про дистанційне керування з пульта та керування двигунами в принипі достатньо для того, аби створити програму для робота, яким можна керувати за допомогою пульта. Цим ми зараз і займемося, а заодно подивимося як працює метод getRemoteCommands, який дозволяє “слухати” одночасно кілька каналів.

Традиційно тестовий робот це частина робота EV3RSTORM, яку ви можете зібрати за інструкцією від Lego. Виглядає робот наступним чином:

Мотори підключено до портів A та B, а інфрачервоний приймач у порт 1. Далі пишемо програму:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package org.akceptor.lejos;

import lejos.hardware.Button;
import lejos.hardware.ev3.LocalEV3;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.hardware.port.Port;
import lejos.hardware.sensor.EV3IRSensor;
import lejos.hardware.sensor.SensorModes;
import lejos.robotics.RegulatedMotor;

public class RCRobot {

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		// Motors
		RegulatedMotor m1 = new EV3LargeRegulatedMotor(MotorPort.A);
		RegulatedMotor m2 = new EV3LargeRegulatedMotor(MotorPort.B);
		m1.setSpeed(200);
		m2.setSpeed(200);
		m2.synchronizeWith(new RegulatedMotor[] { m1 });
		m2.startSynchronization();
		// IR Remote
		Port port = LocalEV3.get().getPort("S1");
		SensorModes sensor = new EV3IRSensor(port);
		System.out.println("Press any key to start");
		Button.waitForAnyPress();
		System.out.println("Press ESCAPE key to stop");
		int keys = 0;
		while (keys != 32 /* ESCAPE */) {
			byte[] commands = { 0, 0, 0, 0 };
			// Get array of commands: one per channel
			((EV3IRSensor) sensor).getRemoteCommands(commands, 0, 4);
			// Current command and channel
			int command = maxValue(commands);
			int multiplier = maxIndex(commands);
			// Speed depends on channel
			// 200->400->600->800
			m1.setSpeed(200 * (1 + multiplier));
			m2.setSpeed(200 * (1 + multiplier));
			switch (command) {
			case 1:
				// Left fwd
				m2.forward();
				break;
			case 2:
				// left bwd
				m2.backward();
				break;
			case 3:
				// right fwd
				m1.forward();
				break;
			case 4:
				// right bwd
				m1.backward();
				break;
			case 5:
				// both fwd
				m2.startSynchronization();
				m1.forward();
				m2.forward();
				m2.endSynchronization();
				break;
			case 6:
				// rotate left
				m2.startSynchronization();
				m1.backward();
				m2.forward();
				m2.endSynchronization();
				break;
			case 7:
				// rotate right
				m2.startSynchronization();
				m1.forward();
				m2.backward();
				m2.endSynchronization();
				break;
			case 8:
				// both bwd
				m2.startSynchronization();
				m1.backward();
				m2.backward();
				m2.endSynchronization();
				break;
			default:
				// stop
				m2.startSynchronization();
				m1.stop();
				m2.stop();
				m2.endSynchronization();
			}
			// Acquire keys
			keys = Button.readButtons();
		}

	}

	/**
	 * Returns max. value for array
	 * 
	 * @param bytes
	 *            aray
	 * @return max value
	 */
	private static int maxValue(byte[] bytes) {
		int max = bytes[0];
		for (int ktr = 0; ktr < bytes.length; ktr++) {
			if (bytes[ktr] > max) {
				max = bytes[ktr];
			}
		}
		return max;
	}

	/**
	 * Returns index of max. element for array
	 * 
	 * @param bytes
	 *            array
	 * @return max element index
	 */
	private static int maxIndex(byte[] bytes) {
		int max = bytes[0];
		int maxIdx = 0;
		for (int ktr = 0; ktr < bytes.length; ktr++) {
			if (bytes[ktr] > max) {
				max = bytes[ktr];
				maxIdx = ktr;
			}
		}
		return maxIdx;
	}
}

Вже страшно? Так, великі плахти коду не найкраще виглядають у блогах, тому я зробив репо на GitHub для своїх експериментів. Посилання на репозиторій: https://github.com/Akceptor/LeJOS

В принципі тут все має бути зрозуміло, крім двох нюансів. По-перше, метод getRemoteCommands. У цього метода 3 аргументи: масив, у який будуть записуватися команди (я його проініціалізував нулями на початку), зміщення, за яким слід записувати команди у масив (у нашому випадку нуль) і кількість команд. Оскільки ми хочемо “слухати” 4 канали, то і параметр цей рівний чотирьом.

Перемикаючи канал на пульті ми відправляємо команди у інший елемент масиву і таким чином можемо використати методи maxValue та maxIndex для того, аби задати швидкість обертання двигунів. Зараз кожен наступний канал швидший за попередній на 200 одиниць. Перемикач, звісно, маленький і клацати ним не надто зручно, але навряд чи це хтось робитиме часто 🙂

Другий нюанс полягає у тому, що за замовчуванням плагін LeJOS для Eclipse не вміє працювати з додатковими бібліотеками. Це означає що ніяких apache.commons.lang чи чогось такого використати не вийде. Звісно, eclipse покладе бібліотеки собі на classpath і все скомпілюється, але при завантаженні результату на EV3 ми отримаємо проблему: JVM кубика не зможе знайти потрібні класи.

Ця проблема вирішується якщо застосовувати якийсь з інструментів для побудови проекту (ant, maven, gradle), але про це іншим разом.

Почитайте ще оце:


Залиште коментар

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

2 thoughts on “LeJOS: програма дистанційно керованого робота