GrabDuck

Подключение акселерометра к Raspberry Pi с использованием библиотеки Pi4J

:

Предисловие


Привет, Хабр! Буквально недавно меня взяли в кружок по робототехнике. Конечно, я с радостью согласился, это же новый опыт и все такое… Тем более я всего лишь первокурсник. Мой преподаватель, объяснив мне общую концепцию, предложил заняться работой с Raspberry Pi. Нужно было разобраться, как с ним работать, установить на него JDK и написать программу, которая выводила бы на экран показания с 3-х осевого акселерометра. Взяв все необходимое, я отправился домой разбираться. Когда я все закончил (ушло на это примерно неделя), решил написать гайдик, адресованный таким же, как и я, дабы собрать все, что я нарыл, в одном месте. Ну, приятного чтения!

Первым делом


Первым делом нужно получить доступ к нашему устройству. Подключаться будем посредством протокола SSH. По умолчанию сервер SSH отключен, и чтобы включить его, подключаем Raspberry к монитору или телевизору, подсоединяем клавиатуру и мышку. Конечно, можно просто просканировать сетевое окружение, выявить наше устройство и подключиться по найденному IP, но все же рекомендую сделать по моему варианту. После загрузки запускам терминал и вводим команду sudo raspi-config. В открывшемся меню идем в advanced options->SSH и выбираем Enable. После этих манипуляций, должно появиться следующее окошко:

image

Отлично! Теперь мы сможем приконектиться к нашей “малинке” в любое время. Давайте сразу пропишем настройки сети. Файл, который нам нужен, находится в каталоге /etc/network/.Переходим туда с помощью команды cd /etc/network. Далее открываем нужный файл, введя sudo nano interfaces. Здесь в соответствующих строках прописываем свои данные, тем самым мы задаем статический IP адрес. Должно получиться примерно следующее:

image

После нажимаем CTRL+X, Y, Enter. Именно по этому адресу будем подключаться. Далее скачиваем клиет SSH — PuTTY. Запустив программу, вы увидите следующее окно:

image

Здесь в поле Host Name пишем тот самый ip, который мы прописали в interfaces. Здесь же можно сохранить настройки, прописав в поле Save Session имя и нажав на Save. Нажимаем Open. Как только PuTTY подключится к SSH серверу, откроется окно, и появится запрос учетных данных (по умолчанию, пользователь: pi, пароль: raspberry):

image

Не пугайтесь, что при вводе вы не видите пароль, в Linux подобных системах пароль просто не виден, хотя ввод происходит. Нажимаем Enter. Если все прошло удачно, вы увидите следующее окошко:

image

В этой консольке можно выполнять любые команды, и они будут выполнены на самом устройстве. Неправда ли удобно?

Установка JDK


Здесь все довольно просто. Обновляем список пакетов, введя в терминале sudo apt-get update.

image

Обновим и саму систему sudo apt-get upgrade.

image
На все это может понадобиться довольно много времени (у меня это обновление проходило примерно 30 минут), так что запаситесь чаем. Слава великой силе, что в списки пакетов был добавлен пакет JDK, и нам не пришлось танцевать с бубном. Для установки пакета просто вводим sudo apt-get install openjdk-7-jdk.

Для проверки работоспособности вводим java -version. Вы должны увидеть примерно следующее:

image

P.S. На некоторых машинах может возникнуть проблема, связанная с тем, что система не находит пакет JDK. Она возникает из-за несовместимости ядра Debian “wheezy” с java. Попробуйте переустановить ОС на Soft-float Debian “wheezy”, оптимизированную для работы с java. В любом случае на моей “малинке” все встало с первого раза. Вот моя версия:

image

I2c vs Raspberry PI


Итак, теперь начинается самое интересное! Для начала, давайте разберемся, что это вообще такое? Великая и могучая Википедия говорит:
I²C (рус. ай-ту-си/и-два-цэ/и-два-си) — последовательная шина данных для связи интегральных схем, использующая две двунаправленные линии связи (SDA и SCL). Используется для соединения низкоскоростных периферийных компонентов с материнской платой, встраиваемыми системами и мобильными телефонами. Название представляет собой аббревиатуру слов Inter-Integrated Circuit.

В своей работе, я использую вот это устройство LSM303DLM, в дальнейшем все примеры будут показаны именно на нем. Ниже я нарисовал схему подключения:

image

Она довольно простая, и я думаю, не требует разъяснений. Продолжим. Ах да, давайте сразу добавим пару строк в файл, отвечающий за автозагрузку модулей. Прописываем в командной строке sudo nano /etc/modules и дописываем туда:

i2c-bcm2708
i2c-dev

image

Теперь устанавливаем пакет i2c-tools. В терминале пишем: sudo apt-get install python-smbus и sudo apt-get install i2c-tools.
Редактируем черный список. Для этого пишем sudo nano /etc/modprobe.d/raspi-blacklist.conf. Добавляем строки:

blacklist spi-bcm2708
blacklist i2c-bcm2708

image

Все. Все самое необходимое для работы с I2C мы сделали, теперь давайте проверим, видим ли мы наше устройство. В утилиту i2c-tools входит команда i2cdetect, она нам и нужна. Но сперва проверим, что драйвера успешно установлены. Пишем в терминале i2cdetect –l. Если видим следующее:

