Передача аналогового сигнала на другую Arduino

serginusoid
Offline
Зарегистрирован: 19.08.2014

Доброго времени суток, уважаемые форумчане.Сегодня столкнулся с такой проблеммой - есть две Arduino Uno, в первой в мамяти хранится некая переменная, значение которой необходимо передать на другую Ардуинку.Полазив по справочной информации на этом сайте попытался сделать след.образом: соединил 9-й пин первой Ардуино с выходом А0 второй. В прошивке програмно отправлял с первой через команду AnalogWrite, и на второй, через команду AnalogRead() принимал.В результате получал только 2 значения 1023 и 0 (как я подозреваю оно передавало значения HIGH и LOW).Просветите неграмотного, как можно решить эту проблемму. Большое спасибо.

Leshiy
Offline
Зарегистрирован: 19.07.2014

Если значение целочисленное, то его можно передавать импульсами, например так:

Ардуино 1 устанавливает на выходе PIN3 низкий уровень сигнала. А сам выход PIN3 подключен к PIN3 на второй Ардуино, только там он не выход, а вход.
Ардуино 2 видит, что на PIN3 низкий уровень сигнала, понимает, что сейчас начнётся передача данных и разрешает работу внешних прерываний
Ардуино 1 меняет состояние на PIN4 (каждое изменение состояния это +единица к счётчику)
Ардуино 2 отлавливает по прерыванию изменение состояния на своём PIN4 и прибавляет к счётчику единицу
...
Так повторяется до тех пор, пока Ардуино 1 не передаст всю информацию. По окончании передачи Ардуино 1 устанавливает на выхоlе PIN3 высокий уровень и этим сообщает Ардуино 2, что передача окончена.
Ардуино 2 запрещает прерывания, смотрит, сколько насчитал счётчик и потом использует эти данные так, как вам нужно.

Вот таким образом можно передавать самую разнобразную информацию с одной Ардуино на другую Ардуино.

Но если этот, вне всякого сомнения, гениальный способ вам почему то не подойдёт, то можно сделать так - http://rfanat.ru/s19/ardu-sv2pl.html

===

Удивительно, но оказалось, что информации на русском о соединении двух ардуино по проводам очень мало.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

serginusoid пишет:

Доброго времени суток, уважаемые форумчане.Сегодня столкнулся с такой проблеммой - есть две Arduino Uno, в первой в мамяти хранится некая переменная, значение которой необходимо передать на другую Ардуинку.Полазив по справочной информации на этом сайте попытался сделать след.образом: соединил 9-й пин первой Ардуино с выходом А0 второй. В прошивке програмно отправлял с первой через команду AnalogWrite, и на второй, через команду AnalogRead() принимал.В результате получал только 2 значения 1023 и 0 (как я подозреваю оно передавало значения HIGH и LOW).Просветите неграмотного, как можно решить эту проблемму. Большое спасибо.

если по вашему варианту, то нужен ЦАП на 21 резисторе по схеме матрицы R2R.... такой ЦАП задействует 10 пинов на выход.... тогда ардуина_1 будет выдавать через ЦАП значения ( в виде напряжения ) 0...1023

ардуина_2 аналоговым пином сможет принимать эти значения, но с ошибкой :(

кроме ошибки ещё одна проблема - СИНХРОНИЗАЦИЯ приёма передачи

 

:) прикольный способ :) посмотрите патенты ! может этот способ ещё не запатентован :)-

Valentinych
Offline
Зарегистрирован: 13.08.2014

Целесообразнее посмотреть в сторону дельта-сигма модуляции (гугл выдаст массу информации). Для передачи сигнала достаточно 1 линии. Плюс линия для синхронизации. И никаких R2R огородов с десятью выходными пинами.

Вообще-то, вопрос в топике задан как-то странно - в шапке речь идет о передаче аналогового сигнала, в тексте - о передаче некоей переменной. Если аналоговый (периодический, непрерывный, длительный...) сигнал - то дельта-сигма, если отдельно взятая переменная - то стандартные процедуры ардуино. Кроме того, если речь идет-таки об аналоговым сигнале, желательно указать его динамический и частотный диапазоны. Это тоже сильно повлияет на выбор оптимального способа передачи. 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Valentinych пишет:

Целесообразнее посмотреть в сторону дельта-сигма модуляции (гугл выдаст массу информации). Для передачи сигнала достаточно 1 линии. Плюс линия для синхронизации. И никаких R2R огородов с десятью выходными пинами.

Вообще-то, вопрос в топике задан как-то странно - в шапке речь идет о передаче аналогового сигнала, в тексте - о передаче некоей переменной. Если аналоговый (периодический, непрерывный, длительный...) сигнал - то дельта-сигма, если отдельно взятая переменная - то стандартные процедуры ардуино. Кроме того, если речь идет-таки об аналоговым сигнале, желательно указать его динамический и частотный диапазоны. Это тоже сильно повлияет на выбор оптимального способа передачи. 

щас ( чуть позжее ) ТС прочитает - и офуеет!!!!!

не нано его грузить дельтасигмами ! пусть здеся освоится ллы начала !

std
Offline
Зарегистрирован: 05.01.2012

serginusoid, попробуйте эти способы:

1. по сериалу

Передатчик:

#include <EasyTransfer.h> 
 
struct DATA_STRUCTURE{
  //структура данных
  //должно быть одинаково у передатчика и у приёмника
  //в т. ч. переменные в одинаковом порядке
  int blinks;
  int pause;
};
 
EasyTransfer ET;
DATA_STRUCTURE myData;
 
void setup(){
  Serial.begin(9600);
  ET.begin(details(myData), &Serial);
  randomSeed(analogRead(0));  
}
 
