#arduino #esp32 #lora #arduino-esp32
Вопрос:
Я заканчиваю проект для школы, и я нахожусь на последнем этапе, чтобы мое устройство работало на 100%. Для получения небольшой информации о проекте. Я разрабатываю беспроводной спидометр, который отслеживает обороты в минуту и преобразует их в миль в час с помощью датчика эффектов Холла. Модули, которые я использую в Heltec LoRa esp32 в дополнение к библиотеке LoRa через Arduino. Проблема, с которой я сталкиваюсь, заключается в том, что я пытаюсь использовать полученные пакеты данных и использовать значения датчиков, отправленные для использования в инструкции if, чтобы активировать вибродвигатель, чтобы указать, достигли ли они определенной максимальной скорости. Мой код приведен ниже, и я был бы очень признателен за любую информацию о том, как правильно использовать пакеты. Спасибо. Приемник:
//lora stuff
#include <SPI.h>
#include <LoRa.h>
#include "SSD1306.h"
SSD1306 display(0x3c, 4, 15);
#define SS 18
#define RST 14
#define DI0 26
#define BAND 433E6
//neopixel
#include <Adafruit_NeoPixel.h>
#define LED_PIN 32
#define LED_COUNT 1
Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, 32, NEO_GRB NEO_KHZ800);
const int buttonPin = 17;// button
const int neo = 32; //
const int neoCount = 1; //number of pixels
int counter = 0; //button state counter
int buttonState = 0;
//Vibration motor
int motorPin = 25;
//level of speed in mph to trigger motor
int beginner = 10;
int intermediate = 15;
int expert = 25;
int mphVal = 0;
String data;
unsigned int totalMPH;
void setup() {
//lora
pinMode(16, OUTPUT);
digitalWrite(16, LOW); // set GPIO16 low to reset OLED
delay(50);
digitalWrite(16, HIGH);
display.init();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_LEFT);
// button
pinMode(buttonPin, INPUT);
//motor
pinMode(motorPin, OUTPUT);
//neopixel
strip.begin();
strip.show();
strip.setBrightness(50);
Serial.begin(115200);
//lora initial
while (!Serial); //if just the the basic function, must connect to a computer
delay(100);
Serial.println("Speed Receiver");
display.drawString(5, 5, "Speed Receiver");
display.display();
SPI.begin(5, 19, 27, 18);
LoRa.setPins(SS, RST, DI0);
if (!LoRa.begin(BAND)) {
display.drawString(5, 25, "Starting LoRa failed!");
while (1);
}
Serial.println("LoRa Initial OK!");
display.drawString(5, 25, "LoRa Initializing OK!");
display.display();
}
void loop() {
// try to parse packet
int packetSize = LoRa.parsePacket();
if (packetSize) {
// received a packets
//Serial.print("Received packet. ");
display.clear();
display.setFont(ArialMT_Plain_16);
display.drawString(3, 0, "Received Speed ");
display.display();
// read packet
while (LoRa.available()) {
String data = LoRa.readString();
Serial.print(data);
display.drawString(20, 22, data);
display.display();
// if speed reaches x then motor will buzz
if (data.equals("MPH: 12.5")) {
digitalWrite(motorPin, HIGH);
delay(10);
digitalWrite(motorPin, LOW);
delay(10);
}
}
// print RSSI of packet
//Serial.print(" with RSSI ");
//Serial.println(LoRa.packetRssi());
// display.drawString(20, 45, "RSSI: ");
// display.drawString(70, 45, (String)LoRa.packetRssi());
// display.display();
}
//taking the packet and turning it into an int from string
//String data = data.toInt();
//int data = totalMPH;
//float totalMPH = data.toFloat();
// char data;
// float totalMPH;
//totalMPH = atof(data);
//Serial.println(totalMPH);
//button
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
counter ;
delay(150);
}
//button states with three colors
//beginner
else if (counter == 0) {
//Serial.println("pushed");
strip.setPixelColor(0, 255, 0, 0);
strip.show();
//Serial.println(0);
display.drawString(10, 45, "REC: 10 MPH");
display.display();
//vibration motor will trigger if the speed recieved is less then or equal to 12mph
// digitalWrite(motorPin, HIGH);
// delay(4000);
// digitalWrite(motorPin, LOW);
// delay(120000);
}
//intermediate
else if (counter == 1) {
strip.setPixelColor(0, 0, 255, 0);
strip.show();
Serial.println(1);
display.drawString(10, 45, "REC: 15 MPH");
display.display();
//vibration motor will trigger if the speed recieved is less then or equal to 17mph
// digitalWrite(motorPin, HIGH);
// delay(4000);
// digitalWrite(motorPin, LOW);
// delay(240000);
//digitalWrite(motorPin, LOW);
}
//expert
else if (counter == 2) {
strip.setPixelColor(0, 0, 0, 255);
strip.show();
Serial.print(2);
display.drawString(10, 45, "REC: 20 MPH");
display.display();
//digitalWrite(motorPin, LOW);
}
//reset settings
else {
counter = 0;
}
}
Передатчик:
//lora
#include <SPI.h>
#include <LoRa.h>
#include "SSD1306.h"
#include <Arduino.h>
#include <Bounce2.h>
Bounce hall = Bounce();
SSD1306 display(0x3c, 4, 15);
#define SS 18
#define RST 14
#define DI0 26
#define BAND 433E6 //915E6
int counter = 0;
int rpmTimer = 0;
int rpmInterval = 1000;
void setup() {
//board and lcd
pinMode(25, OUTPUT); //Send success, LED will bright 1 second
pinMode(16, OUTPUT);
digitalWrite(16, LOW); // set GPIO16 low to reset OLED
delay(50);
digitalWrite(16, HIGH);
// sensor and led
hall.attach(37, INPUT);
hall.interval(1);
//pinMode(led, OUTPUT);
//pinMode(hallSens, INPUT);
Serial.begin(115200);
//lcd
while (!Serial); //If just the the basic function, must connect to a computer
// Initialising the UI will init the display too.
display.init();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(5, 5, "LoRa Sender");
display.display();
//lora
SPI.begin(5, 19, 27, 18);
LoRa.setPins(SS, RST, DI0);
Serial.println("LoRa Sender");
if (!LoRa.begin(BAND)) {
Serial.println("Starting LoRa failed!");
while (1);
}
Serial.println("LoRa Initial OK!");
display.drawString(5, 20, "LoRa Initializing OK!");
display.display();
delay(10);
}
void loop() {
hall.update();
if(hall.rose()){
counter ;
}
if(millis() - rpmTimer > rpmInterval){
float rpm = counter * 60;
float rph = rpm * 60;
float dia = 0.00004349;
float cir = dia * 3.14;
float totalMPH = rph * cir;
Serial.println(totalMPH);
rpmTimer = millis();
counter = 0;
//sending packet
LoRa.beginPacket();
LoRa.print("MPH: " String(totalMPH));
LoRa.endPacket();
//LoRa.sleep(); //puts lora receiver to sleep probably dont need
digitalWrite(25, HIGH); // turn the LED on (HIGH is the voltage level)
delay(10); // wait for a second
digitalWrite(25, LOW); // turn the LED off by making the voltage LOW
delay(100); // wait for a second
//delay(300);
}
}
Комментарии:
1. вы можете отправить «S12.5» (S=Скорость) и в приемнике использовать substr (), чтобы получить первый символ и остальную часть сообщения в stof(). Первый символ сообщения определяет, что означает остальная часть сообщения. Отправитель и получатель оба знают, что «S» означает «миль в час», а «12,5» — это то, что «S» имеет в виду. Это, по сути, проводной дизайн API, в котором передатчик определяет API, а приемник просто анализирует строку. Это позволяет получать очень компактные сообщения через LoRa.
2. Зачем отправлять строку? почему бы просто не отправить числовое с помощью Lora.write() ?
3. если отправитель управляет более чем одним датчиком, получателю необходимо будет знать, на какое измерение ссылается Lora.write()
4. Вопрос @codebrane OP не о том, как разработать протокол проводной связи, я согласился с вами, что имеет больше смысла сравнивать данные с числовым значением, чем со строкой, что ставит вопрос о том, почему вы хотите преобразовать числовое значение в строку, отправить его, проанализировать и преобразовать обратно в числовое значение? Фактически, для аргумента наличия «очень компактного сообщения по LoRa» можно использовать
(int) 12.5*10
преобразование числа с плавающей запятой в целое число с точностью до одной десятичной точки, это сделает его очень компактным, отправив всего два байта, чем строку из 5 байтов с «S12.5».5. Существует много способов разработки последовательного API, я мог бы подумать об использовании структуры, а не строки. Как разработать последовательный API, в данном случае не имеет значения, и это также часто самоуверенно и, следовательно, не по теме.
Ответ №1:
С точки зрения проектирования API на основе проводов:
// packet is the packet from the transmitter
String packet = "S12.5"
String measurement = packet.substring(0, 1); // "S"
if (measurement == "S") {
// at this point we know that the rest of the message is the MPH
String data = packet.substring(1, strlen(packet)-1); // "12.5"
float mph = data.toFloat();
if (mph >= TOP_SPEED) {
doSomething();
}
else {
doSomethingElse();
}
}
вы могли бы использовать charAt(0)
measurement
вместо substring()
этого, если вы знаете, что в сети менее 25 датчиков.
каждое измерение будет иметь свое собственное char
в начале сообщения, и сразу же последуют данные, относящиеся к этому измерению. Таким образом, отправитель и получатель взаимодействуют как клиент/сервер в обмене API. Между ними существует неявный контракт, так что, когда передатчик говорит «S12.5», приемник знает, что это означает 12,5 миль в час. Это ваша система, поэтому вы можете создавать коммуникационные пакеты любым удобным для вас способом.