17 January 2014

Raspberry PI и JAVA: пристальный взгляд

Java
Недавно на хабрахабре вышла статья о java на raspberry pi, увидев название которой было много ожиданий, а под катом оказался банальный Hello World!

Дело в том, что ко мне как раз ехала моя малинка и хотелось получить ответы на следующие вопросы:

1. Сравнима ли скорость работы java на малинке и настольном компьютере?
2. Насколько удобно работать с java на raspberry?
3. Есть ли адекватные библиотеки для работы с GPIO?

Вот на эти вопросы я и попробую дать ответы в этой статье.

Кому интересно: добро пожаловать под кат (графики и фотографий обнаженной малинки там не будет)

Настройка доступа к Raspberry PI по ssh без пароля


Я очень люблю свой родной ноутбук и предпочитаю работать на других линукс-машинах через ssh.
Поэтому, в первую очередь, ради удобства настраиваем доступ к малинке по ключу.
Для этого на компьютере, с которого будет осуществляться подключение генерируем пару ключей при помощи команды ssh-keygen.
Затем копируем открытый ключ на малинку

$ scp /home/user1/.ssh/id_rsa.pub pi@raspberry_server:~/
$  ssh  pi@raspberry_server
$ mkdir .ssh
$ cat ~/id_rsa.pub >> ~/. ssh /authorized_keys

Нажимаем Ctrl-D для выхода из сеанса. Пытаемся снова подключиться — профит. Подключение происходит без запроса пароля.

Заглядываем под капот


Прежде всего меня интересует, что же за оборудование мне досталось. Можно, конечно, посмотреть в документацию, но всей правды она не всегда скажет.
Поэтому, подключаемся и вводим команду
$ cat /proc/cpuinfo


Заинтересовала следующая строка:
Features: swp half thumb fastmult vfp edsp java tls

Что-ж уже интересно. Можно надеяться, что малинка меня порадует.

Установка JAVA SE Embedded


В предыдущей статье был описан способ установки openJDK. Кому интересно — посмотрит.

Но мне было интересно установить java от оракла (все равно java-код я люблю компилировать на любимом ноутбуке в любимой IDE), что и я сделал:
Итак, идем на сайт оракла, скачиваем пакет java se embedded (ARMv6/7 Linux — Headless — Client Compiler EABI, VFP, HardFP ABI, Little Endian) и заливаем его в папку /home/pi.

Заходим в консоль малинки и
1. Распаковываем архив в папку /opt
$ sudo tar -xvf ejre-7u45-fcs-b15-linux-arm-vfp-hflt-client_headless-26_sep_2013.tar.gz -C /opt

2. Далее добавляем путь к файлу java в переменную PATH и устанавливаем переменную JAVA_HOME
$ sudo chmod a+w /etc/profile
$ echo 'export PATH=/opt/ejre1.7.0_45/bin:$PATH' >> /etc/profile 
$ echo 'export JAVA_HOME=/opt/ejre1.7.0_45' >> /etc/profile 
$ sudo chmod a-w /etc/profile

Перезаходим по ssh и командой
$ java -version

убеждаемся, что виртуальная машина установлена.

Тестируем скорость работы


Теперь настало время выяснить насколько медленна/быстра java на малинке. Тест не претендует на какую-либо всеобъемлющую объективность, а лишь призван показать приблизительный порядок разницы скорости работы виртуальной машины на малинке и настольном компьютере.
Для теста был выбран мой нетбук с процессором AMD E-300 APU с тактовой частотой 1,3 Гц (т. е. Почти в два раза большей, чем у малинки).
Для теста используем программу поиска простых чисел при помощи решета Эратосфена.

Кому интересно, может посмотреть исходный код:
public class RaspTest {
    public static void main(String[] args) {
        int maxPrimesCount = 40000;
        int currentPrimesCount = 1;
        long prevTime, execTime;
        prevTime = System.currentTimeMillis();


        long[] primes = new long[maxPrimesCount];
        long currentNumber = 3;

        boolean isPrime = false;

        primes[0]=2;

        while (currentPrimesCount < maxPrimesCount) {
            isPrime = true;
            for (int i = 0; i < currentPrimesCount; i++) {
                if (currentNumber % primes[i] == 0) {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime) {
                primes[currentPrimesCount] = currentNumber;
                currentPrimesCount++;
            }
            currentNumber++;
        }

        execTime = System.currentTimeMillis() - prevTime;
        System.out.println(execTime);
        System.out.print(currentNumber-1);


    }
}



Итого:
Нетбук показал результат 89 секунд, а raspberry — 444 секунды.
Итого: на малинке почти в пять раз медленнее. Что-ж вполне ожидаемо учитывая разницу в тактовой частоте и архитектуре.
Неожиданность нас постигнет, если мы изменим тип чисел с long на int.
При этом нетбук показал результат 38 секунд, а raspberry — 65 секунд.
Я был приятно удивлен.

Вывод: скорость работы виртуальной машины на raspberry pi сравнима с таковой на настольных компьютерах.

Работа с GPIO


В одном из докладов на конференции Joker докладчики программировали GPIO на Java Embedded ME (micro edition).
Standart Edition, к сожалению, не имеет соответствующих классов, поэтому я обратился к гуглу и нашел проект Pi4J (www.pi4j.com). Стабильная версия сейчас 0.0.5, но проект развивается и версия 1 разрабатывается в данный момент.
Тем не менее я рекомендую пользоваться стабильной версией, ибо на версии 1 у меня не все заработало.
Следует также отметить, что номера портов несколько отличаются от стандартных, поэтому рекомендую ознакомиться с документацией на сайте Pi4J.

Цепляю на первый порт светодиод, на второй кнопку, пишу следующий код:

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        GpioController gpioController = GpioFactory.getInstance();
        GpioPinDigitalOutput gpioPinDigitalOutput = gpioController.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED", PinState.HIGH);
        GpioPinDigitalInput gpioPinDigitalInput = gpioController.provisionDigitalInputPin(RaspiPin.GPIO_02,PinPullResistance.PULL_DOWN);
        gpioPinDigitalInput.addListener(new GpioPinListenerDigital() {
            @Override
            public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent gpioPinDigitalStateChangeEvent) {
                System.out.println("GPIO Pin changed" + gpioPinDigitalStateChangeEvent.getPin() + gpioPinDigitalStateChangeEvent.getState());
                System.out.println("Sleeping 5s");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Unsleep");
            }
        });

        while (true) {
            gpioPinDigitalOutput.toggle();
            Thread.sleep(500);
        }


    }
}



Собираю пакет, копирую jar файл и библиотеки на raspberry pi, запускаю и… Не работает.
Оказывается, для управления портами ввода/вывода необходимы права администратора.
Но для того, чтобы сработала команда
$ sudo java

в каталоге /bin должна быть символическая ссылка на исполняемый файл java-машины. Создаем ее:

ln -s /opt/ejre1.7.0_45/bin/java /bin/java


Снова запускаем — работает. Лампочка мигает, при нажатии на кнопку и засыпании потока обработки лампочка мигать продолжает, т.е. обработка события от кнопки запускается асинхронно.

Выводы:
1. Raspberry pi — это не игрушка, а компьютер с производительностью и возможностями, подходящими для решения многих задач.
2. Производительности виртуальной машины java сравнима с производительностью в настольных системах, хотя и несколько ниже.
3. Управление внешним оборудованием при помощи java и raspberry pi — реальная и вполне легко решаемая задача (чем я и собираюсь заняться в дальнейшем).

Спасибо за внимание.
Tags:raspberryh pijavagpiolinux
Hubs: Java
+38
61.3k 189
Comments 62