ESP32, nRF24L01 무선통신

nRF24L01

library

스케치> 라이브러리 포함하기> 라이브러리 관리> nRF24L01 검색한 후, RF24 by TMRh20, Avamander 설치


schematic: nRF24L01 receiver with ESP32

※ nRF24L01 모듈에 따라 10uF 캐페시터가 없으면 통신이 안되는 경우가 있음. 이런 경우에만 사용할 것.


pinmap: (안테나를 위로 향하게 두고, 모듈을 위에서 내려다 볼때의 핀배열)
ESP32 3V3 IO5 IO23 None
nRF24L01 VCC + 10uF CSN MOSI IRQ
(위에서 보이는 핀배열) GND + 10uF CE SCK MISO
ESP32 GND IO4 IO18 IO19

sketch: 1:1 Chat Room

  • 양방향 송수신을 위하여 위 회로도를 보고 2개의 모듈을 만든 뒤, 다음 스케치를 업로드한다.
  • 시리얼 모니터를 띄운 뒤, 메세지를 전송해본다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//Libraries for NRF24L01+ module.
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//RF24 object with two pins defined with arguments. CE: 4, CSN: 5
RF24 radio(4, 5);

//Address of the pipe. 40 bit long, you can choose this freely.
//Remember to use different address in different projects.
long long address = 0x1234ABCDEFLL;

int count = 0;
char stext[32] = "";
int spos = 0;
char rtext[32] = "";
int rpos = 0;

void sendText(char * text, int tlen)
{
radio.stopListening();
radio.openWritingPipe(address);
radio.write(stext, tlen);

Serial.print("SEND: ");
Serial.println(text);

memset(stext, 0x00, 32);

radio.openReadingPipe(0, address);
radio.startListening();
}

void setup() {
//Start the radio
Serial.begin(115200);
radio.begin();

//Open reading pipe with given address and start listening for incoming data
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_MIN);
radio.startListening();
}

void loop() {
while(0 < Serial.available()) {
stext[spos] = Serial.read();

if(stext[spos] == 0x0a) {
sendText(stext, spos);
spos = 0;
}
else {
spos += 1;
}
}

if (radio.available()) {
while (radio.available()) {
radio.read(rtext, 32);
}
Serial.print("RECV: ");
Serial.println(rtext);
}
}

sketch: 1:1 Chat Room

다음은 처음 실행 후 시리얼모니터에 입력한 ID를 이용하여 Chat Room을 만드는 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//Libraries for NRF24L01+ module.
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//RF24 object with two pins defined with arguments. CE: 4, CSN: 5
RF24 radio(4, 5);

//Address of the pipe. 40 bit long, you can choose this freely.
//Remember to use different address in different projects.
long long address = 0x1234ABCDEFLL;

String username = "";
String dataInput;
char dataToSend[32];
char dataReceived[32];

void setup() {
//Start the radio
Serial.begin(115200);
delay(2000);
Serial.println("Enter username: ");
radio.begin();
radio.setRetries(3, 5);
//Open reading pipe with given address and start listening for incoming data
radio.openWritingPipe(address);
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_MIN);
}

void loop() {

//set username
while(username == "") {
if(Serial.available()) {
username = Serial.readStringUntil('\n');
Serial.print("Welcome ");
Serial.println(username);
}
}

radio.startListening();

if(radio.available()) {
radio.read(&dataReceived, sizeof(dataReceived));
Serial.println(dataReceived);
}

if(Serial.available()) {
radio.stopListening();

dataInput = "[" + username + "] " + Serial.readStringUntil('\n');
Serial.println(dataInput);
dataInput.toCharArray(dataToSend, 32);

radio.write(&dataToSend, sizeof(dataToSend));
}
}


nRF24L01을 이용한 센서값 전송

for Receiver

schematic


sketch
long long address = 0x1234ABCDEFLL;
  • receiver와 transmitter의 페어링을 위한 파이프(주소)를 지정함. (receiver와 transmitter의 파이프(주소)는 동일해야 함)
  • 주변 여러 사람이 동시에 nRF24L01 모듈을 사용할 경우, 서로 다른 고유의 파이프(주소)를 지정하여야 한다.

