Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/**
OCADu - Fall 2020 - Creation & Computation
Experiment 5
Simran Duggal, Greg Martin, and Mairead Stewart
submitted to Kate Hartman and Nick Puckett
December 4, 2020
Based on code from Creation & Computation 'SendReceiveTemps'
https://github.com/DigitalFuturesOCADU/CC2020/tree/main/Experiment5
and 'six-axis-comp-filter'
https://github.com/DigitalFuturesOCADU/CC2020/tree/main/Experiment3
With thanks to Arduino WifiNINA WebClient Reference
https://www.arduino.cc/en/Tutorial/LibraryExamples/WiFiNINAWiFiWebClient
**/
#include <WiFiNINA.h>
#include <SPI.h>
#define PubNub_BASE_CLIENT WiFiClient
#include <PubNub.h>
#include <ArduinoJson.h>
#include <SparkFunLSM6DS3.h>
#include "six_axis_comp_filter.h"
#include "Wire.h"
float pitch;
float roll;
float absPitch;
float absRoll;
float level;
bool canDoAction = true;
bool allLit = false;
// outgoing JSON variables
const char* myID = "Greg"; //self ID
const static char publishChannel[] = "Greg"; //self channel
const static char readChannel1[] = "Mairead"; //other channel 1
const static char readChannel2[] = "Sim"; //other channel 2
//first, set your pins
int firstLights[] = { A3, 6, 10, 11}; //UPDATE: add all pins that should light when one person is avail
int secondLights[] = { A2, 5, 9, 12}; //UPDATE: add all add'l pins that should light when two people avail
int thirdLights[] = {}; //UPDATE: if applicable, add third row of pins when all are avail
int selfAvail = 2;
int selfBusy = 3;
const static char* teamInOrder[] = {publishChannel, readChannel1, readChannel2};
int teamStatuses[] = {0, 0, 0};
int numTeamAvail = 0;
int teamSize = 3;
//Wifi details
extern char ssid[] = "YourSSID"; //UPDATE
extern char pass[] = "enteryourpassword"; //UPDATE
int status = WL_IDLE_STATUS; // the Wifi radio's status
// pubnub keys
char pubkey[] = "your-pub-key";
char subkey[] = "your-sub-key";
// JSON variables
StaticJsonDocument<200> dataToSend; // The JSON from the outgoing message
StaticJsonDocument<200> inMessage; // JSON object for receiving the incoming values
//create the names of the parameters you will use in your message
String JsonParamName1 = "publisher";
String JsonParamName2 = "pitch";
unsigned long lastCheck; //time of last publish
int publishRate = 1500; //how often to publish the data to PN
unsigned long lastPublish; //time of last publish
int lastStatus = 0; //0 for busy, 1 for available
int thisStatus; //current local status for comparison against last published status
LSM6DS3 myIMU(I2C_MODE, 0x6A); //Default constructor is I2C, addr 0x6B
CompSixAxis CompFilter(0.1, 2); //define the filter object
void setup() {
Serial.begin(9600);
connectToPubNub();
for (int i = 0; i < sizeof(firstLights) /sizeof(firstLights[0]); i++) {
pinMode(firstLights[i], OUTPUT);
}
for (int i = 0; i < sizeof(secondLights)/sizeof(secondLights[0]); i++) {
pinMode(secondLights[i], OUTPUT);
}
for (int i = 0; i < sizeof(thirdLights) /sizeof(thirdLights[0]); i++) {
pinMode(thirdLights[i], OUTPUT);
}
//for self-separate mode
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
myIMU.begin();
}
void loop() {
if((millis() - lastCheck) >= publishRate) {
Serial.println("IN");
//calculate local pitch and roll
calculatePitchAndRoll();
//send and receive messages with PubNub, based on a timer
sendReceiveMessages();
//update the number of teammates available
updateStatus();
//update buffer variables
lastCheck = millis();
}
//keep the box lit even while not checking for other statuses
lightLevels(numTeamAvail);
//delay(100);
}
void calculatePitchAndRoll()
{
float accelX, accelY, accelZ, // variables to store sensor values
gyroX, gyroY, gyroZ,
xAngle, yAngle;
// Get all motion sensor (in this case LSM6DS3) parameters,
accelX = myIMU.readFloatAccelX();
accelY = myIMU.readFloatAccelY();
accelZ = myIMU.readFloatAccelZ();
gyroX = myIMU.readFloatGyroX();
gyroY = myIMU.readFloatGyroY();
gyroZ = myIMU.readFloatGyroZ();
// Convert these values into angles using the Complementary Filter
CompFilter.CompAccelUpdate(accelX, accelY, accelZ); // takes arguments in m/s^2
CompFilter.CompGyroUpdate(gyroX, gyroY, gyroZ); // takes arguments un rad/s
CompFilter.CompUpdate();
CompFilter.CompStart();
// Get angle relative to X and Y axes and write them to the variables in the arguments
//in radians
CompFilter.CompAnglesGet(&xAngle, &yAngle);
//convert from radians to angles
pitch = xAngle*RAD_TO_DEG;
roll = yAngle*RAD_TO_DEG;
absPitch = pitch;
absRoll = roll;
//because both axes trip between 0 and 360, use an absolute value measure instead
if (pitch > 180) {
absPitch = 360 - pitch;
}
if (roll > 180) {
absRoll = 360 - roll;
}
if (absPitch > 40 || absRoll > 40) {
thisStatus = 1;
} else {
thisStatus = 0;
if (allLit) {
//if your being busy stops allLit, allow action to be completed next time
canDoAction = true;
}
}
//set own status based on pitch and roll values
teamStatuses[0] = thisStatus;
}
void sendReceiveMessages()
{
//connect, publish new messages, and check for incoming
//publish data if local status has changed
if (thisStatus != lastStatus) {
sendMessage(); // publish this value to PubNub
lastStatus = thisStatus;
}
//check for new incoming messages
readMessage(readChannel1);
readMessage(readChannel2);
}
void updateStatus() {
//loop over status array and light box accordingly
//sequential lighting: light the next set of lights
numTeamAvail = 0; //reset team avail counter
//loop through others' status and light the correct number of lights
for (int i = 0; i < sizeof(teamStatuses) / sizeof(teamStatuses[0]); i++) {
if (teamStatuses[i] == 1) {
numTeamAvail++;
}
}
if (numTeamAvail == teamSize) {
allLit = true;
completeMyAction();
}
}
void lightLevels(int numLev) {
int level = 255;
int firstLightLevel = 0;
int secondLightLevel = 0;
int thirdLightLevel = 0;
if (teamStatuses[0] == 1) {
digitalWrite(selfAvail, level);
digitalWrite(selfBusy, 0);
} else {
digitalWrite(selfBusy, level);
digitalWrite(selfAvail, 0);
}
if (teamStatuses[1] == 1 && teamStatuses[2] == 1) {
secondLightLevel = level;
firstLightLevel = level;
} else if (teamStatuses[1] == 1 || teamStatuses[2] == 1) {
firstLightLevel = level;
}
for (int h = 0; h < sizeof(firstLights) /sizeof(firstLights[0]); h++) {
digitalWrite(firstLights[h], firstLightLevel);
}
for (int i = 0; i < sizeof(secondLights) /sizeof(secondLights[0]); i++) {
digitalWrite(secondLights[i], secondLightLevel);
}
for (int i = 0; i < sizeof(thirdLights) /sizeof(thirdLights[0]); i++) {
digitalWrite(thirdLights[i], thirdLightLevel);
}
}
void completeMyAction() {
//varies by team member: in this example, connect to IFTTT and trigger a pre-configured Wemo switch
if (canDoAction && allLit) {
canDoAction = false;
Serial.println("Everyone's free! Action!");
char servername[]="maker.ifttt.com";
WiFiClient actionClient;
if (actionClient.connect(servername, 80)) {
Serial.println("connected to maker");
actionClient.println("GET /trigger/everyone_avail/with/key/b_ABu3206tdQ71ikTs_8tN HTTP/1.1");
actionClient.println("Host: maker.ifttt.com");
actionClient.println("Connection: close");
actionClient.println();
Serial.println("sent get");
Serial.print(actionClient.connected());
Serial.print("!!!" + actionClient.read());
while (actionClient.available() == 0) {
Serial.print(".");
}
while (actionClient.available()) {
char c = actionClient.read();
Serial.print(c);
}
if (!actionClient.connected()) {
Serial.println();
Serial.println("disconnecting from server");
actionClient.stop();
}
}
} else {
Serial.println("Already done action.");
}
}
void sendMessage()
{
char msg[64]; // variable for the JSON to be serialized into for your outgoing message
// assemble the JSON to publish
dataToSend["publisher"] = myID; // first key value is sender: yourName
dataToSend["pitch"] = thisStatus; // second key value is the potiometer value: analogValue
serializeJson(dataToSend, msg); // serialize JSON to send - sending is the JSON object, and it is serializing it to the char msg
WiFiClient* client = PubNub.publish(publishChannel, msg); // publish the variable char
if (!client)
{
Serial.println("publishing error"); // if there is an error print it out
}
}
void readMessage(const char channel[]) {
String msg;
auto inputClient = PubNub.history(channel,1);
if (!inputClient)
{
Serial.println("message error");
delay(1000);
return;
}
HistoryCracker getMessage(inputClient);
while (!getMessage.finished())
{
getMessage.get(msg);
//basic error check to make sure the message has content
if (msg.length() > 0)
{
Serial.print("**Received Message from ");
Serial.print(channel);
Serial.println(msg);
//parse the incoming text into the JSON object
deserializeJson(inMessage, msg); // parse the JSON value received
//read the values from the message and store them in local variables
const char* inMessagePublisher = inMessage[JsonParamName1]; // other person's name
int inMessageStatus = int(inMessage[JsonParamName2]); // other person's status (0 or 1)
for (int i = 0; i < teamSize; i++) {
Serial.print(String(teamInOrder[i]));
Serial.print("-----");
Serial.print(String(inMessagePublisher));
if (String(teamInOrder[i]) == String(inMessagePublisher)) {
Serial.println(" TRUE");
Serial.println(teamStatuses[i]);
Serial.println(inMessageStatus);
if (allLit && ((int)teamStatuses[i] != (int)inMessageStatus)) {
Serial.println("reset canDoAction");
//if coming off allLit status, allow action to be completed again
canDoAction = true;
} else {
Serial.print(canDoAction);
Serial.println(" not changed");
}
teamStatuses[i] = inMessageStatus;
} else {
Serial.println(" FALSE");
}
}
}
}
inputClient->stop();
}
void connectToPubNub()
{
// attempt to connect to Wifi network:
while ( status != WL_CONNECTED)
{
Serial.print("Attempting to connect to the network, SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass);
Serial.print("*");
// wait 10 seconds for connection:
delay(2000);
}
// once you are connected :
Serial.println();
Serial.print("You're connected to ");
Serial.println(ssid);
PubNub.begin(pubkey, subkey);
Serial.println("Connected to PubNub Server");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment