Доброго времени суток! Имеется RPi и Multiservo на 18 сервомашинок (от АМПЕРКА), но никак не могу наладить связь по i2c (не знаю как пакет управления передать - управлять). Интерфейс работает! команда i2cdetect -y 1 выдаёт: 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- 06 07 -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- 47 -- -- -- -- -- -- -- -- 50: 50 51 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- где: 06 07 - моя плата ComMotion motor driver - моя плата на 4 коллекторных двигателя (вчера с горем пополам до неё достучался и в BASH и в PYTHON) 50 51 - просто так (для теста) подключил 24Cxx - не помню какая память (xx) 47 - судя по скачанным проектам для multiservo - она и есть! (кстати всплывает не всегда - судя по документации i2c на этой плате работает с интервалом) Собственно вопрос - какой протокол обмена, ну или пример обмена по i2c. Спасибо!
Посмотрите исходники библиотеки Мультисерво и перенесите их в Малину: https://github.com/amperka/Multiservo/blob/master/library/Multiservo/Multiservo.cpp
Уже часа 4 курю эти исходники! Одно смущает: #include <Arduino.h> #include <Wire.h> ведь там определено (Wire): do { Wire.beginTransmission(twiAddress); Wire.write(pin); Wire.write(pulseWidth >> 8); Wire.write(pulseWidth & 0xFF); errorCode = (Error)Wire.endTransmission(); } while (errorCode && --retryAttempts); Wire.beginTransmission(twiAddress); - опнятно, что адрес! а вот к примеру Wire.write(pin); установка просто на i2c или запись по какому-то адресу внутри устройства. Как пример (беру из PYTHON): write_byte(addr, p0) - передаём по адресу i2c addr параметр p0 write_byte_data(addr, saddr, p0) - передаём по адресу i2c addr в регистр saddr параметр p0 вчера с ComMotion получилось (не без описания) получилось по write_byte_data(addr, saddr, p0) пока не компилю на си - очень неудобно удаленно на Raspberry и тут же пробовать, пока пробую на интерпретаторах (PYTHON, BASH). Отработаю - тогда уж и мой любимый GCC. Организовал RAM-disk на Raspberry в нём и кручу всё это и тут же запускаю. С утра ковыряюсь с Multiservo, с ComMotion вчера быстрее получилось. Устал уж от того и болтаю много. Но спасибо, что откликнулись.
write_word_data(twiAddress, pin, val) в данном случае twiAddress - адрес на шине i2c, pin - адрес регистра внутри устройства на шине i2c, val - 8-ми битное значение (байт), но в исходнике 490 <= val <= 2400, т.е. двухвайтоное значение: write_word_data(twiAddress, pin, val(l/h)) write_word_data(twiAddress, pin + 1, val(h/i)) К сожалению не работает. Эту команду уже применял ранее. Пока не разберусь сколько, чего и куда отправить, чтоб сервромашина заработала. Судя по всему плата исправна, коли связь есть и при подачи питания сервомашины (их 2 шт) вжыкают.
Понимаю так, что никто не использует эти шилды в составе Raspberry Pi а только через Arduino и зря маюсь с этим - деньги на ветер?
Функция write_word_data отсылает слово, т.е. val двухбайтный. Конструкция: write_word_data(twiAddress, pin, val(l/h)) write_word_data(twiAddress, pin + 1, val(h/i)) В корне неверная. Вас сбила с толку "высокоуровневая обертка", которую прикрутили на питоне для i2c. Она заключается в том, что большинство i2c микросхем содержат регистры. В шилд надо послать i2c_addr, pin, us_high, us_low, поэтому надо использовать write_word_data(twiAddress, pin, val). Если разбить как вы указали, то будут посланы команды для двух разных пинов с некорректными значениями В чем я вижу тут могут быть еще проблемы: 1. Возможно в val надо будет поменять местами старший и младший байт, т.к. непонятно какой уходит первым. Правильно посылать первым старший 2. В исходниках Амперки почему-то эти данные отправляются несколько раз. Возможно это "фича" платы, что с первого раза может не принять и поэтому требуется 5 попыток. Отставить панику, все заработает
Простите, что обманываю с write_word_data(twiAddress, pin, val(l/h)) невнимательность! я применял write_byte_data(twiAddress, pin, val(l/h)) потому и писал про байты. Сейчас попробую. и ещё - если я правильно понял не надо обращаться по адресу, а просто посылать пакет в определённом формате - так?
Заработало! Если кому интересно: Код (Python): #!/usr/bin/python # coding: utf-8 import smbus import time print("=====test multiservo=====") addr = 0x47 bus = smbus.SMBus(1) pin = 1 res = 0 set = 700 def wrmultiservo(addr, _pin, val): global res res = 0 tm = 0.05 te = 1 p0 = (val >> 8) p1 = val & 0xff cmd = _pin try: print(addr, cmd, p0, p1) bus.write_i2c_block_data(addr, cmd, [p0, p1]) time.sleep(tm) res = 1; except: print("--error--") time.sleep(tm) def sup(pin): global set global addr global res while(set < 1700): wrmultiservo(addr, pin, set) if(res > 0): res = 0 set = set + 10 # def sdown(pin): global set global addr global res while(set > 700): wrmultiservo(addr, pin, set) if(res > 0): res = 0 set = set - 10 # nums=10 while(nums > 0): sup(pin) sdown(pin) nums = nums - 1 В процессе опытов убил одну сервомашину - по своей глупости. Моя глупость: Подключение было вместе с ComMotion motor driver. Смонтировано в виде бутерброда, и питание от него. Но не учёл, что этот самый ComMotion время от времени начинает откликаться на все адреса I2C. Ну соответственно и с ним произошло что-то тоже, а стали работать только два его двигателя, причём один работает только в одну сторону. так что у меня заработала только write_i2c_block_data(addr, cmd, [p0, p1]) другие более не стал трогать.