uint16_t temphumi[2];
  • 8-bit 기반 Arduino와 32-bit 기반 ESP32를 receiver와 transmitter로 혼용하여 사용할 경우, 아래와 같이 int를 사용하여 변수(혹은 배열)를 선언하면 문제가 발생함.

    1
    int temphumi[2];

    8비트 아키텍처에서 int는 16비트이지만, 32비트 아키텍처에서는 32비트로 정의되기 때문이며,

  • 이로 인해 radio.write 또는 radio.read를 할때 일부 데이터가 송신(혹은 수신)되지 않을 수 있다.

  • 그러므로, arduino와 ESP32를 함께 사용할때에는, 아래와 같은 형태로 변수(혹은 배열) 선언시 특정 비트의 변수로 제한하여 선언할 필요가 있다.

    1
    uint16_t temphumi[2];
  • 단, 송수신기로 Arduino만 사용하거나, 혹은 ESP32만 사용하는 경우에는 int를 사용해도 됨


radio.openReadingPipe(1, address);

페어링 파이프(주소)를 오픈


for Transmitter

schematic

스케치를 업로드하고, 컴퓨터와 연결한 USB선을 분리한 뒤, 독립하여 동작하도록 외부 전원을 연결한다.

※ nRF24L01 모듈에 따라 10uF 캐페시터가 없으면 통신이 안되는 경우가 있음. 이런 경우에만 사용할 것.


18650을 사용하여 5V 외부 전원 만들기
  • ESP32를 외부전원을 통해 동작시키려면, ESP32의 5V/GND 단자를 사용하여 512V의 전압(최적 전압은 67V)을 공급하여야 한다.
  • 18650 소켓에 F단자를 납땜하여 연결한다. (M단자는 서로 맞닿을 경우 과열 위험이 있으므로 사용금지!)


  • DC-DC 5V 승압 모듈에 아래 그림과 같이 납땜하여 연결한다. (USB단자는 사용하지 않음)


※ USB단자가 있는 5V 승압 모듈을 사용하였지만, USB단자가 없는 승압모듈을 사용하면 더 깔끔하게 제작 가능하다.


  • 위 사진과 같이 납땜한 승압 모듈을 18650배터리와 ESP32에 연결한다.
승압 모듈 ESP32 18650배터리
파란색 원 (GND) GND
빨간색 원 (5V) 5V
노란색 원(IN+) (+)극
초록색 원(IN-) (-)극

(transmitter의 경우, 많은 전류를 사용하지 않으므로) 위 그림처럼 ESP32에 DC컨버터를 사용하여 전원을 공급하는 형태보다는, TTGO T-Energy 사용을 추천함

TTGO T-Energy

sketch: DHT22 temperature and humidity Sensor
library for DHT11 or DHT22 sensor

먼저 온습도 센서 데이터를 보내기 위해 온습도 센서 라이브러리를 설치

스케치> 라이브러리 포함하기> 라이브러리 관리> DHT 검색

  • 먼저 **DHT sensor library (by Adafruit)**를 검색하여 설치를 누르면,

  • Dependencies for library DHT sensor library 창이 나오면 Install all을 클릭하여 2개의 라이브러리를 동시에 설치


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//Libraries for NRF24L01+ module.
#include <SPI.h>
#include <RF24.h>

//RF24 object with two pins defined with arguments. CE: 4, CSN: 5
RF24 radio(4, 5);

//Address of the pipe. 40 bit long, you can choose this freely.
//Remember to use different address in different projects.
long long address = 0x1234ABCDEFLL;

// for temperature, humidity sensor
#include "DHT.h"
#define DHTPIN 13 // data pin
#define DHTTYPE DHT22 // change to DHT11 if you're using the DHT11
//float temphumi[2]; // AM2301(DHT21) -> DHT21, AM2302(DHT22) -> DHT22
uint16_t temphumi[2];
DHT dht(DHTPIN, DHTTYPE);


void setup() {
//Start the radio
Serial.begin(115200);

radio.begin();
radio.openWritingPipe(address);
//RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
//NRF24L01: -18dBm, -12dBm,-6dBM, and 0dBm
radio.setPALevel(RF24_PA_LOW);
radio.stopListening();

dht.begin();
}