void loop(){
  //заполняем структуру
  mydata.blinks = 5;
  mydata.pause = random(5);
  //посылаем
  ET.sendData();
  delay(5000);
}

Приёмник:

#include <EasyTransfer.h>
  
struct DATA_STRUCTURE{
  //структура данных
  int blinks;
  int pause;
};
 
EasyTransfer ET;
DATA_STRUCTURE myData;
 
void setup(){
  pinMode(13, OUTPUT); 
  Serial.begin(9600);
  ET.begin(details(myData), &Serial);
}
 
void loop(){
  //принято, мигаем
  if(ET.receiveData()){
    for(int i = 0; i < mydata.blinks; i++) {
      digitalWrite(13, HIGH);
      delay(mydata.pause * 100);
      digitalWrite(13, LOW);
      delay(mydata.pause * 100);
    }
  }
}

2. по iic

(резисторы по 4.7k)

Передатчик:

#include <Wire.h>
#include <EasyTransferI2C.h>

struct SEND_DATA_STRUCTURE{
  //структура данных для передачи
  int blinks;
  int pause;
};

SEND_DATA_STRUCTURE mydata;
EasyTransferI2C ET; 

//адрес i2c ведомого
#define I2C_SLAVE_ADDRESS 1

void setup(){
  Wire.begin();
  ET.begin(details(mydata), &Wire);  
  randomSeed(analogRead(0));  
}

void loop(){
  //заполняем структуру
  mydata.blinks = 5;
  mydata.pause = random(5);
  //посылаем
  ET.sendData(I2C_SLAVE_ADDRESS);  
  delay(5000);
}

Приёмник:

#include <Wire.h>
#include <EasyTransferI2C.h>

struct RECEIVE_DATA_STRUCTURE{
  //структура данных
  int blinks;
  int pause;
};

EasyTransferI2C ET; 
RECEIVE_DATA_STRUCTURE mydata;

#define I2C_SLAVE_ADDRESS 1
boolean receiveComplete = false; //флаг, true по факту приёма

void setup(){
  pinMode(13, OUTPUT); 
  Wire.begin(I2C_SLAVE_ADDRESS);
  ET.begin(details(mydata), &Wire);
  Wire.onReceive(receive);  
}

void loop(){
  if (receiveComplete == true){
    //пришла инфа, мигаем
    for(int i = 0; i < mydata.blinks; i++) {
      digitalWrite(13, HIGH);
      delay(mydata.pause * 100);
      digitalWrite(13, LOW);
      delay(mydata.pause * 100);
    }
    receiveComplete = false; //снимаем флаг
  }       
}

// приёмная функция
void receive(int numBytes){    
  //проверяем приход инфы, ставим флаг
  if(ET.receiveData()) {
    receiveComplete = true; 
  }
}

Архив с либой: https://github.com/madsci1016/Arduino-EasyTransfer

serginusoid
Offline
Зарегистрирован: 19.08.2014

И снова здраствуйте, почти месяц прошел, а я все еще топчусь на том же месте.)) Попытался попробовать все вышеозвученные способы (кроме модуляции, т.к. вообще не в теме). Вообщем все не получалось кроме последнего примера по сериалу(который предложил(а) std) но и с ним не все хорошо. Собственно, с ним я и пытаюсь сейчас работать. Суть в чем: сам пример работает замечательно, но я его немного изменил(в коде Приемника):

#include <EasyTransfer.h>
#include <Servo.h> 

Servo myservo;

struct DATA_STRUCTURE{
  //структура данных
  int blinks;
  int pause;

};

EasyTransfer ET;

DATA_STRUCTURE myData;

void setup(){
  pinMode(13, OUTPUT);
  myservo.attach(8);
  myservo.write(0);
  
  Serial.begin(9600);
  ET.begin(details(myData), &Serial);
}

void loop(){
  //принято, мигаем
  if(ET.receiveData()){
    myservo.write(myData.pause*10);
    for(int i = 0; i < myData.blinks; i++) {
      digitalWrite(13, HIGH);
      delay(myData.pause * 100);
      digitalWrite(13, LOW);
      delay(myData.pause * 100);
    }
  }
}

 Итак, надеюсь, идея понятна. Hо при подсоединении к платке Приемника  сервопривода, он(серв), работать не будет потому нет питания, поэтому было логично, по крайней мере для меня питание подключить. И тут начались проблеммы - платка Приемника подключалась через USB порт в результате чего все просто переставало работать(как я думаю, это связано с внутренней логикой контроллера), а в Serial Monitor (Передатчика) вместо нормальных значений появляется абаркадабра какая-то(в коде Передатчика я вставил в loop метод Serial.println(myData.pause) чтобы отслеживать правильность значений). Собственно в чем может быть проблемма?

std
Offline
Зарегистрирован: 05.01.2012

После вызова метода ET.begin() вывод информации в Serial monitor невозможен. Сериал не может одновременно пропускать через себя и отладочную информацию, и трафик EasyTransfer.

Как вариант, можно передавать по i2c. Приём по этой шине должен работать. Пробовался ли этот вариант?

Кстати, существует реализация через программный сериал, называется SoftEasyTransfer. И кстати, скорее всего всё вышеперечисленное вряд-ли нужно. Читайте пример EasyTransfer_2Way_wServo_Example.

serginusoid
Offline
Зарегистрирован: 19.08.2014

Получается, я не могу подключить сериал к связке из двух ардуин? Если так, то как это можно обойти, если это вообще возможно?

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

serginusoid пишет:

Получается, я не могу подключить сериал к связке из двух ардуин? Если так, то как это можно обойти, если это вообще возможно?


