Key details
Project: remote controlled valve using a servo.
Board: CubeCell-Board (HTCC-AB01)
Libraries: LoRaWan_APP, CubeCellServoTimers
Host OS: Ubuntu 20.04.3 LTS
Arduino IDE: 1.8.14 Hourly Build 2021/04/08 03:25
The CubeCell Arduino libraries are up-to-date, I have downloaded them today and followed the instructions found here.
Issue
The servo library works fine on its own. Notice the test loop at the beginning of loop()
, everything works fine there. However, when the board receives a downlink message and changes the servo to a new position, it only works the first time.
Example program cycle:
- Program start/board reset
- Receive new downlink message
- Change servo position
- Sleep cycle
- Receive new downlink message
- Change servo position
- Sleep cycle
- Receive new downlink message
- Change servo position
- …
This behaviour is really weird since the servo works perfectly inside the test loop. So the only reason I supsect this is happening is because of a conflict with the LoRaWan library cycle.
Code
#include <LoRaWan_APP.h>
#include <Arduino.h>
#include "CubeCellServoTimers.h"
uint32_t license[4] = { /* ... */ };
/* OTAA parameters */
uint8_t devEui[] = { /* ... */ };
uint8_t appEui[] = { /* ... */ };
uint8_t appKey[] = { /* ... */ };
/* ABP parameters */
uint8_t nwkSKey[] = { /* ... */ };
uint8_t appSKey[] = { /* ... */ };
uint32_t devAddr = (uint32_t) 0x00000000;
uint16_t userChannelsMask[6] = { 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;
DeviceClass_t loraWanClass = CLASS_A;
uint32_t appTxDutyCycle = 50000;
bool overTheAirActivation = true;
bool loraWanAdr = true;
bool keepNet = true;
bool isTxConfirmed = false;
uint8_t appPort = 2;
uint8_t confirmedNbTrials = 8;
#define VALVE_OPEN 100
#define VALVE_CLOSE 0
#define VALVE_HALF_CLOSE 35
#define SERVO_MIN 500
#define SERVO_MAX 2500
#define SERVO_IN_MIN 0
#define SERVO_IN_MAX 4096
#define SERVO_MIN_DEGREE 0
#define SERVO_MAX_DEGREE 180
#define SERVO_PIN GPIO2
#define SERVO_INPUT_PIN ADC
#define TEST_OVERRIDE_PIN GPIO1
Servo servo;
long getServoPosition() {
return map(analogRead(SERVO_INPUT_PIN), SERVO_IN_MIN, SERVO_IN_MAX, SERVO_MAX_DEGREE, SERVO_MIN_DEGREE);
}
void setServo(int spos) {
servo.write(spos);
delay(5000);
}
static void prepareTxFrame(uint8_t port) {
}
void downLinkDataHandle(McpsIndication_t *mcpsIndication) {
int action = 0;
for(uint8_t i = 0; i < mcpsIndication->BufferSize; i++) {
Serial.print("READ: ");
Serial.println(mcpsIndication->Buffer[i]);
action = mcpsIndication->Buffer[i];
switch (action) {
case 0:
setServo(VALVE_CLOSE);
break;
case 1:
setServo(VALVE_OPEN);
break;
case 2:
setServo(VALVE_HALF_CLOSE);
break;
default:
break;
}
}
Serial.println();
uint32_t color = mcpsIndication->Buffer[0] << 16 | mcpsIndication->Buffer[1] << 8 | mcpsIndication->Buffer[2];
#if(LoraWan_RGB == 1)
turnOnRGB(color, 5000);
turnOffRGB();
#endif
}
void setup() {
Serial.begin(115200);
while (!Serial);
#if(AT_SUPPORT)
enableAt();
#endif
deviceState = DEVICE_STATE_INIT;
LoRaWAN.ifskipjoin();
servo.attach(SERVO_PIN, SERVO_MIN, SERVO_MAX);
pinMode(TEST_OVERRIDE_PIN, INPUT);
}
void loop() {
if (digitalRead(TEST_OVERRIDE_PIN) == HIGH) {
int positions[] = { VALVE_OPEN, VALVE_CLOSE, VALVE_HALF_CLOSE };
for (int i = 0; i < sizeof(positions) / sizeof(positions[0]); i++) {
int spos = positions[i];
setServo(spos);
delay(1000);
int inPos = analogRead(SERVO_INPUT_PIN);
int servoPos = map(inPos, SERVO_IN_MIN, SERVO_IN_MAX, SERVO_MAX_DEGREE, SERVO_MIN_DEGREE);
Serial.printf("spos: %dº | %dmV -> %dº = %d\n", spos, inPos, servoPos, abs(servoPos - spos));
}
} else {
switch (deviceState) {
case DEVICE_STATE_INIT:
{
#if(AT_SUPPORT)
getDevParam();
#endif
printDevParam();
LoRaWAN.init(loraWanClass, loraWanRegion);
deviceState = DEVICE_STATE_JOIN;
break;
}
case DEVICE_STATE_JOIN:
{
LoRaWAN.join();
break;
}
case DEVICE_STATE_SEND:
{
prepareTxFrame(appPort);
LoRaWAN.send();
deviceState = DEVICE_STATE_CYCLE;
break;
}
case DEVICE_STATE_CYCLE:
{
txDutyCycleTime = appTxDutyCycle + randr(0, APP_TX_DUTYCYCLE_RND);
LoRaWAN.cycle(txDutyCycleTime);
deviceState = DEVICE_STATE_SLEEP;
break;
}
case DEVICE_STATE_SLEEP:
{
LoRaWAN.sleep();
break;
}
default:
{
deviceState = DEVICE_STATE_INIT;
break;
}
}
}
}
Extra details
Downlink actions:
-
00
: Close valve -
01
: Open valve -
02
: Half close valve
Test:
- run test loop cycle when
TEST_OVERRIDE_PIN
(default: GPIO1) is high