void loop() {
//Get temperature from the sensor
uint16_t t = dht.readTemperature();
uint16_t h = dht.readHumidity();

temphumi[0] = t;
temphumi[1] = h;

//Send the temperature wirelessly, print error if failed
if (!radio.write(&temphumi, sizeof(temphumi))) {
Serial.println(F("Sending temperature failed"));

// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
delay(2000);
}
}

  • long long address = 0x1234ABCDEFLL;

    • receiver와 transmitter의 페어링을 위한 파이프(주소)를 지정함. (receiver와 transmitter의 파이프(주소)는 동일해야 함)

    • 주변 여러 사람이 동시에 nRF24L01 모듈을 사용할 경우, 서로 다른 고유의 파이프(주소)를 지정하여야 한다.


  • radio.setPALevel(RF24_PA_LOW);
    • RF24_PA_MIN
    • RF24_PA_LOW
    • RF24_PA_HIGH
    • RF24_PA_MAX: 가장 강함 (전류소모도 큼)

result



nRF24L01 + Dual Joystick

2개의 조이스틱을 사용하여 x축, y축 좌표값을 받아보자.


for Transmitter

schematic: nRF24L01 transmitter with ESP32, Dual Joystick

하나의 조이스틱으로도 일반적인 조정이 가능하지만, 시판되는 조정기의 경우 dual joystick(혹은 dual channel)을 사용하는 형태가 많으므로, 여기서도 이와 같은 형태의 transmitter를 만들어 보자.

  • 위 그림에서는 18650을 DC 컨버터를 사용하여 5V핀에 입력하고 있음.

  • (transmitter의 경우, 많은 전류를 사용하지 않으므로) 위 그림처럼 ESP32에 DC컨버터를 사용하여 전원을 공급하는 형태보다는, TTGO T-Energy 사용을 추천함

    TTGO T-Energy

pinmap
ESP32 Joystick1 (x축) Joystick2 (y축)
GND GND GND
5V 5V 5V
25 VRX
32 VRY

sketch: nRF24L01 transmitter with ESP32, Dual Joystick
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <SPI.h>
#include <RF24.h>
RF24 radio(4, 5);

long long address = 0x1234ABCDEFLL;

// for no interference, two joysticks must be used with each other ADC!
// one joystick use ADC1: GPIO 36,39,32,33,34,35
// the other must use ADC2: GPIO 4,0,2,15,13,12,14,27,25,26
const int Jstick_x_pin = 25; // Left_Right GPIO25
const int Jstick_y_pin = 32; // Forward_Back GPIO32

struct Value{
uint16_t value_x;
uint16_t value_y;
};

Value data;


void setup() {
Serial.begin(115200);

radio.begin();
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();
}

void loop() {
data.value_x = Jstick(Jstick_x_pin);
delay(10);
data.value_y = Jstick(Jstick_y_pin);
delay(10);
radio.write(&data, sizeof(Value));

//Serial.print("x: "); Serial.print(data.value_x);
//Serial.print(", y: "); Serial.println(data.value_y);
}

uint16_t Jstick(int Jstick_Pin){
return analogRead(Jstick_Pin);
}

Joystick GPIO의 선정
1
2
3
4
5
// for no interference, two joysticks must be used with each other ADC! 
// one joystick use ADC1: GPIO 36,39,32,33,34,35
// the other must use ADC2: GPIO 4,0,2,15,13,12,14,27,25,26
const int Jstick_x_pin = 25; // Left_Right GPIO25
const int Jstick_y_pin = 32; // Forward_Back GPIO32
  • 2개의 joystick을 동시에 사용할때 동일한 ADC의 GPIO를 사용하면, 한쪽 joystick을 움직여 값을 변화시킬 경우 다른 한쪽 joystick을 움직이지 않았음에도 동시에 값이 일부 (소폭) 변화하는 현상이 생긴다.
  • 이 문제를 해결하기 위해 각각의 joystick을 서로 다른 ADC에 연결한다.
    • ADC1: GPIO 36,39,32,33,34,35 중 1개 사용 (예제에서는 GPIO 32를 y축 joystick으로 사용)
    • ADC2: GPIO 4,(0),(2),15,13,(12),14,27,25,26 중 1개 사용 (()안의 핀은 사용시 주의 필요) (예제에서는 GPIO 25를 x축 joystick으로 사용)
  • 단, ESP32의 wifi 기능을 이용하면 ADC1핀 중에서 wifi 기능에 공유되는 핀의 사용에 제한을 받게 되므로 주의가 필요하다.
  • 그밖에도 사용하는 ADC의 noise를 제거하기 위해 다음과 같은 방법을 쓰는 것이 좋다.
    • GPIO와 GND에 100nF 케패시터를 연결하여 사용
    • 10여회 정도의 값을 받아 평균값으로 사용