Давайте представим сериал как 2 трубы в одну кричишь из другой слушаешь. Пока у вас 2 человека они могут орать и говорить одновременно. Полный дуплекс. А если 3 и все говорят одновременно, то получается фигня и никто не слышит никого.

vvadim
Offline
Зарегистрирован: 23.05.2012

Попробуйте 

A New Software Serial Library for Arduino

Делает ещё один Serial port на двух цифровых выходах

SLOM
Offline
Зарегистрирован: 06.11.2014

подскажите пожалуйста как сделать код под мои нужды: 

 

у меня есть плата в которой спаяны и ардуино и мотор шилд. 

на ней нехватает свободных пинов, для этих целей я хочу управлять ею с другой платы через UART 

вот то что я хочу получить в картинках: 

оно же в расширеной версии. 

 

 

у меня колесный робот. на котором 2 канала моторов. и нужно управлять кучей серво приводов и нагрузок. на камеру и эхолот внимания не обращайте... это так, может быть в будущем. 

все перерыл немогу найти приеру где бы через EasyTransfer или еще как то я мог управлять моторами и сервами одной ардуины через другую с геймпада по блютус, о как :)

 

на данный момент все управление идет через телефон по блютусу, на тирекс контролер

// Скетч для управления через блютус, Wild Thumper 6WD, на ардуино совместимом контролере TREX controller. реализовано движение и стрельба с водомета, захват клешней манипулятором. 
// по вопросам и предложениям писать на почту slom1@list.ru 
// новые фото и видео можно найти на www.шоуальянс.com

#include <BTCA2ALite.h>// Добавляем библиотеку блютус программы
#include <Servo.h> // Добавляем библиотеку серво

Servo myservoH; // Горизонтальная серва углы от 0 до 180 (центровка 89)
Servo myservoV; // Вертикальная серва углы от 1 до 45
Servo myservoZ; // серва Клешня
Servo myservoR; // серва рука клешни
const int Z_SERVO_PIN = 5; // добовляем пин захвата
const int R_SERVO_PIN = 6; // добовляем пин руки манипулятора
const int H_SERVO_PIN = 7; // Горизонтальная серва подключена к пину 7
const int V_SERVO_PIN = 8; //Пин вертикального сервопривода 8
const float Z_L_ANGLE = 116; // Максимальные угл поворота башни налево
const float Z_R_ANGLE = 45; // Максимальные угл поворота башни направо
const float Z_DEF_ANGLE = 50; // Дефолтный угол (центровка)
const float R_L_ANGLE = 178; // Максимальные угл поднятия руки
const float R_R_ANGLE = 3; // Максимальные угл наклона руки
const float R_DEF_ANGLE = 160; // Дефолтный угол руки
const float H_L_ANGLE = 180; // Максимальные угл поворота башни налево
const float H_R_ANGLE = 0; // Максимальные угл поворота башни направо
const float H_DEF_ANGLE = 84; // Дефолтный угол (центровка)
const float V_U_ANGLE = 140; // Максимальные угл поворота башни вверх
const float V_D_ANGLE = 45; // Максимальные угл поворота башни вниз
const float V_DEF_ANGLE = 60; // Дефолтный угол (центровка)
//Размер шага V_STEP и H_STEP побираем экспериментально для достижения нужной скорости поворота серв
const float V_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по вертикали.
const float H_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по горизонтали
const float Z_STEP = 0.012; // шаг захвата
const float R_STEP = 0.012; // шаг руки
float curVAngle = V_DEF_ANGLE; //Переменная текущего угла верт. сервы
float curHAngle = H_DEF_ANGLE; //Переменная текущего угла гор. сервы
float curZAngle = Z_DEF_ANGLE; //
float curRAngle = R_DEF_ANGLE; //
bool moveServoVUp = false; //Флаг движения верт. сервы вверх
bool moveServoVDown = false; //Флаг движения верт. сервы вниз
bool moveServoHLeft = false; //Флаг движения гор. сервы влево
bool moveServoHRight = false; //Флаг движения гор. сервы вправо
bool moveServoZLeft = false; //Флаг движения гор. сервы влево
bool moveServoZRight = false; //Флаг движения гор. сервы вправо
bool moveServoRLeft = false; //Флаг движения гор. сервы влево
bool moveServoRRight = false; //Флаг движения гор. сервы вправо

btca2aLite btca2aLite; // Конструктор btca2aLite


// задаем пины для левого мотора
#define Dir_L 2
#define Pwm_L 3
#define Brake_L 4
// задаем пины для правого мотора
#define Dir_R 10
#define Pwm_R 11
#define Brake_R 9

// Задаем скорости для движения
byte MaxSpeed = 230; // Максимальная скорость
byte MinSpeed = 90;  // Минимальная скорость

int forw_back = 0;
int righ_left = 0;

byte step_fb = 5;     // Шаг изменения скорости движения вперед - назад
byte step_stop = 10;  // Шаг изменения скорости остановки
byte step_rl =  10;    // Шаг изменения скорости движения вправо - влево
byte step_dir = 10;   // Шаг изменения скорости выравнивания



#define SHOT  12 // пин для водомета

enum States
{
    WAITING,
    READING,
    RUNNING,
    ERROR,
    TIMEOUT
};

States state;
States onWait();
States onRead();
States onRun();
States onError();

States onTimeout();

void performServo(); // добовляем сервы


