Удаленное управление. I2C. Гироскоп.

И снова здравствуйте.

Раз уже сайт совсем умер, то напишу, пожалуй, ещё… А ну, как оживет.

По случаю достал гироскоп на чипе L3G4200D, которым можно управлять как по I2C, так и по SPI. Даташит приводить на него, думаю, не стоит, потому как это легко гуглится. При помощи интерфейса i2c буду получить от него какие-нибудь сведения. Например значения по x, y и z. Что ж еще нужно от гироскопа?
Сначала некоторые константы:
адрес по-умолчанию = 0x69 (можно обнаружить прямо на малине при помощи, например i2cdetect)
5 контрольных регистров 0x20..0x24
Регистры значений X, Y, Z соответственно (0х28, 0х29), (0х2A, 0х2B), (0х2C, 0х2D). Значения занимают каждый по 2 байта в таком виде (Low, High).
Lua:

device_address	= 0x69
ctrl_regs	= { 0x20, 0x21, 0x22, 0x23, 0x24 }

R_xL = 0x28
R_xH = 0x29

R_yL = 0x2A
R_yH = 0x2B

R_zL = 0x2C
R_zH = 0x2D

Чтоб было интереснее сделаем метатаблицу lua для работы с данным чипом. Чтоб работать с гироскопом, как с отдельным объектом.

i2c = fr.client.smbus -- псевдоним для клиента smbus

-- пустая таблица без ничего.
L3G4200D = { }

-- метод new, который вернут новый экземпляр таблицы
L3G4200D.new = function( ) 
    inst = { }
    for k, v in pairs(L3G4200D) do 
        inst[k] = v 
    end
    -- откроем девайс и сохраним его в нашей таблице.
    inst.i = assert(i2c.open( 1, device_address ))
    -- это метатаблица
    setmetatable( inst, L3G4200D )
    return inst
end

теперь можно сделать что-то типа

local r = L3G4200D.new( )

Код создаст экземпляр таблицы, откроет девайс и если все нормально, с ним можно работать.
для того, чтоб настроить на работу устройство, добавлю функцию setup

-- настройка состоит в том, чтоб записать нужные регистры нужными значениями. 
L3G4200D.setup = function( self, scale ) 
    -- настроим таблицу. write_bytes ожидает таблицу, в которой указано [регистр]=значение
    local data = { 
	[ctrl_regs[1]] = 15, -- включим
	[ctrl_regs[2]] =  0, -- нормальный режим. По-умолчанию 
	[ctrl_regs[3]] =  8, 
	[ctrl_regs[4]] = scale_values[scale], -- установка scale
	[ctrl_regs[5]] =  0 -- по-умолчанию
    }
    -- запишем. 
    assert(self.i:write_bytes(data))
end

Если не сработал assert, то гироскоп будет включен и готов к чтению данных. Функция для чтения тоже довольно проста

-- табица для чтения. read_bytes ожидает в таблице номера регистров для чтения.
read_xyz_data = { R_xL, R_xH, R_yL, R_yH, R_zL, R_zH }
L3G4200D.read_xyz = function( self )
    -- читаем
    local res = assert(self.i:read_bytes( read_xyz_data ))
    -- возвращаем таблицу с уже поправленными значениями { x = ..,y = .., z = .. }
    return { x = res[R_xH] << 8 | res[R_xL],
             y = res[R_yH] << 8 | res[R_yL],
             z = res[R_zH] << 8 | res[R_zL] }
end

Теперь есть полный инструмент для получения данных с гироскопа. Далее я приведу скрипт, который раз в 100 миллисекунд вычитывает данные и выбрасывает их на консоль.

i2c = fr.client.smbus
eq  = fr.client.event_queue -- для работы с очередью событий клиента
eqt = eq.timer  -- таймеры клиента

device_address	= 0x69
ctrl_regs	= { 0x20, 0x21, 0x22, 0x23, 0x24 }
scale_values	= { [250]=0, [500]=16, [2000]=48 }

R_xL = 0x28
R_xH = 0x29

R_yL = 0x2A
R_yH = 0x2B

R_zL = 0x2C
R_zH = 0x2D

read_xyz_data = { R_xL, R_xH, R_yL, R_yH, R_zL, R_zH }

L3G4200D = { }

L3G4200D.new = function( ) 
    inst = { }
    for k, v in pairs(L3G4200D) do 
        inst[k] = v 
    end
    inst.i = assert(i2c.open( 1, device_address ))
    setmetatable( inst, L3G4200D )
    return inst
end

L3G4200D.setup = function( self, scale ) 
    -- setup table for write
    local data = { 
	[ctrl_regs[1]] = 15,
	[ctrl_regs[2]] =  0,
	[ctrl_regs[3]] =  8,
	[ctrl_regs[4]] = scale_values[scale],
	[ctrl_regs[5]] =  0 
    }
    -- write registry
    assert(self.i:write_bytes(data))
end

L3G4200D.read_xyz = function( self )
    local res = assert(self.i:read_bytes( read_xyz_data ))
    return { x = res[R_xH] << 8 | res[R_xL],
             y = res[R_yH] << 8 | res[R_yL],
             z = res[R_zH] << 8 | res[R_zL] }
end

-- функция таймера, которая вычитает данные и выведет их на консоль
function show_values( err, dev ) -- первый параметр - ошибка таймера. при нормальной работе err=nil
    if nil == err then  
        local values = dev:read_xyz( ) -- вычитаем
	print( "X:", values.x, 
               "Y:", values.y, 
               "Z:", values.z )        -- ... и выведем
	eqt.post( show_values, {milli=100}, dev ) -- поставим новое задание в таймер на 100 milliсекунд
    else -- если ошибка 
	fr.exit(err) -- завершимся. fr.exit( ) остановит очередь
    end
end
 
function main( )
    fr.run( ) -- запустим очередь событий
    local r = L3G4200D.new( ) -- откроем устройство
    r:setup(2000) -- настроем устройство
    show_values( nil, r ) -- запустим вывод.
end

теперь можно проверить: 192.168.1.3:12345 — адрес и порт агента на малине. Запущу и подвигаю железку немного.

$ ./lua_client -s 192.168.1.3:12345 -e L3G4200D.lua 
X:	129	Y:	500	Z:	65489
X:	50	Y:	65468	Z:	65508
X:	26	Y:	4	Z:	14
...............
X:	34869	Y:	37125	Z:	21348
X:	57781	Y:	65259	Z:	3636
X:	32752	Y:	32752	Z:	32832
...............
X:	76	Y:	78	Z:	23
X:	73	Y:	7	Z:	11
X:	78	Y:	62	Z:	65519
X:	48	Y:	65495	Z:	45
X:	14	Y:	4	Z:	6
^C

На этом все, спасибо за внимание.
PS: скрипт можно взять тут
PPS: Добавил в пример получение значения температурного регистра: 0x26
  • 0

Комментарии (0)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.