for Receiver

schematic: nRF24L01 receiver with ESP32


sketch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <SPI.h>
#include <RF24.h>
RF24 radio(4 ,5);

long long address = 0x1234ABCDEFLL;

struct Value{
uint16_t value_x;
uint16_t value_y;
};

Value data;


void setup() {
Serial.begin(115200);
radio.begin();
radio.openReadingPipe(1, address);
radio.setPALevel(RF24_PA_LOW);
radio.startListening();
}

unsigned long lastRecvTime = 0;

void recvData(){
while( radio.available()){
radio.read(&data, sizeof(Value));
lastRecvTime = millis();
}
}

void loop() {
unsigned long now = millis();

if( now - lastRecvTime > 1000){
recvData();
}

Serial.print("x: "); Serial.print(data.value_x);
Serial.print(", y: "); Serial.println(data.value_y);
}

result



nRF24L01 + Dual Joystick + Dual Servomotors

for Receiver

schematic: nRF24L01 receiver with ESP32, Dual Joystick

  • MG996R과 같이 전류 사용량이 큰 서보 모터를 2개 이상 사용하는 경우, ESP32의 5V pin에서 공급하는 전류량이 부족하여 서보모터 동작이 원활치 않을 수 있다. 이런 경우에는 아래와 같이 외부 전원을 사용하여야 한다.

pinmap
ESP32 servo_x servo_y
GND GND (갈) GND (갈)
5V 5V (빨) 5V (빨)
25 VRX (주)
32 VRY (주)

schematic: nRF24L01 receiver with ESP32, Dual Joystick, External Power (standalone)


외부 전원의 구성
  • 18650 리튬이온 전지 2개를 사용하여 7.4V를 공급 (혹은 18650 3개를 사용하여 11.1V로 구성)

  • XL4015E1칩을 사용한 HW-514 DC-DC regulator를 사용하여, 7.4V → 5V로 전압을 낮춘다. (유사한 형태의 모듈 사용 가능)

    HW-514 HC v0.2 Specification
    Input voltage: 5-36V (6.5V 미만 입력시 디스플레이 동작안됨)

    Output voltage: 1.25-32V continuously adjustable
    Output current: adjustable, up to 5A (4.5A 이내 권장)
    Output power: 75W max (50W 이내 권장)

    Conversion efficiency: up to 96%

    Working frequency: 180KHz
    Short circuit protection: yes
    Over-temperature protection
    Input reverse polarity protection: None,
    (필요시 고전류 다이오드를 입력단에 사용)

    Module Size: 68.2 * 38.8 * 15 (mm)
    • 왼쪽 가변저항으로 출력 전압을 5V 조정 (오른쪽 가변저항은 출력 전류를 조정)

    • 2P 출력단자는 모터에 직접 연결

    • USB포트는 USB-A to microUSB 케이블을 사용하여 ESP32에 연결 (이런 이유로 USB단자가 있는 모듈을 사용하는 것이 편함)

  • 아래와 같은 mini360, mini560 등의 소형 컨버터를 사용하면,

    • SG90 서보모터는 정상적으로 동작
    • MG996R 서보모터를 연결한 경우에는 컨버터 자체가 불안정하여 모터 동작이 멈춤