void setup(){
    Serial.begin(9600); // Скорость BT и порта должна быть 9600
    //Моторы
    pinMode (Pwm_L, OUTPUT);
    pinMode (Dir_L, OUTPUT);
    pinMode (Brake_L, OUTPUT);
    
    pinMode (Pwm_R, OUTPUT);
    pinMode (Dir_R, OUTPUT);
    pinMode (Brake_R, OUTPUT);
    
    digitalWrite (Pwm_L, LOW);
    digitalWrite (Pwm_R, LOW);
    
    digitalWrite (Brake_L, LOW);
    digitalWrite (Brake_R, LOW);
  
 pinMode(SHOT, OUTPUT); // задаем выход для стрельбы водой
    
    // устанавливаем пин как вывод управления сервой
    myservoH.attach(H_SERVO_PIN);
    myservoV.attach(V_SERVO_PIN);
    myservoZ.attach(Z_SERVO_PIN);
    myservoR.attach(R_SERVO_PIN);
    myservoH.write(curHAngle);
    myservoV.write(curVAngle);
    myservoZ.write(curZAngle);
    myservoR.write(curRAngle);
    
    //Светодиод
    pinMode(13, OUTPUT); // Инициализируем пин светодиода
    digitalWrite(13, HIGH); // Светодиод выключен
}

void loop(){
    
    btca2aLite.ReadCommand(); // Считывание принятых команд (кодов кнопок)
    //Вызываем функцию управление сервами
    performServo();
    
 //этот код для меня темный лес, мне его дали для плавного старта и торможения моторов. если ехать вперед и резко нажать кнопку назад, машина продолжит ехать вперед, плавно остановиться и только потом поедет назад, это спасает редуктора от разрушения. 
 //если ктото знает что тут к чему, прокоментируйте пожалуйста, чтоб я тоже понимал :)
  static unsigned long pre_millis = 0;
  if(millis()-pre_millis > 50)
  {
    pre_millis = millis();
    
    if(btca2aLite.ButtonPressed(KEYCODE_DPAD_UP)) 
    {
      forw_back += step_fb;
      if(forw_back > 0 && forw_back < MinSpeed) forw_back = MinSpeed;
    }
    else if(btca2aLite.ButtonPressed(KEYCODE_DPAD_DOWN)) 
    {
      forw_back -= step_fb;
      if(forw_back < 0 && forw_back > MinSpeed*-1) forw_back = MinSpeed*-1;
    }
    else 
    {
      if(forw_back < 0) forw_back += step_stop;
      else if(forw_back > 0) forw_back -= step_stop;
      if(abs(forw_back) < MinSpeed) forw_back = 0;
    }
    forw_back = constrain(forw_back, MaxSpeed*-1, MaxSpeed);


    if(btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)) 
    {
      righ_left += step_rl;
      if(righ_left > 0 && righ_left < MinSpeed) righ_left = MinSpeed;
    }
    else if(btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)) 
    {
      righ_left -= step_rl;
      if(righ_left < 0 && righ_left > MinSpeed*-1) righ_left = MinSpeed*-1;
    }
    else 
    {
      if(righ_left < 0) righ_left += step_dir;
      else if(righ_left > 0) righ_left -= step_dir;
      if(abs(righ_left) < MinSpeed) righ_left = 0;
    }
    righ_left = constrain(righ_left, MaxSpeed*-1, MaxSpeed);


    int pwm_l = forw_back + righ_left;
    int pwm_r = forw_back - righ_left;
    pwm_l = constrain(pwm_l, MaxSpeed*-1, MaxSpeed);
    pwm_r = constrain(pwm_r, MaxSpeed*-1, MaxSpeed);

    digitalWrite(Dir_L, (pwm_l<0)?0:1);
    digitalWrite(Dir_R, (pwm_r<0)?0:1);
    analogWrite(Pwm_L, abs(pwm_l));
    analogWrite(Pwm_R, abs(pwm_r));
  }
        
  //дальше идут кнопки управления
    
    //-------— включение насоса —-------------
   if (btca2aLite.ButtonPressed(KEYCODE_BUTTON_SELECT))
    { 
     digitalWrite (SHOT, HIGH);
     }
    //-------— выключение насоса происходит автоматически после отпускания кнопки—------------- 
   if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_SELECT))
    {
   digitalWrite (SHOT, LOW);
    } 
    
        if(btca2aLite.Button(KEYCODE_BUTTON_START)) // алгоритм автоматического хватания предметов
    {
       
 /* шаг вперед, отключил....
      digitalWrite (Dir_L, HIGH); 
      analogWrite (Pwm_L, 150); 
      digitalWrite (Dir_R, HIGH); 
      analogWrite (Pwm_R, 150); 
      delay (100);
      // потом стоп
      analogWrite (Pwm_L, 0); 
      analogWrite (Pwm_R, 0); 
      delay (500);
 */
      
       myservoZ.write(45);; // Клешня разжимается 
        myservoR.write(3);; // рука клешни опускаем 
        delay(2000); /* ждем 2 секунды, */
         myservoZ.write(116);; // Клешня сжимаем
         delay(1000); /* ждем 1 секунду, */
          myservoR.write(170);; // рука клешни поднимаем
           delay(1000); /* ждем  */
           myservoZ.write(45);; // Клешня разжимаем
    } 
    
    
    //--------— Повороты серв при нажатии кнопок —-------------
    
    if(btca2aLite.Button(KEYCODE_BUTTON_X)) // поворот водомета вниз
    {
        moveServoVDown = true;
              
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_A)) // поворот водомета направо
    {
        moveServoHRight = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_B)) // поворот водомета вверх
    {
        moveServoVUp = true;
              
    }
    
    if(btca2aLite.Button(KEYCODE_BUTTON_Y)) // поворот водомета налево
    {
        moveServoHLeft = true;
    }
    
        if(btca2aLite.Button(KEYCODE_BUTTON_R1)) // зхахват сжать
    {
        moveServoZLeft = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_R2)) // захват разжать 
    {
        moveServoZRight = true;
    }
    
    
           if(btca2aLite.Button(KEYCODE_BUTTON_L1)) // рука клешни вниз
    {
        moveServoRLeft = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_L2)) // рука клешни вверх
    {
        moveServoRRight = true;
    } 
    
    
