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