image

То все нормально, можно двигаться дальше. Теперь пишем i2cdetect –y 1 ( i2cdetect –y 0). Видим решетку адресов:

image

В моем случае, адрес акселерометра 0x18(можно узнать, например, в документации). Теперь поговорим о PI4J.

Уоу уоу уоу палехче…


Для работы с I2C средствами JAVA, нужно скачать и установить дополнительную библиотеку PI4J. Прочитать про нее можно здесь. Скачиваем, написав в терминале wget pi4j.googlecode.com/files/pi4j-0.0.5.deb. Устанавливаем, прописав: sudo dpkg -i pi4j-0.0.5.deb. Проверим установленные файлы:

image

Теперь для компиляции программы пишем:

javac -classpath .:classes:/opt/pi4j/lib/'*' (название)

Для запуска:
sudo java -classpath .:classes:/opt/pi4j/lib/'*' (название)

Из всех пакетов нам пригодится 3:

import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;

Создаем ссылки на объекты классов I2CDevice и I2CBus.

import java.io.IOException;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;

public class accelerometrOne {
	static I2CDevice device;
	static I2CBus bus;
	static byte[] accel;
    public static void main(String[] args) throws IOException {
        System.out.println("Starting sensors reading:");
        try {
           bus = I2CFactory.getInstance(I2CBus.BUS_1);
           System.out.println("Connected to bus OK!");
            
           device = bus.getDevice(0x18);
           System.out.println("Connected to device OK!");
                   
        } catch (IOException e) {
           System.out.println(e.getMessage());
        }
    }
}

Разберем код. Строчкой bus = I2CFactory.getInstance(I2CBus.BUS_1); мы подключаемся к нашей шине, а с помощью device = bus.getDevice(0x18); мы подключаемся к нашему устройству.

Теперь нужно произвести калибровку акселерометра. Лезем в документацию.

image

У кого совсем все плохо с английским. В моем вольном переводе: “После включения LSM303DLH необходимо произвести конфигурацию устройства по 2 регистрам CTRL_REG1_A(20h) и CTRL_REG2_A (23h). Для этого в первый регистр пишем 0x27 для нормальной работы с ODR 50гц.

Пишем 0*40 во второй регистр для того, чтобы сохранить полный диапазон измерений +- 2 гаусс в непрерывном обновлении базы данных и изменить порядок байтов от младшего к старшему на порядок, от старшего к младшему.”

Для записи данных в устройство воспользуемся методом write из класса I2CDevice. Допишем программу:

import java.io.IOException;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;

public class accelerometrOne {
	static I2CDevice device;
	static I2CBus bus;
	static byte[] accel;
    public static void main(String[] args) throws IOException {
        System.out.println("Starting sensors reading:");
        try {
           bus = I2CFactory.getInstance(I2CBus.BUS_1);
           System.out.println("Connected to bus OK!");
            
           device = bus.getDevice(0x18);
           System.out.println("Connected to device OK!");
           
           device.write(0x20, (byte) 0x27);
           device.write(0x23, (byte) 0x40);
           System.out.println("Configuring sensors OK!");
         
        } catch (IOException e) {
           System.out.println(e.getMessage());
        }
    }

Отлично!!! Осталось считать данные с устройства. Снова лезем в документацию и узнаем, что данные выдаются по 2 байта на каждую ось:
image

Ну и все. Записываем полученные байты в массив и выводим данные на экран:

import java.io.IOException;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;

public class accelerometrOne {
	static I2CDevice device;
	static I2CBus bus;
	static byte[] accel;
    public static void main(String[] args) throws IOException {
        System.out.println("Starting sensors reading:");
        try {
           bus = I2CFactory.getInstance(I2CBus.BUS_1);
           System.out.println("Connected to bus OK!");
            
           device = bus.getDevice(0x18);
           System.out.println("Connected to device OK!");
           
           device.write(0x20, (byte) 0x27);
           device.write(0x23, (byte) 0x40);
           System.out.println("Configuring sensors OK!");
         
           readingsensors();
           
        } catch (IOException e) {
           System.out.println(e.getMessage());
        }
    }

    private static void readingsensors() throws IOException {
		while (true) {
			accel = new byte[6];
			accel[0] = (byte) device.read(0x28);
			accel[1] = (byte) device.read(0x29);
			accel[2] = (byte) device.read(0x2a);
			accel[3] = (byte) device.read(0x2b);
			accel[4] = (byte) device.read(0x2c);
			accel[5] = (byte) device.read(0x2d);
			int accelx = asint(accel[0]) * 256 + asint(accel[1]);
			int accely = asint(accel[2]) * 256 + asint(accel[3]);
			int accelz = asint(accel[4]) * 256 + asint(accel[5]);
			System.out.println("accelx: " + accelx + ", accely: " + accely
					+ ", accelz: " + accelz);
		}
	}
    private static int asint(byte b) {
        int i = b;
        if (i < 0) {
            i = i + 256;
        }
        return i;
    }
} 

В итоге, после запуска мы увидим примерно следующее:

image