16 сервоприводов. Библиотека Adafruit_PWMServoDriver.h

Letro
Offline
Зарегистрирован: 10.12.2015

Всем привет!

Прошу помочь разобраться с библитекой Adafruit_PWMServoDriver.h. 

Купил Adafruit 16-Channel Servo Driver (НЕ РЕКЛАМА! ссылка на картинку+документацию https://learn.adafruit.com/downloads/pdf/16-channel-pwm-servo-driver.pdf ).

Ранее работал с servo.h, с ней все достаточно просто. С этой у меня пошло туго, в документации написано сделайте: pulselength = map(degrees, 0, 180, SERVOMIN, SERVOMAX); и получите градусы. Но куда впихнуть, и как вызвать?

В примерах библиотеки все завязано на циклах, ШИМ и тучи непонятных мне параметров. Не могу понять как хотя бы одну определенную серву повернуть в -90 град, затем в +90 град. Там все завязано на setPWM(channel, on, off):

Arguments channel: 

The channel that should be updated with the new values (0..15) 

on: The tick (between 0..4095) when the signal should transition from low to high

off:the tick (between 0..4095) when the signal should transition from high to low

Как всем этим чудом управлять ума не приложу, прошу помочь с самым простым скетчем, или ткните меня в ман, что почитать, где посмотреть. 

 

Сейчас скеч выглядит так для 4-х серв:

/***************************************************
  This is an example for our Adafruit 16-channel PWM & Servo driver
  Servo test - this will drive 16 servos, one after the other

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate, 2 pins are required to
  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

// Depending on your servo make, the pulse width min and max may vary, you
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN  125 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  580 // this is the 'maximum' pulse length count (out of 4096)

// our servo # counter
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");

#ifdef ESP8266
  Wire.pins(2, 14);   // ESP8266 can use any two pins, such as SDA to #2 and SCL to #14
#endif

  pwm.begin();

  pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates

  yield();
}

// you can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. its not precise!
void setServoPulse(uint8_t n, double pulse) {
  double pulselength;

  //  pulselength = 1000000;   // 1,000,000 us per second
  //  pulselength /= 60;   // 60 Hz
  Serial.print(pulselength); Serial.println(" us per period");
  // pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit");
  //  pulse *= 1000;
  //  pulse /= pulselength;
  //  Serial.println(pulse);
  //  pwm.setPWM(n, 0, pulse);
}

void loop() {
  // Drive each servo one at a time
  Serial.println(servonum);
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);

  servonum ++;
  if (servonum > 3) servonum = 0;
}

 

 

Letro
Offline
Зарегистрирован: 10.12.2015

уважаемые форумчане, что я не так пишу?)

Как тут получить ответ, как формулировать вопрос? Или мне с такими вопросами заказывать код нужно?

Или вопрос совсем идиотский?

Duino A.R.
Offline
Зарегистрирован: 25.05.2015

Letro пишет:

уважаемые форумчане, что я не так пишу?)

Как тут получить ответ, как формулировать вопрос? Или мне с такими вопросами заказывать код нужно?

Или вопрос совсем идиотский?

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

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

А что вас смутило-то? В параметрах к функции всё четко прописано: номер канала, сервы; длительность части периода "on"; длительность части периода "off" и даже диапазон указан .. Вы не знаете КАК управляются Сервы? Как раз этими самыми "длительностями". В даташите на каждую, они честно прописаны в миллисекундах "от" (-90), "до" (+90) или по другим углам.. что "непонятно"-то? Как значение в градусах преобразовать в длительности? Так сами же и приводите функцию map() .. ею.

Хотите, чтобы вам сделали готовый "пирог"? Ну так вы разделом ошиблись, как понимаю. Вам верно ответили: есть конкретные непонятки - спрашивайте, ответят.

Letro
Offline
Зарегистрирован: 10.12.2015

Понял, спасибо, буду думать. Вроде руки из Ж... не растут, но нечерта не выходит. Все легкие задачи без проблем решаются, стоит логику придумать из двух двигателей, ультразвукового датчика и сервы все идет лесом. Будем книжки читать.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Логика управления не содержит ничего заумного. Тег "автоматное программирование" вам в руки, дерзайте. :)

EuBeginer
Offline
Зарегистрирован: 16.11.2015

Letro привет!

ну, да, не очень деликатно, но мол ...иди и учись. Что ж, может чем и помогу. То же только постигаю азы С++ с Ардуино. Мне инужно эти сервы (чуть больше 20 ) управлять вручную (от тумблером) нагруженных на расширитель MCP23016.

Брал Ваш, скетч (он из примера по PWM 16 channels), 

поигрался вот с этим

#define SERVOMIN  370 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  400 // this is the 'maximum' pulse length count (out of 4096)
У меня для испытаний сервы SG-90 - пратическое отклонение +-10градусов
ну а дальше идет цикл. Причем как вижу у Вас реально ТРИ сервы включены.
kasper007
Offline
Зарегистрирован: 23.05.2016

Шикарная библиотека, шикарный шильд.  Для лучшего понимания работы посмотрите второй пример, который идет с данной библиотекой. А вооще главное отличие от библиотеки servo.h в том, что на указзном шильде стоит 12битный контроллер PWM с управлением по i2c.

Если в стандартной библиотеке мы задаем просто градус, на который нужно отклониться, то здесь будем управлять исключительно длительностью импульса. Хотя даже не длительностью, а 12битной последовательностью (4096 значений).

К примеру:

Пусть диапазон длительностей управляющих импульсов сервы равен: 800 мкс до 2000 мкс.

Частота следования управляющих импульстов 50 ГЦ (период 20 мс)

Пересчитаем в управляющий код:

1.000.000 мкс / 4096 / 50 ГЦ = 4,88 - это вес единицы в последовательности

т.е. 800 мкс управления обычной сервой будет соответсвовать значению = 800/4,88 = 164

а 2000 мкс = 410

т.е. что бы загнать сервы в одно крайнее положение нужно лишь написать

pwm.setPWM(servonum, 0, 164)

а вдругое

pwm.setPWM(servonum, 0, 410)

Ну для удобства можно все пересчитывать через угол посредтсвом команды map()

так что сложного ничего тут нет. Зато позволяет задействовав всего 2 порта управлять 16 двигателями.

EuBeginer
Offline
Зарегистрирован: 16.11.2015
   Точно!!! я так и поступил. И спасибо за помощь Sindbad  !!!
Провел натурные испытания, проверил необходимые мне углы отклонения и 
в обновленном скетче я использовал
     if (AC[i] == 0)
           {
              //Serial.print ("Servo # "); Serial.print (servonum); Serial.println (" Left");
               pwm.setPWM(servonum, 0, 330);              
           }
              else
             {    
              //Serial.print ("Servo # "); Serial.print (servonum); Serial.println (" Right");
              pwm.setPWM(servonum, 0, 380);
            }
АС[i] - состояние считанного входа расширителя МСР23016, соответствующего серве "i"
Servonum - номер тойже сервы подсоединенной к 16ти канальному (что упрощает согласование адресов серв) расширителю РСА9685 
Все висит на I2C и прекрасно работает без рывков при вкл питания. Питание на сервы через РСА9685 подаю вручную примерно через 5-6 секунд после ардуина и шины.
EuBeginer
Offline
Зарегистрирован: 16.11.2015

Точно!!! я так и поступил. И спасибо за помощь Sindbad !!! Провел натурные испытания, проверил необходимые мне углы отклонения и в обновленном скетче я использовал

     
if (AC[i] == 0)
           {
              //Serial.print ("Servo # "); Serial.print (servonum); Serial.println (" Left");
               pwm.setPWM(servonum, 0, 330);              
           }
              else
             {    
              //Serial.print ("Servo # "); Serial.print (servonum); Serial.println (" Right");
              pwm.setPWM(servonum, 0, 380);
            }

 

АС[i] - состояние считанного входа расширителя МСР23016, соответствующего серве "i"
Servonum - номер тойже сервы подсоединенной к 16ти канальному (что упрощает согласование адресов серв) расширителю РСА9685 
Все висит на I2C и прекрасно работает без рывков при вкл питания. Питание на сервы через РСА9685 подаю вручную примерно через 5-6 секунд после ардуина и шины.
EuBeginer
Offline
Зарегистрирован: 16.11.2015

Что-то зазбоило. Будет здорово если модератор удалит предыдущее сообщение...

Извиняюсь.

Neocivic
Offline
Зарегистрирован: 16.03.2019

Добрый день!

Решил более глубоко разобраться с библиотекой Adafruit_PWMServoDriver.h. Но не смог найти ответа на два вопроса:

1. Что за тип переменной uint8_t и uint16_t ? В чём их разница?

2. Почему у 12-ти битной последовательности 4096 значений? Как это высчитывается?

 

sadman41
Offline
Зарегистрирован: 19.10.2016

1) uint8_t - 8 bit - 1 byte (в Arduino - byte), uint16_t - 16 bit - 2 byte (в Arduino - unsigned int)

2) 2^12 = 4096

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Neocivic пишет:

Добрый день!

Решил более глубоко разобраться с библиотекой Adafruit_PWMServoDriver.h. Но не смог найти ответа на два вопроса:

1. Что за тип переменной uint8_t и uint16_t ? В чём их разница?

2. Почему у 12-ти битной последовательности 4096 значений? Как это высчитывается?

 

1. беззнаковое 8 бит, беззнаковое 16 бит

2. 8 бит - 256, 9-бит -512, 10 бит - 1024, 11 бит -2048, 12 бит - 4096

Так понятно?

Neocivic
Offline
Зарегистрирован: 16.03.2019

Первый вопрос примерно - да. А второй вопрос нет, я знал эту зависимость, но не понимаю почему 8 бит это именно 256, а 12 бит это 4096... Может не верно гуглу вопросы задавал, ответа найти не смог.

sadman41
Offline
Зарегистрирован: 19.10.2016

И какие вопросу вы гуглу задавали?

https://www.google.com/search?q=почему+8+бит+это+256

strarbit
strarbit аватар
Offline
Зарегистрирован: 12.06.2016
bwn
Offline
Зарегистрирован: 25.08.2014

Neocivic пишет:

но не понимаю почему 8 бит это именно 256, а 12 бит это 4096... Может не верно гуглу вопросы задавал, ответа найти не смог.

Допустимое число неповторяющихся комбинаций ноликов и единичек при заданном количестве разрядов.

Neocivic
Offline
Зарегистрирован: 16.03.2019

bwn пишет:

Допустимое число неповторяющихся комбинаций ноликов и единичек при заданном количестве разрядов.

Спасибо, самый короткий и мне понятный ответ. :)

Neocivic
Offline
Зарегистрирован: 16.03.2019

Спасибо Вам и всем, кто ответил. :)