//--------— чтобы сервы не продолжали движения при отжатых кнопках —-------------    
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_X))
{
moveServoVDown = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_B))
{
moveServoVUp = false;
}

if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_A))
{
moveServoHRight = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_Y))
{
moveServoHLeft = false;
}
 
 if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_R2))
{
moveServoZRight = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_R1))
{
moveServoZLeft = false;
}   
    
 if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_L2))
{
moveServoRRight = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_L1))
{
moveServoRLeft = false;
}       
    
    
    //----------------— Стоп —---------------------
    
    // Если не нажата ни одна кнопка курсора происходит остановка, скорость 0 для каждого мотора
    if (btca2aLite.ButtonReleased(KEYCODE_DPAD_UP) && btca2aLite.ButtonReleased(KEYCODE_DPAD_DOWN) && btca2aLite.ButtonReleased(KEYCODE_DPAD_LEFT) && btca2aLite.ButtonReleased(KEYCODE_DPAD_RIGHT)){
        analogWrite (Pwm_L, 0);
        analogWrite (Pwm_R, 0);
    }
}



//Функция управления сервоприводами (вызывается в теле loop на каждой итерации)
//Выполняет изменения положения серв на подобранный шаг согласно установленным флагам движения
//Флаги устанавливаются согласно поступившим символам управления сервами
void performServo()
{
    //Установлен флаг движения вверх и текущий угол не максимальный
    if (moveServoVUp && curVAngle + V_STEP <= V_U_ANGLE)
    {
        //К текущему верт. углу прибавляем шаг
        curVAngle += V_STEP;
    }
    //Установлен флаг движения вниз и текущий угол не минимален
    else if (moveServoVDown && curVAngle - V_STEP >= V_D_ANGLE)
    {
        //От текущего верт. угла отнимаем шаг
        curVAngle -= V_STEP;
    }
    //Установлен флаг движения влево и текущий угол не максимален
    if (moveServoHLeft && curHAngle + H_STEP <= H_L_ANGLE)
    {
        //К текущему гор. углу прибавляем гор. шаг
        curHAngle += H_STEP;
    }
    //Установлен флаг движения вправо и текущий угол не минимален
    else if (moveServoHRight && curHAngle - H_STEP >= H_R_ANGLE)
    {
        //От текущего угла отнимаем гор. шаг
        curHAngle -= H_STEP;
    }
    
    //Установлен 
    if (moveServoZLeft && curZAngle + Z_STEP <= Z_L_ANGLE)
    {
        //К текущему гор. углу прибавляем гор. шаг
        curZAngle += Z_STEP;
    }
    //Установлен флаг движения вправо и текущий угол не минимален
    else if (moveServoZRight && curZAngle - Z_STEP >= Z_R_ANGLE)
    {
        //От текущего угла отнимаем гор. шаг
        curZAngle -= Z_STEP;
    }
    
    
        //Установлен 
    if (moveServoRLeft && curRAngle + R_STEP <= R_L_ANGLE)
    {
        //К текущему гор. углу прибавляем гор. шаг
        curRAngle += R_STEP;
    }
    //Установлен флаг движения вправо и текущий угол не минимален
    else if (moveServoRRight && curRAngle - R_STEP >= R_R_ANGLE)
    {
        //От текущего угла отнимаем гор. шаг
        curRAngle -= R_STEP;
    }
    
    //Если было движние по вертикали
    if (moveServoVUp || moveServoVDown)
    {
        myservoV.write(curVAngle);
    }
    //Если было движение по горизонтали
    if (moveServoHLeft || moveServoHRight)
    {
        myservoH.write(curHAngle);
    }
    
    if (moveServoZLeft || moveServoZRight)
    {
        myservoZ.write(curZAngle);
    }
    
        if (moveServoRLeft || moveServoRRight)
    {
        myservoR.write(curRAngle);
    }
}

 

в качестве теста, на другой плате использаван вот такой код, управляется с джойсткика 2 сервы: 

#include <PS2X_lib.h>  //for v1.6
#include <Servo.h>
PS2X ps2x;
int PS2 = 0; 
Servo LXservo;
Servo LYservo;
#define L_dir 2   //пины для драйвера мотора
#define L_pwm 3
#define R_dir 4
#define R_pwm 5

int mass[4];      //здесь будем хранить значения для скоростей и направлений
                  //mass[0]   лев.напр.
                  //mass[1]   лев.скор.
                  //mass[2]   прав.напр.
                  //mass[3]   прав.скор.
                 
void setup(){
  LXservo.attach(8);
  LYservo.attach(6);
  
  PS2 = ps2x.config_gamepad(13,11,10,12, true, true);   //Настройка выводов: (clock, command, attention, data, true, true)
  pinMode(L_dir, OUTPUT);
  pinMode(L_pwm, OUTPUT);
  pinMode(R_dir, OUTPUT);
  pinMode(R_pwm, OUTPUT);
}

void loop(){
  LXservo.write(map(ps2x.Analog(PSS_LX), 255, 0, 0, 180)); ; 
 delay(50); 
  ps2x.read_gamepad(false, 0);
  
  LYservo.write(map(ps2x.Analog(PSS_LY), 0, 255, 0, 90)); ; 
 delay(50); 
  ps2x.read_gamepad(false, 0);
  
  
    dir_pwm(ps2x.Analog(PSS_RY),2);   //обрабатываем правый джойстик
  digitalWrite(R_dir, mass[2]);
  analogWrite(R_pwm, mass[3]);
}    