※ 외부 전원 구성시 주의할 점!
  • 외부 전원을 ESP32의 5V or 3.3V 핀에 직접 연결하지 않도록 한다.
  • 외부 전원을 DC 컨버터를 사용하여 5V or 3.3V로 만든 경우에도 5V or 3.3V 핀에 직접 연결하면 안된다.
  • ESP32의 스펙상 5V or 3.3V 핀을 사용하여 외부 전원을 구성해도 된다고 나와 있지만, 실제로는 모터 등의 모듈이 작동하지 않거나, 심할 경우 ESP32 보드가 망가질 수 있으므로 이와 같은 구성은 지양한다.
  • (경험상) ESP32의 microUSB포트를 통해 전원을 공급하는 것이 가장 안정적으로 동작하였음!

sketch: nRF24L01 receiver with ESP32, Dual Joystick , External Power (standalone)
library for ESP32

스케치> 라이브러리 포함하기> 라이브러리 관리 에서 “esp32servo“ 검색


sketch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <SPI.h>
#include <RF24.h>
RF24 radio(4, 5);

long long address = 0x1234ABCDEFLL;

struct Value{
uint16_t value_x;
uint16_t value_y;
};

Value data;

//Servo motor library for ESP32
#include <ESP32Servo.h>

Servo servo_x; // create servo object to control a servo
Servo servo_y; // 16 servo objects can be created on the ESP32

int angle_x, angle_y;

// Recommended PWM GPIO pins on the ESP32 include 2,4,12-19,21-23,25-27,32-33
int servo_xPin = 15;
int servo_yPin = 2;

// RecvTime
unsigned long lastRecvTime = 0;

void recvData(){
while( radio.available()){
radio.read(&data, sizeof(Value));
lastRecvTime = millis();
}
}

void setup() {
Serial.begin(115200);

radio.begin();
radio.openReadingPipe(1, address);
radio.setPALevel(RF24_PA_LOW);
radio.startListening();

// Allow allocation of all timers
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
servo_x.setPeriodHertz(50); // standard 50 hz servo
servo_y.setPeriodHertz(50);
servo_x.attach(servo_xPin, 500, 2500); // attaches the servo on pin 25 & 32 to the servo object
servo_y.attach(servo_yPin, 500, 2500);
// using default min/max of 1000us and 2000us
// different servos may require different min/max settings
// for an accurate 0 to 180 sweep
}

void loop() {
recvData();
unsigned long now = millis();

if( now - lastRecvTime > 1000){
//ResetData();
}

rotate_xy();
}

void rotate_xy() {
Serial.print("x: "); Serial.print(data.value_x);
Serial.print(", y: "); Serial.println(data.value_y);
angle_x = map(data.value_x, 0, 4095, 0, 180);
angle_y = map(data.value_y, 0, 4095, 0, 180);
servo_x.write(angle_x);
servo_y.write(angle_y);
delay(10);
}



조이스틱 중립 조정

  • 2개의 조이스틱을 중립에 두고, 시리얼 모니터를 통해 센서값을 확인했을때, x축 서보모터는 2700정도, y축 서보모터는 2800 정도의 값을 나타내었다.

  • 이를 기준으로 조이스틱의 값에 따른 대략적인 형태를 생각해보면 (아래의 원 그림에 2개의 조이스틱 값을 모두 나타냄)

  • x축 조이스틱 값이

    • 1350~3400 일때: 중립 (서보모터는 90도 위치로 이동)
    • 0~1350 일때: 서보모터 1도씩 감소 (0도 위치가 될때까지)
      • 단, 자동차 조향 시스템에 적용할 경우 55~90도 사이에서만 움직이도록 조정
    • 3400~4095 일때: 서보모터 1도씩 증가 (180도 위치가 될때까지)
      • 단, 자동차 조향 시스템에 적용할 경우 90~125도 사이에서만 움직이도록 조정
  • y축 조이스틱 값이

    • 1400~3350 일때: 중립 (서보모터는 90도 위치로 이동)
    • 0~1400 일때: 서보모터 1도씩 감소 (0도 위치가 될때까지) (자동차에 적용시 브레이크 역할)
    • 3350~4095 일때: 서보모터 1도씩 증가 (180도 위치가 될때까지) (자동차에 적용시 액셀레이터 역할)
  • 위 그림에 나타낸 값은 모든 조이스틱에 적용되는 절대적인 값이 아니며, 조이스틱마다 중립을 나타내는 센서값이 다르므로, 초기값을 100번 읽은 후 평균값을 만들어 사용한다.


