ENG-CANSAT-MISSION1-CAPTURE
Introduction
Before starting this point, we recommand to follow all the sensors testing steps (BMP280 sensor, TMP36 Sensor, RFM69HCW radio and RFM69HCW Testing). It contains all the details about the wiring, install needed libraries and conduct basic testing. |
The following Wiring is used to capture
- Air temperature
- Air pressure
and transmissing the information via the RFM69HCW radio module.
Wiring
Wire the barometric sensor
The BMP280 is wired on the I2C bus of the Feather.
Wire the temperature sensor
Then connect the TMP36 sensor as follows:
- The pin 1 (on the left) to a power source (3.3V),
- The pin 3 (the the right droite) to the ground/GND.
- The pin 2 (middle one) to the A3 analogue input.
Wire the radio module
Finally wire the RFM69HCW radio as follows:
Feather M0 Express | RFM69 |
3V | VIN |
GND | GND |
MO | MOSI |
MI | MISO |
SCK | SCK |
6 | CS |
9 | G0 |
10 | RST |
The code
The code is available for download on the GitHub associated to this wiki.
Testing
Now, we will move forward in several steps.
- Getting data from sensors + send them it over the serial connexion (to confirm good working) + transmit over radio
- Testing the radio reception
- Going autonomous (removing Serial Connexion waiting) + add the Lipo
The code proposed here under has been tested up to 22620128 (22.6 millions) iterations without issue, time where we decided to end the test :-) .
LEDs and errors
Being able to understand rapidly what's happening inside your object is essential to fix the issue.
The best is to figure out what's happening is to use LED, blink status, heartbeat.
By doing so, no need to open a Serial Monitor or diagnostic tool to figure out the status of the object.
The NeoPixel LED does turn GREEN when the Feather M0 switch on to normal operation (when it runs your Arduino Sketch).
In the following sample, we do take the control over the NeoPixel LED to switch it off at the end of setup() function. This means that all buses and devices are properly initialized.
The RADIO_LED wired on the Pin 13 is used to signal radio status when emitting a message.
LED operation | Description | Fix the issue |
NeoPixel GREEN | The setup() function did not complete initialization because of a crash. | Check the wiring of sensors. Test each sensor separately (with their tests code). If this not working, remove all sensors except the one you are testing. |
NeoPixel OFF | The setup() did complete successfully. The main loop() is not running. | Nothing to do here, just check the RADIO_LED for more informations. |
RADIO LED = 1 pulse 50ms | The LED is pulsed for each successfully send message + getting ACK from the receiver. The code wait 500ms max for the ACK. | Nothing to do here. |
RADIO LED = 2 pulse 50ms + pause 100ms | Message send but error while decoding the ACK response. | This is not critical, the most important is that the message was sent successfully. |
RADIO LED = 3 pulse 50ms + pause 150ms | Not ACK message received within the 500ms after message was sent. This can be interpreted as "Is there someone listening the message?" because there are not reply. |
This is not critical, the most important is that the message was sent successfully. |
The code explained
Here some explanation about the
This Arduino sketch would:
- Wait for the serial connexion to be established before starting the sketch
- Collect the sensor data
- Send it to serial connexion
- Send it over the radio connexion
First, the script will includes all the needed libraries.
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_NeoPixel.h>
#include <RH_RF69.h>
Then, it defines the parameters for the radio module and the pinout used to wire the RFM69HCW radio module to the Feather M0.
The last line create the object rf69 to control the module.
#define RF69_FREQ 433.0
#define RFM69_CS 6
#define RFM69_INT 9
#define RFM69_RST 10
#define RADIO_LED 13
RH_RF69 rf69(RFM69_CS, RFM69_INT);
Defining the parameters to control the NeoPixel LED available on the board. That LED is wired on the Pin 8.
The last line creates an objet pixel which is a Pixels Strand of only 1 pixel length.
#define NEOPIXEL 8
#define NUMPIXELS 1
Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUMPIXELS, NEOPIXEL, NEO_GRB + NEO_KHZ800);
Defining the parameter and objects for temperature and pressure sensor.
#define temperaturePin A3
Adafruit_BMP280 bme; // wired with I2C
Initialize the serial connexion @ 9600 bauds, the BMP sensor, the radio module (init_radio_module()) and pixel.
The NeoPixel is turned when the setup() function is complete.
void setup() {
Serial.begin(9600);
// wait until serial console is open
while (!Serial) { delay(1); }
if (!bme.begin()) {
Serial.println("Could not find a valid BMP280 sensor, check wiring!");
while (1);
}
init_radio_module();
// everything is right! So switch off neopixel
pixel.begin();
pixel.setPixelColor(0, pixel.Color(0,0,0)); // switch off
pixel.show();
}
bool header_send = false; // if header has not been send yet...
int16_t packetnum = 0; // packet number increment at each data emission
void loop() {
// send columns header
if( !(header_send) ){
send_header();
header_send = true;
}
// read the voltage of TMP36
float voltage = getVoltage(temperaturePin);
// convert voltage to temperature
// Degrees = (voltage - 500mV) multiplied by 100
float temperature = (voltage - .5) *100;
float bme_temp = bme.readTemperature();
float bme_hpa = bme.readPressure();
unsigned long ms = millis();
packetnum += 1; // increment
// char radiopacket[40] = "Hello World #";
String packet_str = String( ":"+String(packetnum,DEC)+"|" );
packet_str.concat( String(ms,DEC)+"|" );
packet_str.concat( String( temperature, 2 )+"|" );
packet_str.concat( String( bme_hpa, 2 )+"|" );
packet_str.concat( String( bme_temp, 2 )+";\r\n" );
// send to Serial
Serial.print( packet_str.c_str() );
// Send over Radio
rf69.send((uint8_t *)(packet_str.c_str()), packet_str.length());
rf69.waitPacketSent();
// Now wait for a reply
uint8_t buf[4]; // We limit the quantity received data
uint8_t len = sizeof(buf);
if (rf69.waitAvailableTimeout(500)) {
// Should be a reply message for us now
if (rf69.recv(buf, &len)) {
Serial.print(": ");
Serial.println((char*)buf);
Blink(RADIO_LED, 50, 1); //blink LED once, 50ms between blinks
} else {
Serial.println("Receive failed");
Blink(RADIO_LED, 50, 1); //blink LED once, 50ms between blinks
}
} else {
Serial.println("No reply, is another RFM69 listening?");
Blink(RADIO_LED, 50, 3 ); // blink 3 times, 50ms between blinks
}
// Going to next round
}
void init_radio_module() {
pinMode(RADIO_LED, OUTPUT);
pinMode(RFM69_RST, OUTPUT);
digitalWrite(RFM69_RST, LOW);
Serial.println("Feather RFM69 TX Test!");
Serial.println();
// manual reset
digitalWrite(RFM69_RST, HIGH);
delay(10);
digitalWrite(RFM69_RST, LOW);
delay(10);
if (!rf69.init()) {
Serial.println("RFM69 radio init failed");
while (1);
}
Serial.println("RFM69 radio init OK!");
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
// No encryption
if (!rf69.setFrequency(RF69_FREQ)) {
Serial.println("setFrequency failed");
}
// If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
// ishighpowermodule flag set like this:
rf69.setTxPower(20, true); // range from 14-20 for power, 2nd arg must be true for 69HCW
// The encryption key has to be the same as the one in the server
uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
rf69.setEncryptionKey(key);
pinMode(RADIO_LED, OUTPUT);
Serial.print("RFM69 radio @");
Serial.print((int)RF69_FREQ);
Serial.println(" MHz");
}
void send_header() {
// Send header about the data Serial.println(F("***START***"));
String s1 = String( F("***HEADER***\r\n") );
Serial.print( s1 );
// use : as begin of data and ; as end of data
String s2 = String( F(":counter|time_ms|temperature|pressure_hpa|temp2;\r\n") );
Serial.print(s2);
String s3 = String( F("***DATA***\r\n") );
Serial.print( s3 );
}
void Blink(byte PIN, byte DELAY_MS, byte loops) {
for (byte i=0; i<loops; i++) {
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
delay(DELAY_MS);
}
// exit: wait 3 times the delay
delay( 3* DELAY_MS );
}
/*
* getVoltage() - return the voltage of an analog pin
*/
float getVoltage(int pin){
// AS the sketch does not call the analogReadResolution()
// function to change the analog reading resolution
// THEN Arduino use the defaut 12 bits resolution!
// Under 12 bits resolution, the analogRead() returns
// a value between 0 & 1024.
//
// Convert digital value between 0 & 1024 to
// voltage between 0 & 3.3 volts.
// (each unit equal 3.3 / 1024 = 3.2 millivolts)
return (analogRead(pin) * .0032);
}
Written by Meurisse D. from MC Hobby - License: CC-SA-BY.