void dir_pwm(int Y, int n){         //Подпрограмма для обработки значений джойстика
  if (Y == 128){
    mass[n+1] = 0;
  }
  if (Y >128){
    mass[n+1] = Y*2-255;
    mass[n] = 1;
  }
  if (Y <128){
    mass[n+1] = 255-Y*2;
    mass[n] = 0;
  }
}

код нашел в одной из здешних тем.  

doom369
Offline
Зарегистрирован: 13.05.2015

Если железки подключены к интренету (можно по ЮСБ), то это можно сделать с помощью проекта Blynk. Пример скетча. Геттинг стартет.

SLOM
Offline
Зарегистрирован: 06.11.2014
мне на другом форуме помогли разобраться  с кодом для работы моторов и серв через I2C интерфейс с управлением от блютус джойстика PS2
выкладываю скетчи, может кому то пригодиться.
за основу взят скетч для контролера ТИРЕКС
скачать можно:
 
этот скетч заливается как есть в управляемую ардуину, в моем случае это и есть контролер ТИРЕКС. 
к этой плате присоединяем двигатели(х2) и сервы(х2)
 
соединяем через I2C интерфейс со 2й платой ардуино.(в моем случае нано.) Ардуино нано соединяем с блютус модулем от геймпада. 
и заливаем скетч: 
#include <PS2X_lib.h>  //for v1.6 библиотека джойстика
#include <Wire.h>


#include <Servo.h>

Servo RXservo; //подключаем сервы 
Servo RYservo;

#define ledPin 13
#define startbyte 0x0F
#define I2Caddress 0x07
int sv[6]={1000,1400,1500,1500,0,0};      //заданны позиции серво приводов, на тирексе их 6 штук, из них первые две отключены, им соответствуют значения = 0, на плате это 5 и 6 пины. далее 1000 = 7 пин, 1400 = 8 пин...           // servo positions: 0 = Not Used 
int sd[6]={5,10,-5,-15,20,-20};                      // servo sweep speed/direction
int lmspeed,rmspeed;                                 // left and right motor speed from -255 to +255 (negative value = reverse)
int ldir=5;                                          // how much to change left  motor speed each loop (use for motor testing)
int rdir=5;                                          // how much to change right motor speed each loop (use for motor testing)
byte lmbrake,rmbrake;                                // left and right motor brake (non zero value = brake)
byte devibrate=50;                                   // time delay after impact to prevent false re-triggering due to chassis vibration
int sensitivity=50;                                  // threshold of acceleration / deceleration required to register as an impact
int lowbat=550;                                      // adjust to suit your battery: 550 = 5.50V
byte i2caddr=7;                                      // default I2C address of T'REX is 7. If this is changed, the T'REX will automatically store new address in EEPROM
byte i2cfreq=0;                                      // I2C clock frequency. Default is 0=100kHz. Set to 1 for 400kHz




/******************************************************************
 * set pins connected to PS2 controller:
 *   - 1e column: original 
 *   - 2e colmun: Stef?
 * replace pin numbers by the ones you use
 //подключение пинов блютус модуля геймпада:
 ******************************************************************/
#define PS2_DAT        12  //14    
#define PS2_CMD        11  //15
#define PS2_SEL        10  //16
#define PS2_CLK        9  //17

/******************************************************************
 * select modes of PS2 controller:
 *   - pressures = analog reading of push-butttons 
 *   - rumble    = motor rumbling
 * uncomment 1 of the lines for each mode selection
 ******************************************************************/
//#define pressures   true
#define pressures   false
//#define rumble      true
#define rumble      false

PS2X ps2x; // create PS2 Controller Class
int PS2 = 0; 
//right now, the library does NOT support hot pluggable controllers, meaning 
//you must always either restart your Arduino after you connect the controller, 
//or call config_gamepad(pins) again after connecting the controller.

int error = 0;
byte type = 0;
byte vibrate = 0;

void setup(){
 
  //пины серв
  RXservo.attach(3);
  RYservo.attach(4);
  
  Serial.begin(57600);
  pinMode(ledPin, OUTPUT);
  Wire.begin();                // no address - join the bus as master
    
  delay(300);  //added delay to give wireless ps2 module some time to startup, before configuring it
   
  //CHANGES for v1.6 HERE!!! **************PAY ATTENTION*************
  
  //setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
  error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble);
  
  if(error == 0){
    Serial.print("Found Controller, configured successful ");
    Serial.print("pressures = ");
	if (pressures)
	  Serial.println("true ");
	else
	  Serial.println("false");
	Serial.print("rumble = ");
	if (rumble)
	  Serial.println("true)");
	else
	  Serial.println("false");
  }  
  else
    Serial.println("Большой еггог :)");
   
  
//  Serial.print(ps2x.Analog(1), HEX);
  
  type = ps2x.readType(); 
  switch(type) {
    case 0:
      Serial.print("Unknown Controller type found ");
      break;
    case 1:
      Serial.print("DualShock Controller found ");
      break;
    case 2:
      Serial.print("GuitarHero Controller found ");
      break;
	case 3:
      Serial.print("Wireless Sony DualShock Controller found ");
      break;
   }
}