sketch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <SPI.h>
#include <RF24.h>
RF24 radio(4 ,5);

long long address = 0x1234ABCDEFLL;

struct Value{
uint16_t value_x;
uint16_t value_y;
};

Value data;

//Servo motor library for ESP32
#include <ESP32Servo.h>

Servo servo_x; // create servo object to control a servo
Servo servo_y; // 16 servo objects can be created on the ESP32

int angle_x = 90;
int angle_y = 90;
int i = 0;
int center_x = 0;
int center_y = 0;
int ref_xl, ref_xr, ref_ya, ref_yb; // Servo rotation reference value

// for no interference, each joysticks must be used with other ADC! (* not recommended)
// one joystick use ADC1: GPIO 36,39,32,33,34,35
// the other must use ADC2: GPIO 4,0*,2,15,13,12,14,27,25,26
int servo_xPin = 15;
int servo_yPin = 2;

// RecvTime
unsigned long lastRecvTime = 0;

void centerData(){
while(i < 100) {
if(radio.available()){
radio.read(&data, sizeof(Value));
center_x = center_x + data.value_x;
center_y = center_y + data.value_y;
i++;
}
}
center_x = center_x / 100; // x축 조이스틱 센터값
center_y = center_y / 100; // y축 조이스틱 센터값

ref_xl = center_x / 2; // 좌회전 동작 기준값
ref_xr = (4095 + center_x) / 2; // 우회전 동작 기준값
ref_ya = (4095 + center_y) / 2; // accelator 동작 기준값
ref_yb = center_y / 2; // brake 동작 기준값
}

void recvData(){
while(radio.available()){
radio.read(&data, sizeof(Value));
lastRecvTime = millis();
}
}

void setup() {
Serial.begin(115200);

radio.begin();
radio.openReadingPipe(1, address);
radio.setPALevel(RF24_PA_LOW);
radio.startListening();

// Allow allocation of all timers
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
servo_x.setPeriodHertz(50); // standard 50 hz servo
servo_y.setPeriodHertz(50);
servo_x.attach(servo_xPin, 500, 2500); // attaches the servo on pin 25 & 32 to the servo object
servo_y.attach(servo_yPin, 500, 2500);
// using default min/max of 1000us and 2000us
// different servos may require different min/max settings
// for an accurate 0 to 180 sweep

// center value
centerData();
}

void loop() {
unsigned long now = millis();

if( now - lastRecvTime > 5){ // 5ms 마다 서보출력
recvData();
rotate_xy();
}
}

void rotate_xy() {
//Serial.print("x: "); Serial.print(data.value_x);
//Serial.print(", y: "); Serial.println(data.value_y);

//x축 서보 구동 조건 설정
if(data.value_x < ref_xl) {
if(angle_x > 0) {
angle_x--;
}
else {
angle_x = 0;
}
}
else if(data.value_x > ref_xr) {
if(angle_x < 180) {
angle_x++;
}
else {
angle_x = 180;
}
}
else {
if(angle_x < 90) {
angle_x++;
}
else if(angle_x > 90) {
angle_x--;
}
else {
angle_x = 90;
}
}

//y축 서보 구동 조건 설정
if(data.value_y < ref_yb) {
if(angle_y > 0) {
angle_y--;
}
else {
angle_y = 0;
}
}
else if(data.value_y > ref_ya) {
if(angle_y < 180) {
angle_y++;
}
else {
angle_y = 180;
}
}
else {
if(angle_y < 90) {
angle_y++;
}
else if(angle_y > 90) {
angle_y--;
}
else {
angle_y = 90;
}
}

servo_x.write(angle_x);
servo_y.write(angle_y);
delay(5); // delay를 더 줄이면 서보 모터 기어에 무리가 감
}
Author

chemidot

Posted on

2021-10-10

Updated on

2021-12-04

Licensed under

댓글