Передача аналогового сигнала на другую Arduino
- Войдите на сайт для отправки комментариев
Втр, 19/08/2014 - 02:29
Доброго времени суток, уважаемые форумчане.Сегодня столкнулся с такой проблеммой - есть две Arduino Uno, в первой в мамяти хранится некая переменная, значение которой необходимо передать на другую Ардуинку.Полазив по справочной информации на этом сайте попытался сделать след.образом: соединил 9-й пин первой Ардуино с выходом А0 второй. В прошивке програмно отправлял с первой через команду AnalogWrite, и на второй, через команду AnalogRead() принимал.В результате получал только 2 значения 1023 и 0 (как я подозреваю оно передавало значения HIGH и LOW).Просветите неграмотного, как можно решить эту проблемму. Большое спасибо.
Если значение целочисленное, то его можно передавать импульсами, например так:
Ардуино 1 устанавливает на выходе PIN3 низкий уровень сигнала. А сам выход PIN3 подключен к PIN3 на второй Ардуино, только там он не выход, а вход.
Ардуино 2 видит, что на PIN3 низкий уровень сигнала, понимает, что сейчас начнётся передача данных и разрешает работу внешних прерываний
Ардуино 1 меняет состояние на PIN4 (каждое изменение состояния это +единица к счётчику)
Ардуино 2 отлавливает по прерыванию изменение состояния на своём PIN4 и прибавляет к счётчику единицу
...
Так повторяется до тех пор, пока Ардуино 1 не передаст всю информацию. По окончании передачи Ардуино 1 устанавливает на выхоlе PIN3 высокий уровень и этим сообщает Ардуино 2, что передача окончена.
Ардуино 2 запрещает прерывания, смотрит, сколько насчитал счётчик и потом использует эти данные так, как вам нужно.
Вот таким образом можно передавать самую разнобразную информацию с одной Ардуино на другую Ардуино.
Но если этот, вне всякого сомнения, гениальный способ вам почему то не подойдёт, то можно сделать так - http://rfanat.ru/s19/ardu-sv2pl.html
===
Удивительно, но оказалось, что информации на русском о соединении двух ардуино по проводам очень мало.
Доброго времени суток, уважаемые форумчане.Сегодня столкнулся с такой проблеммой - есть две Arduino Uno, в первой в мамяти хранится некая переменная, значение которой необходимо передать на другую Ардуинку.Полазив по справочной информации на этом сайте попытался сделать след.образом: соединил 9-й пин первой Ардуино с выходом А0 второй. В прошивке програмно отправлял с первой через команду AnalogWrite, и на второй, через команду AnalogRead() принимал.В результате получал только 2 значения 1023 и 0 (как я подозреваю оно передавало значения HIGH и LOW).Просветите неграмотного, как можно решить эту проблемму. Большое спасибо.
если по вашему варианту, то нужен ЦАП на 21 резисторе по схеме матрицы R2R.... такой ЦАП задействует 10 пинов на выход.... тогда ардуина_1 будет выдавать через ЦАП значения ( в виде напряжения ) 0...1023
ардуина_2 аналоговым пином сможет принимать эти значения, но с ошибкой :(
кроме ошибки ещё одна проблема - СИНХРОНИЗАЦИЯ приёма передачи
:) прикольный способ :) посмотрите патенты ! может этот способ ещё не запатентован :)-
Целесообразнее посмотреть в сторону дельта-сигма модуляции (гугл выдаст массу информации). Для передачи сигнала достаточно 1 линии. Плюс линия для синхронизации. И никаких R2R огородов с десятью выходными пинами.
Вообще-то, вопрос в топике задан как-то странно - в шапке речь идет о передаче аналогового сигнала, в тексте - о передаче некоей переменной. Если аналоговый (периодический, непрерывный, длительный...) сигнал - то дельта-сигма, если отдельно взятая переменная - то стандартные процедуры ардуино. Кроме того, если речь идет-таки об аналоговым сигнале, желательно указать его динамический и частотный диапазоны. Это тоже сильно повлияет на выбор оптимального способа передачи.
Целесообразнее посмотреть в сторону дельта-сигма модуляции (гугл выдаст массу информации). Для передачи сигнала достаточно 1 линии. Плюс линия для синхронизации. И никаких R2R огородов с десятью выходными пинами.
Вообще-то, вопрос в топике задан как-то странно - в шапке речь идет о передаче аналогового сигнала, в тексте - о передаче некоей переменной. Если аналоговый (периодический, непрерывный, длительный...) сигнал - то дельта-сигма, если отдельно взятая переменная - то стандартные процедуры ардуино. Кроме того, если речь идет-таки об аналоговым сигнале, желательно указать его динамический и частотный диапазоны. Это тоже сильно повлияет на выбор оптимального способа передачи.
щас ( чуть позжее ) ТС прочитает - и офуеет!!!!!
не нано его грузить дельтасигмами ! пусть здеся освоится ллы начала !
serginusoid, попробуйте эти способы:
1. по сериалу
Передатчик:
01
#include <EasyTransfer.h>
02
03
struct
DATA_STRUCTURE{
04
//структура данных
05
//должно быть одинаково у передатчика и у приёмника
06
//в т. ч. переменные в одинаковом порядке
07
int
blinks;
08
int
pause;
09
};
10
11
EasyTransfer ET;
12
DATA_STRUCTURE myData;
13
14
void
setup
(){
15
Serial
.begin(9600);
16
ET.begin(details(myData), &
Serial
);
17
randomSeed(analogRead(0));
18
}
19
20
void
loop
(){
21
//заполняем структуру
22
mydata.blinks = 5;
23
mydata.pause = random(5);
24
//посылаем
25
ET.sendData();
26
delay(5000);
27
}
Приёмник:
01
#include <EasyTransfer.h>
02
03
struct
DATA_STRUCTURE{
04
//структура данных
05
int
blinks;
06
int
pause;
07
};
08
09
EasyTransfer ET;
10
DATA_STRUCTURE myData;
11
12
void
setup
(){
13
pinMode(13, OUTPUT);
14
Serial
.begin(9600);
15
ET.begin(details(myData), &
Serial
);
16
}
17
18
void
loop
(){
19
//принято, мигаем
20
if
(ET.receiveData()){
21
for
(
int
i = 0; i < mydata.blinks; i++) {
22
digitalWrite(13, HIGH);
23
delay(mydata.pause * 100);
24
digitalWrite(13, LOW);
25
delay(mydata.pause * 100);
26
}
27
}
28
}
2. по iic
(резисторы по 4.7k)
Передатчик:
01
#include <Wire.h>
02
#include <EasyTransferI2C.h>
03
04
struct
SEND_DATA_STRUCTURE{
05
//структура данных для передачи
06
int
blinks;
07
int
pause;
08
};
09
10
SEND_DATA_STRUCTURE mydata;
11
EasyTransferI2C ET;
12
13
//адрес i2c ведомого
14
#define I2C_SLAVE_ADDRESS 1
15
16
void
setup
(){
17
Wire.begin();
18
ET.begin(details(mydata), &Wire);
19
randomSeed(analogRead(0));
20
}
21
22
void
loop
(){
23
//заполняем структуру
24
mydata.blinks = 5;
25
mydata.pause = random(5);
26
//посылаем
27
ET.sendData(I2C_SLAVE_ADDRESS);
28
delay(5000);
29
}
Приёмник:
01
#include <Wire.h>
02
#include <EasyTransferI2C.h>
03
04
struct
RECEIVE_DATA_STRUCTURE{
05
//структура данных
06
int
blinks;
07
int
pause;
08
};
09
10
EasyTransferI2C ET;
11
RECEIVE_DATA_STRUCTURE mydata;
12
13
#define I2C_SLAVE_ADDRESS 1
14
boolean receiveComplete =
false
;
//флаг, true по факту приёма
15
16
void
setup
(){
17
pinMode(13, OUTPUT);
18
Wire.begin(I2C_SLAVE_ADDRESS);
19
ET.begin(details(mydata), &Wire);
20
Wire.onReceive(receive);
21
}
22
23
void
loop
(){
24
if
(receiveComplete ==
true
){
25
//пришла инфа, мигаем
26
for
(
int
i = 0; i < mydata.blinks; i++) {
27
digitalWrite(13, HIGH);
28
delay(mydata.pause * 100);
29
digitalWrite(13, LOW);
30
delay(mydata.pause * 100);
31
}
32
receiveComplete =
false
;
//снимаем флаг
33
}
34
}
35
36
// приёмная функция
37
void
receive(
int
numBytes){
38
//проверяем приход инфы, ставим флаг
39
if
(ET.receiveData()) {
40
receiveComplete =
true
;
41
}
42
}
Архив с либой: https://github.com/madsci1016/Arduino-EasyTransfer
И снова здраствуйте, почти месяц прошел, а я все еще топчусь на том же месте.)) Попытался попробовать все вышеозвученные способы (кроме модуляции, т.к. вообще не в теме). Вообщем все не получалось кроме последнего примера по сериалу(который предложил(а) std) но и с ним не все хорошо. Собственно, с ним я и пытаюсь сейчас работать. Суть в чем: сам пример работает замечательно, но я его немного изменил(в коде Приемника):
01
#include <EasyTransfer.h>
02
#include <Servo.h>
03
04
Servo myservo;
05
06
struct
DATA_STRUCTURE{
07
//структура данных
08
int
blinks;
09
int
pause;
10
11
};
12
13
EasyTransfer ET;
14
15
DATA_STRUCTURE myData;
16
17
void
setup
(){
18
pinMode(13, OUTPUT);
19
myservo.attach(8);
20
myservo.write(0);
21
22
Serial
.begin(9600);
23
ET.begin(details(myData), &
Serial
);
24
}
25
26
void
loop
(){
27
//принято, мигаем
28
if
(ET.receiveData()){
29
myservo.write(myData.pause*10);
30
for
(
int
i = 0; i < myData.blinks; i++) {
31
digitalWrite(13, HIGH);
32
delay(myData.pause * 100);
33
digitalWrite(13, LOW);
34
delay(myData.pause * 100);
35
}
36
}
37
}
Итак, надеюсь, идея понятна. Hо при подсоединении к платке Приемника сервопривода, он(серв), работать не будет потому нет питания, поэтому было логично, по крайней мере для меня питание подключить. И тут начались проблеммы - платка Приемника подключалась через USB порт в результате чего все просто переставало работать(как я думаю, это связано с внутренней логикой контроллера), а в Serial Monitor (Передатчика) вместо нормальных значений появляется абаркадабра какая-то(в коде Передатчика я вставил в loop метод Serial.println(myData.pause) чтобы отслеживать правильность значений). Собственно в чем может быть проблемма?
После вызова метода ET.begin() вывод информации в Serial monitor невозможен. Сериал не может одновременно пропускать через себя и отладочную информацию, и трафик EasyTransfer.
Как вариант, можно передавать по i2c. Приём по этой шине должен работать. Пробовался ли этот вариант?
Кстати, существует реализация через программный сериал, называется SoftEasyTransfer. И кстати, скорее всего всё вышеперечисленное вряд-ли нужно. Читайте пример EasyTransfer_2Way_wServo_Example.
Получается, я не могу подключить сериал к связке из двух ардуин? Если так, то как это можно обойти, если это вообще возможно?
Получается, я не могу подключить сериал к связке из двух ардуин? Если так, то как это можно обойти, если это вообще возможно?
Давайте представим сериал как 2 трубы в одну кричишь из другой слушаешь. Пока у вас 2 человека они могут орать и говорить одновременно. Полный дуплекс. А если 3 и все говорят одновременно, то получается фигня и никто не слышит никого.
Попробуйте
A New Software Serial Library for Arduino
Делает ещё один Serial port на двух цифровых выходах
подскажите пожалуйста как сделать код под мои нужды:
у меня есть плата в которой спаяны и ардуино и мотор шилд.
на ней нехватает свободных пинов, для этих целей я хочу управлять ею с другой платы через UART
вот то что я хочу получить в картинках:
оно же в расширеной версии.
у меня колесный робот. на котором 2 канала моторов. и нужно управлять кучей серво приводов и нагрузок. на камеру и эхолот внимания не обращайте... это так, может быть в будущем.
все перерыл немогу найти приеру где бы через EasyTransfer или еще как то я мог управлять моторами и сервами одной ардуины через другую с геймпада по блютус, о как :)
на данный момент все управление идет через телефон по блютусу, на тирекс контролер
001
// Скетч для управления через блютус, Wild Thumper 6WD, на ардуино совместимом контролере TREX controller. реализовано движение и стрельба с водомета, захват клешней манипулятором.
002
// по вопросам и предложениям писать на почту <a href="mailto:slom1@list.ru">slom1@list.ru</a>
003
// новые фото и видео можно найти на www.шоуальянс.com
004
005
#include <BTCA2ALite.h>// Добавляем библиотеку блютус программы
006
#include <Servo.h> // Добавляем библиотеку серво
007
008
Servo myservoH;
// Горизонтальная серва углы от 0 до 180 (центровка 89)
009
Servo myservoV;
// Вертикальная серва углы от 1 до 45
010
Servo myservoZ;
// серва Клешня
011
Servo myservoR;
// серва рука клешни
012
const
int
Z_SERVO_PIN = 5;
// добовляем пин захвата
013
const
int
R_SERVO_PIN = 6;
// добовляем пин руки манипулятора
014
const
int
H_SERVO_PIN = 7;
// Горизонтальная серва подключена к пину 7
015
const
int
V_SERVO_PIN = 8;
//Пин вертикального сервопривода 8
016
const
float
Z_L_ANGLE = 116;
// Максимальные угл поворота башни налево
017
const
float
Z_R_ANGLE = 45;
// Максимальные угл поворота башни направо
018
const
float
Z_DEF_ANGLE = 50;
// Дефолтный угол (центровка)
019
const
float
R_L_ANGLE = 178;
// Максимальные угл поднятия руки
020
const
float
R_R_ANGLE = 3;
// Максимальные угл наклона руки
021
const
float
R_DEF_ANGLE = 160;
// Дефолтный угол руки
022
const
float
H_L_ANGLE = 180;
// Максимальные угл поворота башни налево
023
const
float
H_R_ANGLE = 0;
// Максимальные угл поворота башни направо
024
const
float
H_DEF_ANGLE = 84;
// Дефолтный угол (центровка)
025
const
float
V_U_ANGLE = 140;
// Максимальные угл поворота башни вверх
026
const
float
V_D_ANGLE = 45;
// Максимальные угл поворота башни вниз
027
const
float
V_DEF_ANGLE = 60;
// Дефолтный угол (центровка)
028
//Размер шага V_STEP и H_STEP побираем экспериментально для достижения нужной скорости поворота серв
029
const
float
V_STEP = 0.012;
// Шаг - знаение отвечающее за скорость вращения по вертикали.
030
const
float
H_STEP = 0.012;
// Шаг - знаение отвечающее за скорость вращения по горизонтали
031
const
float
Z_STEP = 0.012;
// шаг захвата
032
const
float
R_STEP = 0.012;
// шаг руки
033
float
curVAngle = V_DEF_ANGLE;
//Переменная текущего угла верт. сервы
034
float
curHAngle = H_DEF_ANGLE;
//Переменная текущего угла гор. сервы
035
float
curZAngle = Z_DEF_ANGLE;
//
036
float
curRAngle = R_DEF_ANGLE;
//
037
bool
moveServoVUp =
false
;
//Флаг движения верт. сервы вверх
038
bool
moveServoVDown =
false
;
//Флаг движения верт. сервы вниз
039
bool
moveServoHLeft =
false
;
//Флаг движения гор. сервы влево
040
bool
moveServoHRight =
false
;
//Флаг движения гор. сервы вправо
041
bool
moveServoZLeft =
false
;
//Флаг движения гор. сервы влево
042
bool
moveServoZRight =
false
;
//Флаг движения гор. сервы вправо
043
bool
moveServoRLeft =
false
;
//Флаг движения гор. сервы влево
044
bool
moveServoRRight =
false
;
//Флаг движения гор. сервы вправо
045
046
btca2aLite btca2aLite;
// Конструктор btca2aLite
047
048
049
// задаем пины для левого мотора
050
#define Dir_L 2
051
#define Pwm_L 3
052
#define Brake_L 4
053
// задаем пины для правого мотора
054
#define Dir_R 10
055
#define Pwm_R 11
056
#define Brake_R 9
057
058
// Задаем скорости для движения
059
byte
MaxSpeed = 230;
// Максимальная скорость
060
byte
MinSpeed = 90;
// Минимальная скорость
061
062
int
forw_back = 0;
063
int
righ_left = 0;
064
065
byte
step_fb = 5;
// Шаг изменения скорости движения вперед - назад
066
byte
step_stop = 10;
// Шаг изменения скорости остановки
067
byte
step_rl = 10;
// Шаг изменения скорости движения вправо - влево
068
byte
step_dir = 10;
// Шаг изменения скорости выравнивания
069
070
071
072
#define SHOT 12 // пин для водомета
073
074
enum
States
075
{
076
WAITING,
077
READING,
078
RUNNING,
079
ERROR,
080
TIMEOUT
081
};
082
083
States state;
084
States onWait();
085
States onRead();
086
States onRun();
087
States onError();
088
089
States onTimeout();
090
091
void
performServo();
// добовляем сервы
092
093
094
void
setup
(){
095
Serial
.begin(9600);
// Скорость BT и порта должна быть 9600
096
//Моторы
097
pinMode (Pwm_L, OUTPUT);
098
pinMode (Dir_L, OUTPUT);
099
pinMode (Brake_L, OUTPUT);
100
101
pinMode (Pwm_R, OUTPUT);
102
pinMode (Dir_R, OUTPUT);
103
pinMode (Brake_R, OUTPUT);
104
105
digitalWrite (Pwm_L, LOW);
106
digitalWrite (Pwm_R, LOW);
107
108
digitalWrite (Brake_L, LOW);
109
digitalWrite (Brake_R, LOW);
110
111
pinMode(SHOT, OUTPUT);
// задаем выход для стрельбы водой
112
113
// устанавливаем пин как вывод управления сервой
114
myservoH.attach(H_SERVO_PIN);
115
myservoV.attach(V_SERVO_PIN);
116
myservoZ.attach(Z_SERVO_PIN);
117
myservoR.attach(R_SERVO_PIN);
118
myservoH.write(curHAngle);
119
myservoV.write(curVAngle);
120
myservoZ.write(curZAngle);
121
myservoR.write(curRAngle);
122
123
//Светодиод
124
pinMode(13, OUTPUT);
// Инициализируем пин светодиода
125
digitalWrite(13, HIGH);
// Светодиод выключен
126
}
127
128
void
loop
(){
129
130
btca2aLite.ReadCommand();
// Считывание принятых команд (кодов кнопок)
131
//Вызываем функцию управление сервами
132
performServo();
133
134
//этот код для меня темный лес, мне его дали для плавного старта и торможения моторов. если ехать вперед и резко нажать кнопку назад, машина продолжит ехать вперед, плавно остановиться и только потом поедет назад, это спасает редуктора от разрушения.
135
//если ктото знает что тут к чему, прокоментируйте пожалуйста, чтоб я тоже понимал :)
136
static
unsigned
long
pre_millis = 0;
137
if
(millis()-pre_millis > 50)
138
{
139
pre_millis = millis();
140
141
if
(btca2aLite.ButtonPressed(KEYCODE_DPAD_UP))
142
{
143
forw_back += step_fb;
144
if
(forw_back > 0 && forw_back < MinSpeed) forw_back = MinSpeed;
145
}
146
else
if
(btca2aLite.ButtonPressed(KEYCODE_DPAD_DOWN))
147
{
148
forw_back -= step_fb;
149
if
(forw_back < 0 && forw_back > MinSpeed*-1) forw_back = MinSpeed*-1;
150
}
151
else
152
{
153
if
(forw_back < 0) forw_back += step_stop;
154
else
if
(forw_back > 0) forw_back -= step_stop;
155
if
(abs(forw_back) < MinSpeed) forw_back = 0;
156
}
157
forw_back = constrain(forw_back, MaxSpeed*-1, MaxSpeed);
158
159
160
if
(btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT))
161
{
162
righ_left += step_rl;
163
if
(righ_left > 0 && righ_left < MinSpeed) righ_left = MinSpeed;
164
}
165
else
if
(btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT))
166
{
167
righ_left -= step_rl;
168
if
(righ_left < 0 && righ_left > MinSpeed*-1) righ_left = MinSpeed*-1;
169
}
170
else
171
{
172
if
(righ_left < 0) righ_left += step_dir;
173
else
if
(righ_left > 0) righ_left -= step_dir;
174
if
(abs(righ_left) < MinSpeed) righ_left = 0;
175
}
176
righ_left = constrain(righ_left, MaxSpeed*-1, MaxSpeed);
177
178
179
int
pwm_l = forw_back + righ_left;
180
int
pwm_r = forw_back - righ_left;
181
pwm_l = constrain(pwm_l, MaxSpeed*-1, MaxSpeed);
182
pwm_r = constrain(pwm_r, MaxSpeed*-1, MaxSpeed);
183
184
digitalWrite(Dir_L, (pwm_l<0)?0:1);
185
digitalWrite(Dir_R, (pwm_r<0)?0:1);
186
analogWrite(Pwm_L, abs(pwm_l));
187
analogWrite(Pwm_R, abs(pwm_r));
188
}
189
190
//дальше идут кнопки управления
191
192
//-------— включение насоса —-------------
193
if
(btca2aLite.ButtonPressed(KEYCODE_BUTTON_SELECT))
194
{
195
digitalWrite (SHOT, HIGH);
196
}
197
//-------— выключение насоса происходит автоматически после отпускания кнопки—-------------
198
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_SELECT))
199
{
200
digitalWrite (SHOT, LOW);
201
}
202
203
if
(btca2aLite.Button(KEYCODE_BUTTON_START))
// алгоритм автоматического хватания предметов
204
{
205
206
/* шаг вперед, отключил....
207
digitalWrite (Dir_L, HIGH);
208
analogWrite (Pwm_L, 150);
209
digitalWrite (Dir_R, HIGH);
210
analogWrite (Pwm_R, 150);
211
delay (100);
212
// потом стоп
213
analogWrite (Pwm_L, 0);
214
analogWrite (Pwm_R, 0);
215
delay (500);
216
*/
217
218
myservoZ.write(45);;
// Клешня разжимается
219
myservoR.write(3);;
// рука клешни опускаем
220
delay(2000);
/* ждем 2 секунды, */
221
myservoZ.write(116);;
// Клешня сжимаем
222
delay(1000);
/* ждем 1 секунду, */
223
myservoR.write(170);;
// рука клешни поднимаем
224
delay(1000);
/* ждем */
225
myservoZ.write(45);;
// Клешня разжимаем
226
}
227
228
229
//--------— Повороты серв при нажатии кнопок —-------------
230
231
if
(btca2aLite.Button(KEYCODE_BUTTON_X))
// поворот водомета вниз
232
{
233
moveServoVDown =
true
;
234
235
}
236
if
(btca2aLite.Button(KEYCODE_BUTTON_A))
// поворот водомета направо
237
{
238
moveServoHRight =
true
;
239
}
240
if
(btca2aLite.Button(KEYCODE_BUTTON_B))
// поворот водомета вверх
241
{
242
moveServoVUp =
true
;
243
244
}
245
246
if
(btca2aLite.Button(KEYCODE_BUTTON_Y))
// поворот водомета налево
247
{
248
moveServoHLeft =
true
;
249
}
250
251
if
(btca2aLite.Button(KEYCODE_BUTTON_R1))
// зхахват сжать
252
{
253
moveServoZLeft =
true
;
254
}
255
if
(btca2aLite.Button(KEYCODE_BUTTON_R2))
// захват разжать
256
{
257
moveServoZRight =
true
;
258
}
259
260
261
if
(btca2aLite.Button(KEYCODE_BUTTON_L1))
// рука клешни вниз
262
{
263
moveServoRLeft =
true
;
264
}
265
if
(btca2aLite.Button(KEYCODE_BUTTON_L2))
// рука клешни вверх
266
{
267
moveServoRRight =
true
;
268
}
269
270
271
//--------— чтобы сервы не продолжали движения при отжатых кнопках —-------------
272
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_X))
273
{
274
moveServoVDown =
false
;
275
}
276
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_B))
277
{
278
moveServoVUp =
false
;
279
}
280
281
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_A))
282
{
283
moveServoHRight =
false
;
284
}
285
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_Y))
286
{
287
moveServoHLeft =
false
;
288
}
289
290
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_R2))
291
{
292
moveServoZRight =
false
;
293
}
294
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_R1))
295
{
296
moveServoZLeft =
false
;
297
}
298
299
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_L2))
300
{
301
moveServoRRight =
false
;
302
}
303
if
(btca2aLite.ButtonReleased(KEYCODE_BUTTON_L1))
304
{
305
moveServoRLeft =
false
;
306
}
307
308
309
//----------------— Стоп —---------------------
310
311
// Если не нажата ни одна кнопка курсора происходит остановка, скорость 0 для каждого мотора
312
if
(btca2aLite.ButtonReleased(KEYCODE_DPAD_UP) && btca2aLite.ButtonReleased(KEYCODE_DPAD_DOWN) && btca2aLite.ButtonReleased(KEYCODE_DPAD_LEFT) && btca2aLite.ButtonReleased(KEYCODE_DPAD_RIGHT)){
313
analogWrite (Pwm_L, 0);
314
analogWrite (Pwm_R, 0);
315
}
316
}
317
318
319
320
//Функция управления сервоприводами (вызывается в теле loop на каждой итерации)
321
//Выполняет изменения положения серв на подобранный шаг согласно установленным флагам движения
322
//Флаги устанавливаются согласно поступившим символам управления сервами
323
void
performServo()
324
{
325
//Установлен флаг движения вверх и текущий угол не максимальный
326
if
(moveServoVUp && curVAngle + V_STEP <= V_U_ANGLE)
327
{
328
//К текущему верт. углу прибавляем шаг
329
curVAngle += V_STEP;
330
}
331
//Установлен флаг движения вниз и текущий угол не минимален
332
else
if
(moveServoVDown && curVAngle - V_STEP >= V_D_ANGLE)
333
{
334
//От текущего верт. угла отнимаем шаг
335
curVAngle -= V_STEP;
336
}
337
//Установлен флаг движения влево и текущий угол не максимален
338
if
(moveServoHLeft && curHAngle + H_STEP <= H_L_ANGLE)
339
{
340
//К текущему гор. углу прибавляем гор. шаг
341
curHAngle += H_STEP;
342
}
343
//Установлен флаг движения вправо и текущий угол не минимален
344
else
if
(moveServoHRight && curHAngle - H_STEP >= H_R_ANGLE)
345
{
346
//От текущего угла отнимаем гор. шаг
347
curHAngle -= H_STEP;
348
}
349
350
//Установлен
351
if
(moveServoZLeft && curZAngle + Z_STEP <= Z_L_ANGLE)
352
{
353
//К текущему гор. углу прибавляем гор. шаг
354
curZAngle += Z_STEP;
355
}
356
//Установлен флаг движения вправо и текущий угол не минимален
357
else
if
(moveServoZRight && curZAngle - Z_STEP >= Z_R_ANGLE)
358
{
359
//От текущего угла отнимаем гор. шаг
360
curZAngle -= Z_STEP;
361
}
362
363
364
//Установлен
365
if
(moveServoRLeft && curRAngle + R_STEP <= R_L_ANGLE)
366
{
367
//К текущему гор. углу прибавляем гор. шаг
368
curRAngle += R_STEP;
369
}
370
//Установлен флаг движения вправо и текущий угол не минимален
371
else
if
(moveServoRRight && curRAngle - R_STEP >= R_R_ANGLE)
372
{
373
//От текущего угла отнимаем гор. шаг
374
curRAngle -= R_STEP;
375
}
376
377
//Если было движние по вертикали
378
if
(moveServoVUp || moveServoVDown)
379
{
380
myservoV.write(curVAngle);
381
}
382
//Если было движение по горизонтали
383
if
(moveServoHLeft || moveServoHRight)
384
{
385
myservoH.write(curHAngle);
386
}
387
388
if
(moveServoZLeft || moveServoZRight)
389
{
390
myservoZ.write(curZAngle);
391
}
392
393
if
(moveServoRLeft || moveServoRRight)
394
{
395
myservoR.write(curRAngle);
396
}
397
}
в качестве теста, на другой плате использаван вот такой код, управляется с джойсткика 2 сервы:
01
#include <PS2X_lib.h> //for v1.6
02
#include <Servo.h>
03
PS2X ps2x;
04
int
PS2 = 0;
05
Servo LXservo;
06
Servo LYservo;
07
#define L_dir 2 //пины для драйвера мотора
08
#define L_pwm 3
09
#define R_dir 4
10
#define R_pwm 5
11
12
int
mass[4];
//здесь будем хранить значения для скоростей и направлений
13
//mass[0] лев.напр.
14
//mass[1] лев.скор.
15
//mass[2] прав.напр.
16
//mass[3] прав.скор.
17
18
void
setup
(){
19
LXservo.attach(8);
20
LYservo.attach(6);
21
22
PS2 = ps2x.config_gamepad(13,11,10,12,
true
,
true
);
//Настройка выводов: (clock, command, attention, data, true, true)
23
pinMode(L_dir, OUTPUT);
24
pinMode(L_pwm, OUTPUT);
25
pinMode(R_dir, OUTPUT);
26
pinMode(R_pwm, OUTPUT);
27
}
28
29
void
loop
(){
30
LXservo.write(map(ps2x.Analog(PSS_LX), 255, 0, 0, 180)); ;
31
delay(50);
32
ps2x.read_gamepad(
false
, 0);
33
34
LYservo.write(map(ps2x.Analog(PSS_LY), 0, 255, 0, 90)); ;
35
delay(50);
36
ps2x.read_gamepad(
false
, 0);
37
38
39
dir_pwm(ps2x.Analog(PSS_RY),2);
//обрабатываем правый джойстик
40
digitalWrite(R_dir, mass[2]);
41
analogWrite(R_pwm, mass[3]);
42
}
43
44
void
dir_pwm(
int
Y,
int
n){
//Подпрограмма для обработки значений джойстика
45
if
(Y == 128){
46
mass[n+1] = 0;
47
}
48
if
(Y >128){
49
mass[n+1] = Y*2-255;
50
mass[n] = 1;
51
}
52
if
(Y <128){
53
mass[n+1] = 255-Y*2;
54
mass[n] = 0;
55
}
56
}
код нашел в одной из здешних тем.
Если железки подключены к интренету (можно по ЮСБ), то это можно сделать с помощью проекта Blynk. Пример скетча. Геттинг стартет.
001
#include <PS2X_lib.h> //for v1.6 библиотека джойстика
002
#include <Wire.h>
003
004
005
#include <Servo.h>
006
007
Servo RXservo;
//подключаем сервы
008
Servo RYservo;
009
010
#define ledPin 13
011
#define startbyte 0x0F
012
#define I2Caddress 0x07
013
int
sv[6]={1000,1400,1500,1500,0,0};
//заданны позиции серво приводов, на тирексе их 6 штук, из них первые две отключены, им соответствуют значения = 0, на плате это 5 и 6 пины. далее 1000 = 7 пин, 1400 = 8 пин... // servo positions: 0 = Not Used
014
int
sd[6]={5,10,-5,-15,20,-20};
// servo sweep speed/direction
015
int
lmspeed,rmspeed;
// left and right motor speed from -255 to +255 (negative value = reverse)
016
int
ldir=5;
// how much to change left motor speed each loop (use for motor testing)
017
int
rdir=5;
// how much to change right motor speed each loop (use for motor testing)
018
byte
lmbrake,rmbrake;
// left and right motor brake (non zero value = brake)
019
byte
devibrate=50;
// time delay after impact to prevent false re-triggering due to chassis vibration
020
int
sensitivity=50;
// threshold of acceleration / deceleration required to register as an impact
021
int
lowbat=550;
// adjust to suit your battery: 550 = 5.50V
022
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
023
byte
i2cfreq=0;
// I2C clock frequency. Default is 0=100kHz. Set to 1 for 400kHz
024
025
026
027
028
/******************************************************************
029
* set pins connected to PS2 controller:
030
* - 1e column: original
031
* - 2e colmun: Stef?
032
* replace pin numbers by the ones you use
033
//подключение пинов блютус модуля геймпада:
034
******************************************************************/
035
#define PS2_DAT 12 //14
036
#define PS2_CMD 11 //15
037
#define PS2_SEL 10 //16
038
#define PS2_CLK 9 //17
039
040
/******************************************************************
041
* select modes of PS2 controller:
042
* - pressures = analog reading of push-butttons
043
* - rumble = motor rumbling
044
* uncomment 1 of the lines for each mode selection
045
******************************************************************/
046
//#define pressures true
047
#define pressures false
048
//#define rumble true
049
#define rumble false
050
051
PS2X ps2x;
// create PS2 Controller Class
052
int
PS2 = 0;
053
//right now, the library does NOT support hot pluggable controllers, meaning
054
//you must always either restart your Arduino after you connect the controller,
055
//or call config_gamepad(pins) again after connecting the controller.
056
057
int
error = 0;
058
byte
type = 0;
059
byte
vibrate = 0;
060
061
void
setup
(){
062
063
//пины серв
064
RXservo.attach(3);
065
RYservo.attach(4);
066
067
Serial
.begin(57600);
068
pinMode(ledPin, OUTPUT);
069
Wire.begin();
// no address - join the bus as master
070
071
delay(300);
//added delay to give wireless ps2 module some time to startup, before configuring it
072
073
//CHANGES for v1.6 HERE!!! **************PAY ATTENTION*************
074
075
//setup pins and settings: GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error
076
error = ps2x.config_gamepad(PS2_CLK, PS2_CMD, PS2_SEL, PS2_DAT, pressures, rumble);
077
078
if
(error == 0){
079
Serial
.print(
"Found Controller, configured successful "
);
080
Serial
.print(
"pressures = "
);
081
if
(pressures)
082
Serial
.println(
"true "
);
083
else
084
Serial
.println(
"false"
);
085
Serial
.print(
"rumble = "
);
086
if
(rumble)
087
Serial
.println(
"true)"
);
088
else
089
Serial
.println(
"false"
);
090
}
091
else
092
Serial
.println(
"Большой еггог :)"
);
093
094
095
// Serial.print(ps2x.Analog(1), HEX);
096
097
type = ps2x.readType();
098
switch
(type) {
099
case
0:
100
Serial
.print(
"Unknown Controller type found "
);
101
break
;
102
case
1:
103
Serial
.print(
"DualShock Controller found "
);
104
break
;
105
case
2:
106
Serial
.print(
"GuitarHero Controller found "
);
107
break
;
108
case
3:
109
Serial
.print(
"Wireless Sony DualShock Controller found "
);
110
break
;
111
}
112
}
113
114
void
loop
() {
115
/* You must Read Gamepad to get new values and set vibration values
116
ps2x.read_gamepad(small motor on/off, larger motor strenght from 0-255)
117
if you don't enable the rumble, use ps2x.read_gamepad(); with no values
118
You should call this at least once a second
119
*/
120
if
(error == 1)
//skip loop if no controller found
121
return
;
122
123
if
(type == 2){
//Guitar Hero Controller
124
ps2x.read_gamepad();
//read controller
125
126
if
(ps2x.ButtonPressed(GREEN_FRET))
127
Serial
.println(
"Green Fret Pressed"
);
128
if
(ps2x.ButtonPressed(RED_FRET))
129
Serial
.println(
"Red Fret Pressed"
);
130
if
(ps2x.ButtonPressed(YELLOW_FRET))
131
Serial
.println(
"Yellow Fret Pressed"
);
132
if
(ps2x.ButtonPressed(BLUE_FRET))
133
Serial
.println(
"Blue Fret Pressed"
);
134
if
(ps2x.ButtonPressed(ORANGE_FRET))
135
Serial
.println(
"Orange Fret Pressed"
);
136
137
if
(ps2x.ButtonPressed(STAR_POWER))
138
Serial
.println(
"Star Power Command"
);
139
140
if
(ps2x.Button(UP_STRUM))
//will be TRUE as long as button is pressed
141
Serial
.println(
"Up Strum"
);
142
if
(ps2x.Button(DOWN_STRUM))
143
Serial
.println(
"DOWN Strum"
);
144
145
if
(ps2x.Button(PSB_START))
//will be TRUE as long as button is pressed
146
Serial
.println(
"Start is being held"
);
147
if
(ps2x.Button(PSB_SELECT))
148
Serial
.println(
"Select is being held"
);
149
150
if
(ps2x.Button(ORANGE_FRET)) {
// print stick value IF TRUE
151
Serial
.print(
"Wammy Bar Position:"
);
152
Serial
.println(ps2x.Analog(WHAMMY_BAR), DEC);
153
}
154
}
155
else
{
//DualShock Controller
156
ps2x.read_gamepad(
false
, vibrate);
//read controller and set large motor to spin at 'vibrate' speed
157
158
if
(ps2x.Button(PSB_START))
//will be TRUE as long as button is pressed
159
Serial
.println(
"Start is being held"
);
160
if
(ps2x.Button(PSB_SELECT))
161
Serial
.println(
"Select is being held"
);
162
163
if
(ps2x.Button(PSB_PAD_UP)) {
//will be TRUE as long as button is pressed
164
Serial
.print(
"Up held this hard: "
);
165
Serial
.println(ps2x.Analog(PSAB_PAD_UP), DEC);
166
}
167
if
(ps2x.Button(PSB_PAD_RIGHT)){
168
Serial
.print(
"Right held this hard: "
);
169
Serial
.println(ps2x.Analog(PSAB_PAD_RIGHT), DEC);
170
}
171
if
(ps2x.Button(PSB_PAD_LEFT)){
172
Serial
.print(
"LEFT held this hard: "
);
173
Serial
.println(ps2x.Analog(PSAB_PAD_LEFT), DEC);
174
}
175
if
(ps2x.Button(PSB_PAD_DOWN)){
176
Serial
.print(
"DOWN held this hard: "
);
177
Serial
.println(ps2x.Analog(PSAB_PAD_DOWN), DEC);
178
}
179
180
vibrate = ps2x.Analog(PSAB_CROSS);
//this will set the large motor vibrate speed based on how hard you press the blue (X) button
181
if
(ps2x.NewButtonState()) {
//will be TRUE if any button changes state (on to off, or off to on)
182
if
(ps2x.Button(PSB_L3))
183
Serial
.println(
"L3 pressed"
);
184
if
(ps2x.Button(PSB_R3))
185
Serial
.println(
"R3 pressed"
);
186
if
(ps2x.Button(PSB_L2))
187
Serial
.println(
"L2 pressed"
);
188
if
(ps2x.Button(PSB_R2))
189
Serial
.println(
"R2 pressed"
);
190
if
(ps2x.Button(PSB_TRIANGLE))
191
Serial
.println(
"Triangle pressed"
);
192
}
193
194
if
(ps2x.ButtonPressed(PSB_CIRCLE))
//will be TRUE if button was JUST pressed
195
Serial
.println(
"Circle just pressed"
);
196
if
(ps2x.NewButtonState(PSB_CROSS))
//will be TRUE if button was JUST pressed OR released
197
Serial
.println(
"X just changed"
);
198
if
(ps2x.ButtonReleased(PSB_SQUARE))
//will be TRUE if button was JUST released
199
Serial
.println(
"Square just released"
);
200
201
Serial
.print(
"Stick:"
);
202
203
//управление моторам через левый стик геймпада
204
lmspeed = -(ps2x.Analog(PSS_LY)-128);
//скопировать данные джойстика в регистры правого и левого двигателя
205
int
tmp = -(ps2x.Analog(PSS_LX)-128);
//
206
rmspeed = lmspeed;
207
lmspeed -= tmp; lmspeed *=2;
208
rmspeed += tmp; rmspeed *=2;
209
if
(lmspeed>255) lmspeed =255;
//ограничить макс. значения моторов
210
if
(rmspeed>255) rmspeed =255;
//
211
if
(lmspeed<-255) lmspeed =-255;
//
212
if
(rmspeed<-255) rmspeed =-255;
//
213
214
lmbrake =0;
//выкл. стоп
215
rmbrake =0;
//
216
217
//управление сервами через правый стик геймпада, реализовано 2мя разными методами, результат примерно одинаковый:
218
219
sv[0] = (map(ps2x.Analog(PSS_RY), 0, 255, 1000, 2000)); ;
220
sv[1] = 1500 -(ps2x.Analog(PSS_RX)-128)*2;
221
//
222
223
Serial
.print(lmspeed, DEC);
//Left stick, Y axis. Other options: LX, RY, RX
224
Serial
.print(
","
);
225
Serial
.print(rmspeed, DEC);
226
Serial
.print(
","
);
227
228
RXservo.write(map(ps2x.Analog(PSS_RX), 255, 0, 0, 180)); ;
229
delay(50);
230
ps2x.read_gamepad(
false
, 0);
231
232
RYservo.write(map(ps2x.Analog(PSS_RY), 0, 255, 0, 90)); ;
233
delay(50);
234
ps2x.read_gamepad(
false
, 0);
235
236
// Serial.print(ps2x.Analog(PSS_RY), DEC);
237
// Serial.print(",");
238
// Serial.print(ps2x.Analog(PSS_RX), DEC);
239
// Serial.println("\t");
240
}
241
digitalWrite(ledPin, HIGH);
242
243
MasterSend(startbyte,2,lmspeed,lmbrake,rmspeed,rmbrake,sv[0],sv[1],sv[2],sv[3],sv[4],sv[5],devibrate,sensitivity,lowbat,i2caddr,i2cfreq);
244
delay(20);
245
MasterReceive();
// receive data packet from T'REX controller
246
}
247
248
249
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)
250
{
251
Wire.beginTransmission(I2Caddress);
// transmit data to 7
252
Wire.write(startbyte);
// start byte
253
Wire.write(pfreq);
// pwm frequency
254
255
Wire.write(highByte(lspeed));
// MSB left motor speed
256
Wire.write( lowByte(lspeed));
// LSB left motor speed
257
Wire.write(lbrake);
// left motor brake
258
259
Wire.write(highByte(rspeed));
// MSB right motor speed
260
Wire.write( lowByte(rspeed));
// LSB right motor speed
261
Wire.write(rbrake);
// right motor brake
262
263
Wire.write(highByte(sv0));
// MSB servo 0
264
Wire.write( lowByte(sv0));
// LSB servo 0
265
266
Wire.write(highByte(sv1));
// MSB servo 1
267
Wire.write( lowByte(sv1));
// LSB servo 1
268
269
Wire.write(highByte(sv2));
// MSB servo 2
270
Wire.write( lowByte(sv2));
// LSB servo 2
271
272
Wire.write(highByte(sv3));
// MSB servo 3
273
Wire.write( lowByte(sv3));
// LSB servo 3
274
275
Wire.write(highByte(sv4));
// MSB servo 4
276
Wire.write( lowByte(sv4));
// LSB servo 4
277
278
Wire.write(highByte(sv5));
// MSB servo 5
279
Wire.write( lowByte(sv5));
// LSB servo 5
280
281
Wire.write(dev);
// devibrate
282
Wire.write(highByte(sens));
// MSB impact sensitivity
283
Wire.write( lowByte(sens));
// LSB impact sensitivity
284
285
Wire.write(highByte(lowbat));
// MSB low battery voltage 550 to 30000 = 5.5V to 30V
286
Wire.write( lowByte(lowbat));
// LSB low battery voltage
287
288
Wire.write(i2caddr);
// I2C slave address for T'REX controller
289
Wire.write(i2cfreq);
// I2C clock frequency: 0=100kHz 1=400kHz
290
Wire.endTransmission();
// stop transmitting
291
292
//Serial.println("Master Command Data Packet Sent");
293
294
295
//-------------------------------- Make sure Master and Slave I2C clock the same ------------------------------------------------
296
297
if
(i2cfreq==0)
// thanks to Nick Gammon: <a href="http://gammon.com.au/i2c" title="http://gammon.com.au/i2c" rel="nofollow">http://gammon.com.au/i2c</a>
298
{
299
TWBR=72;
// default I²C clock is 100kHz
300
}
301
else
302
{
303
TWBR=12;
// changes the I²C clock to 400kHz
304
}
305
}
306
307
308
void
MasterReceive()
309
{
//================================================================= Error Checking ==========================================================
310
byte
d;
311
int
i=0;
312
Wire.requestFrom(I2Caddress,24);
// request 24 bytes from device 007
313
314
while
(Wire.available()<24)
// wait for entire data packet to be received
315
{
316
if
(i==0)
Serial
.print(
"Waiting for slave to send data."
);
// Only print message once (i==0)
317
if
(i>0)
Serial
.print(
"."
);
// print a dot for every loop where buffer<24 bytes
318
i++;
// increment i so that message only prints once.
319
if
(i>79)
320
{
321
Serial
.println(
""
);
322
i=1;
323
}
324
}
325
d=Wire.read();
// read start byte from buffer
326
if
(d!=startbyte)
// if start byte not equal to 0x0F
327
{
328
Serial
.print(d,DEC);
329
while
(Wire.available()>0)
// empty buffer of bad data
330
{
331
d=Wire.read();
332
}
333
Serial
.println(
" Wrong Start Byte"
);
// error message
334
return
;
// quit
335
}
336
337
//================================================================ Read Data ==============================================================
338
339
//Serial.print(". Trex Err:"); // slave error report
340
Serial
.print(Wire.read(),DEC);
341
342
i=Wire.read()*256+Wire.read();
// T'REX battery voltage
343
Serial
.print(
" Akk:"
);
344
Serial
.print(
int
(i/10));
Serial
.print(
"."
);
345
Serial
.print(i-(
int
(i/10)*10));
Serial
.print(
"V"
);
346
347
i=Wire.read()*256+Wire.read();
348
Serial
.print(
"\tL Curr:"
);
349
Serial
.print(i);
Serial
.print(
"mA"
);
// T'REX left motor current in mA
350
351
i=Wire.read()*256+Wire.read();
352
Serial
.print(
" Enc:"
);
353
Serial
.print(i);
// T'REX left motor encoder count
354
355
i=Wire.read()*256+Wire.read();
356
Serial
.print(
"\tR Curr:"
);
357
Serial
.print(i);
Serial
.print(
"mA"
);
// T'REX right motor current in mA
358
359
i=Wire.read()*256+Wire.read();
360
Serial
.print(
" Enc:"
);
361
Serial
.print(i);
// T'REX right motor encoder count
362
363
i=Wire.read()*256+Wire.read();
364
Serial
.print(
" X-axis:"
);
365
Serial
.print(i);
// T'REX X-axis
366
367
i=Wire.read()*256+Wire.read();
368
Serial
.print(
" Y:"
);
369
Serial
.print(i);
// T'REX Y-axis
370
371
i=Wire.read()*256+Wire.read();
372
Serial
.print(
" Z:"
);
373
Serial
.print(i);
// T'REX Z-axis
374
375
i=Wire.read()*256+Wire.read();
376
Serial
.print(
" X-delta:"
);
377
Serial
.print(i);
// T'REX X-delta
378
379
i=Wire.read()*256+Wire.read();
380
Serial
.print(
" Y:"
);
381
Serial
.print(i);
// T'REX Y-delta
382
383
i=Wire.read()*256+Wire.read();
384
Serial
.print(
" Z:"
);
385
Serial
.println(i);
// T'REX Z-delta
386
}
1