void loop() {
  /* You must Read Gamepad to get new values and set vibration values
     ps2x.read_gamepad(small motor on/off, larger motor strenght from 0-255)
     if you don't enable the rumble, use ps2x.read_gamepad(); with no values
     You should call this at least once a second
   */  
  if(error == 1) //skip loop if no controller found
    return; 
  
  if(type == 2){ //Guitar Hero Controller
    ps2x.read_gamepad();          //read controller 
   
    if(ps2x.ButtonPressed(GREEN_FRET))
      Serial.println("Green Fret Pressed");
    if(ps2x.ButtonPressed(RED_FRET))
      Serial.println("Red Fret Pressed");
    if(ps2x.ButtonPressed(YELLOW_FRET))
      Serial.println("Yellow Fret Pressed");
    if(ps2x.ButtonPressed(BLUE_FRET))
      Serial.println("Blue Fret Pressed");
    if(ps2x.ButtonPressed(ORANGE_FRET))
      Serial.println("Orange Fret Pressed"); 

    if(ps2x.ButtonPressed(STAR_POWER))
      Serial.println("Star Power Command");
    
    if(ps2x.Button(UP_STRUM))          //will be TRUE as long as button is pressed
      Serial.println("Up Strum");
    if(ps2x.Button(DOWN_STRUM))
      Serial.println("DOWN Strum");
 
    if(ps2x.Button(PSB_START))         //will be TRUE as long as button is pressed
      Serial.println("Start is being held");
    if(ps2x.Button(PSB_SELECT))
      Serial.println("Select is being held");
    
    if(ps2x.Button(ORANGE_FRET)) {     // print stick value IF TRUE
      Serial.print("Wammy Bar Position:");
      Serial.println(ps2x.Analog(WHAMMY_BAR), DEC); 
    } 
  }
  else { //DualShock Controller
    ps2x.read_gamepad(false, vibrate); //read controller and set large motor to spin at 'vibrate' speed
    
    if(ps2x.Button(PSB_START))         //will be TRUE as long as button is pressed
      Serial.println("Start is being held");
    if(ps2x.Button(PSB_SELECT))
      Serial.println("Select is being held");      

    if(ps2x.Button(PSB_PAD_UP)) {      //will be TRUE as long as button is pressed
      Serial.print("Up held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_UP), DEC);
    }
    if(ps2x.Button(PSB_PAD_RIGHT)){
      Serial.print("Right held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC);
    }
    if(ps2x.Button(PSB_PAD_LEFT)){
      Serial.print("LEFT held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_LEFT), DEC);
    }
    if(ps2x.Button(PSB_PAD_DOWN)){
      Serial.print("DOWN held this hard: ");
      Serial.println(ps2x.Analog(PSAB_PAD_DOWN), DEC);
    }   

    vibrate = ps2x.Analog(PSAB_CROSS);  //this will set the large motor vibrate speed based on how hard you press the blue (X) button
    if (ps2x.NewButtonState()) {        //will be TRUE if any button changes state (on to off, or off to on)
      if(ps2x.Button(PSB_L3))
        Serial.println("L3 pressed");
      if(ps2x.Button(PSB_R3))
        Serial.println("R3 pressed");
      if(ps2x.Button(PSB_L2))
        Serial.println("L2 pressed");
      if(ps2x.Button(PSB_R2))
        Serial.println("R2 pressed");
      if(ps2x.Button(PSB_TRIANGLE))
        Serial.println("Triangle pressed");        
    }

    if(ps2x.ButtonPressed(PSB_CIRCLE))               //will be TRUE if button was JUST pressed
      Serial.println("Circle just pressed");
    if(ps2x.NewButtonState(PSB_CROSS))               //will be TRUE if button was JUST pressed OR released
      Serial.println("X just changed");
    if(ps2x.ButtonReleased(PSB_SQUARE))              //will be TRUE if button was JUST released
      Serial.println("Square just released");     

    Serial.print("Stick:");

//управление моторам через левый стик геймпада
   lmspeed = -(ps2x.Analog(PSS_LY)-128); //скопировать данные джойстика в регистры правого и левого двигателя
    int tmp = -(ps2x.Analog(PSS_LX)-128); //
    rmspeed = lmspeed;
    lmspeed -= tmp; lmspeed *=2;
    rmspeed += tmp; rmspeed *=2;
    if (lmspeed>255) lmspeed =255;        //ограничить макс. значения моторов
    if (rmspeed>255) rmspeed =255;        //
    if (lmspeed<-255) lmspeed =-255;      //
    if (rmspeed<-255) rmspeed =-255;      //

    lmbrake =0;				 //выкл. стоп
    rmbrake =0;				 //
    
 //управление сервами через правый стик геймпада, реализовано 2мя разными методами, результат примерно одинаковый:    
    
 sv[0] = (map(ps2x.Analog(PSS_RY), 0, 255, 1000, 2000)); ; 
 sv[1] = 1500 -(ps2x.Analog(PSS_RX)-128)*2;
 //
    
    Serial.print(lmspeed, DEC); //Left stick, Y axis. Other options: LX, RY, RX  
    Serial.print(",");
    Serial.print(rmspeed, DEC); 
    Serial.print(",");
    
    RXservo.write(map(ps2x.Analog(PSS_RX), 255, 0, 0, 180)); ; 
 delay(50); 
  ps2x.read_gamepad(false, 0);
  
  RYservo.write(map(ps2x.Analog(PSS_RY), 0, 255, 0, 90)); ; 
 delay(50); 
  ps2x.read_gamepad(false, 0);

 //    Serial.print(ps2x.Analog(PSS_RY), DEC); 
  //   Serial.print(",");
   //  Serial.print(ps2x.Analog(PSS_RX), DEC); 
   //  Serial.println("\t");
  }
  digitalWrite(ledPin, HIGH);

 MasterSend(startbyte,2,lmspeed,lmbrake,rmspeed,rmbrake,sv[0],sv[1],sv[2],sv[3],sv[4],sv[5],devibrate,sensitivity,lowbat,i2caddr,i2cfreq);
  delay(20);
  MasterReceive();    // receive data packet from T'REX controller 
}


void MasterSend(byte sbyte, byte pfreq, int lspeed, byte lbrake, int rspeed, byte rbrake, int sv0, int sv1, int sv2, int sv3, int sv4, int sv5, byte dev,int sens,int lowbat, byte i2caddr,byte i2cfreq)
{
  Wire.beginTransmission(I2Caddress); // transmit data to 7
  Wire.write(startbyte);              // start byte
  Wire.write(pfreq);                  // pwm frequency
  
  Wire.write(highByte(lspeed));       // MSB left  motor speed
  Wire.write( lowByte(lspeed));       // LSB left  motor speed
  Wire.write(lbrake);                 // left  motor brake
  
  Wire.write(highByte(rspeed));       // MSB right motor speed
  Wire.write( lowByte(rspeed));       // LSB right motor speed
  Wire.write(rbrake);                 // right motor brake
  
  Wire.write(highByte(sv0));          // MSB servo 0
  Wire.write( lowByte(sv0));          // LSB servo 0
  
  Wire.write(highByte(sv1));          // MSB servo 1
  Wire.write( lowByte(sv1));          // LSB servo 1
  
  Wire.write(highByte(sv2));          // MSB servo 2
  Wire.write( lowByte(sv2));          // LSB servo 2
  
  Wire.write(highByte(sv3));          // MSB servo 3
  Wire.write( lowByte(sv3));          // LSB servo 3
  
  Wire.write(highByte(sv4));          // MSB servo 4
  Wire.write( lowByte(sv4));          // LSB servo 4
  
  Wire.write(highByte(sv5));          // MSB servo 5
  Wire.write( lowByte(sv5));          // LSB servo 5
  
  Wire.write(dev);                    // devibrate
  Wire.write(highByte(sens));         // MSB impact sensitivity
  Wire.write( lowByte(sens));         // LSB impact sensitivity
  
  Wire.write(highByte(lowbat));       // MSB low battery voltage  550 to 30000 = 5.5V to 30V
  Wire.write( lowByte(lowbat));       // LSB low battery voltage
  
  Wire.write(i2caddr);                // I2C slave address for T'REX controller
  Wire.write(i2cfreq);                // I2C clock frequency:   0=100kHz   1=400kHz
  Wire.endTransmission();             // stop transmitting
  
  //Serial.println("Master Command Data Packet Sent");
  
  
  //-------------------------------- Make sure Master and Slave I2C clock the same ------------------------------------------------
  
  if(i2cfreq==0)                                                               // thanks to Nick Gammon: http://gammon.com.au/i2c
  {
    TWBR=72;                                                                   // default I²C clock is 100kHz
  }
  else
  {
    TWBR=12;                                                                   // changes the I²C clock to 400kHz
  }
}


void MasterReceive()
{//================================================================= Error Checking ==========================================================
  byte d;
  int i=0;
  Wire.requestFrom(I2Caddress,24);                                // request 24 bytes from device 007
  
  while(Wire.available()<24)                                      // wait for entire data packet to be received
  {
    if(i==0) Serial.print("Waiting for slave to send data.");     // Only print message once (i==0)
    if(i>0) Serial.print(".");                                    // print a dot for every loop where buffer<24 bytes
    i++;                                                          // increment i so that message only prints once.
    if(i>79)
    {
      Serial.println("");
      i=1;
    }
  }
  d=Wire.read();                                                  // read start byte from buffer
  if(d!=startbyte)                                                // if start byte not equal to 0x0F                                                    
  {
    Serial.print(d,DEC);
    while(Wire.available()>0)                                     // empty buffer of bad data
    {
      d=Wire.read();
    }
    Serial.println("  Wrong Start Byte");                         // error message
    return;                                                       // quit
  }
  
  //================================================================ Read Data ==============================================================

  //Serial.print(". Trex Err:");                           // slave error report
  Serial.print(Wire.read(),DEC);
  
  i=Wire.read()*256+Wire.read();                                  // T'REX battery voltage
  Serial.print(" Akk:");
  Serial.print(int(i/10));Serial.print(".");                      
  Serial.print(i-(int(i/10)*10));Serial.print("V");
  
  i=Wire.read()*256+Wire.read();
  Serial.print("\tL Curr:");
  Serial.print(i);Serial.print("mA");                           // T'REX left  motor current in mA
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" Enc:");
  Serial.print(i);                                              // T'REX left  motor encoder count
  
  i=Wire.read()*256+Wire.read();
  Serial.print("\tR Curr:");
  Serial.print(i);Serial.print("mA");                           // T'REX right motor current in mA
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" Enc:");
  Serial.print(i);                                              // T'REX right motor encoder count
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" X-axis:");
  Serial.print(i);                                              // T'REX X-axis
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" Y:");
  Serial.print(i);                                              // T'REX Y-axis
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" Z:");
  Serial.print(i);                                              // T'REX Z-axis
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" X-delta:");
  Serial.print(i);                                              // T'REX X-delta
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" Y:");
  Serial.print(i);                                              // T'REX Y-delta
  
  i=Wire.read()*256+Wire.read();
  Serial.print(" Z:");
  Serial.println(i);                                              // T'REX Z-delta
}

 

 
 
 
важный момент, при соеденении по И2С шине, на плате тирекс нужно на один из пинов и2с разьема подавать +5в для активации этого соединения, если питание не подать, ничего работать не будет! 
после включения тирекса через сек 10 происходит бип моторам - тирекс готов. после этого можно включать нану, и сразу жать ресет, не знаю почему, если ресет не нажать то соединение не устанавливается.