Created
December 3, 2020 21:33
-
-
Save grgmrtn/f737c007c4067a98c8828a7bcea10bd1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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