Need help for making the cycle-sequence of a program - arduino

I'm working on a dishwasher program that can implement few modes, well like the hot water, long mode; hot water, short mode; cold water, long mode; fruit wash mode, etc.
Problem is, on my final project presentation (on design stage, not even into coding yet), I presented on how I implement this with basically real pre-wash/wash/rinse/dry cycles on a dishwasher. It was before I realized if that's actually complicating things, a lot, and unfortunately I have to implement it anyway, since I presented it like so.
Using ESP32 DEVKIT V1 DOIT here, if you're wondering.
What I got confused now, I already made how the cycles works, which below (it's incomplete, yet, and not even modified much as I don't know to implement the prewash/wash/rinse/dry cycle well).
switch (currProg) {
// set up parameters for selected wash program:
//water level, prewash time, wash time, wash Temperature , rinse time, rinse temp, dry time, dry Temperature
case hotFastProg:washprogconfig (high,5,15,60,10, 60,10,70); break;
case hotLongProg:washprogconfig (high,10,25,60,10, 60,10,70); break;
case coldFastProg:washprogconfig (high,5,15,60,10, 60,10,70); break;
case coldLongProg:washprogconfig (high,10,25,60,10, 60,10,70); break;
case fruitProg:washprogconfig (high,5,15,60,10, 60,10,70); break;
}
//below, how we can put those parameters above to the cycles.
void washprogconfig (int inwaterLevel, int inprewashTime, int inwashTime, float inwashTemp, int inrinseTime, float inrinseTemp, int indryTime, float indryTemp)
{
waterLevel = inwaterLevel;
prewashTime = inprewashTime;
washTime = inwashTime;
rinseTime = inrinseTime;
dryTime = indryTime;
washTemp = inwashTemp;
rinseTemp = inrinseTemp;
dryTemp = indryTemp;
}
//switch between cycles (drain, fill, prewash, wash, rinse, dry)
void switchmode ( int induration, String newmsg)
{
String outmsg = " mode started";
prevMode = currMode;
startTime = timeNow;
endTime = startTime + induration;
outmsg = ": " + newmsg + outmsg;
digitalWrite (outlet, switchOff);
digitalWrite (washPump, switchOff);
digitalWrite (inlet, switchOff);
digitalWrite (heater, switchOff);
heaterStatus = false;
}
////// ------------------------- few lines of codes that's unnecesary to show (for showing text)
// record the time
timeNow = millis() / timingFactor;
// calculate remaining progtime (to be honest, on this part I didn't get it much, it just works on the past before I modify it. hence probably it'd be wrong)
remainProgTime = 0;
remainProgTime += (endTime - timeNow); // remprogrime = remprogtrime + (endtime-timenow)
switch (currMode) {
case fillin : remainProgTime += (washTime + drainTime);
break;
case preWash : remainProgTime += drainTime;
break;
case wash : remainProgTime += drainTime;
break;
case rinse : remainProgTime += drainTime;
break;
case drain: //nothing to add
break;
}
// add the time of the remaining full cycles and the Dry Time
remainProgTime += ( fillTime + prewashTime + washTime + rinseTime + drainTime) + dryTime;
////// ------------------------- few lines of codes that's unnecesary to show
//(but at least I can get it done on the cycle modes, still lots of mistake ofc tho)
switch (currMode)
{
// ----------------------------------- START
case progStart:
if (currMode != prevMode) {
switchmode (0, "Program Dimulai");
}
currMode = drain;
break;
// ------------------------------ DRAIN
case drain:
if (currMode != prevMode) {
switchmode (drainTime, "Drain");
delay (2000);
digitalWrite (outlet, switchOn);
}
else if (waterLevel == empty || (currProg == testProg && timeNow >= endTime))
{ // drain completed
currCycle ++;
if (currCycle <= nbrCycle)
currMode = fillin;
else
if (dryTime > 0)
currMode = dry;
else
currMode = complete;
}
else if (timeNow >= endTime) {
currMode = errPause; //Error
}
break;
// ------------------------------ FILL
case fillin:
if (currMode != prevMode) {
switchmode (fillTime, "fill");
digitalWrite (inlet, switchOn); // open the inlet to let water in from the hose.
}
else if (waterLevel == high or (currProg == testProg and timeNow >= endTime))
currMode = wash;
else if (timeNow >= endTime) {
currMode = errPause; // Error
}
break;
// ------------------------- PREWASH
case prewash:
if (currMode != prevMode)
{
switchmode (prewashTime, "Pre-Wash");
digitalWrite (washPump, switchOn);
}
else if (timeNow >= endTime)
{
currMode = drain;
}
break;
// ------------------------ WASH
case wash:
if (currMode != prevMode)
{
switchmode (washTime, "Wash");
//tambah buat sabun
digitalWrite (washPump, switchOn);
}
else if (timeNow >= endTime)
{
currMode = drain;
}
if (washTemp > 0)
{ // turn off heater if above max. Temp.
if ( waterTemp > (washTemp + marginTemp) ) {
digitalWrite (heater, switchOff);
heaterStatus = false;
}
// turn on heater if below max. Temp
else if ( waterTemp < (washTemp - marginTemp) ) {
digitalWrite (heater, switchOn);
heaterStatus = true;
}
}
break;
// ----------------------------- RINSE
case rinse:
if (currMode != prevMode)
{
switchmode (rinseTime, "Rinse");
digitalWrite (washPump, switchOn);
}
else if (timeNow >= endTime)
{
currMode = drain;
}
if (rinseTemp > 0)
{ // turn off heater if above max. Temp.
if ( waterTemp > (rinseTemp + marginTemp) ) {
digitalWrite (heater, switchOff);
heaterStatus = false;
}
// turn on heater if below max. Temp
else if ( waterTemp < (rinseTemp - marginTemp) ) {
digitalWrite (heater, switchOn);
heaterStatus = true;
}
}
break;
//------------------------------- DRY
case dry:
if (currMode != prevMode) {
switchmode (dryTime, "Dry");
}
else if (timeNow >= endTime)
currMode = complete;
if (dryTemp > 0)
{ // turn off heater if above max. Temp.
if ( waterTemp > (dryTemp + marginTemp) ) {
digitalWrite (dryer, switchOff);
}
// turn on heater if below max. Temp
else if ( waterTemp < (dryTemp - marginTemp) ) {
digitalWrite (dryer, switchOn);
}
}
break;
case complete:
switchmode (0, "Program Selesai");
pressedButton = 0;
currentPos = 1;
updateMenu();
currMode = progSelect;
menuNo = 0;
prevProg =1;
break;
case errPause:
switchmode (0, "Program Ditunda");
pressedButton = 0;
currentPos = 3;
updateMenu();
currMode = standby;
menuNo = 1;
prevProg =1;
break;
delay (100);
}
Here's what I want, in dishwashing (which, actually wash the dishes) program, I want to make the cycle runs like this:
Start -> drain -> fill -> prewash -> drain -> fill -> wash -> drain -> fill -> rinse -> drain -> dry -> done.
While on the fruit one, I just want to run it like this.
Start -> drain -> fill -> prewash -> drain -> done.
Basically the program before I 'mess' it, well, the program went well on only 'wash', without the additional pre-wash and rinse.
How can I implement the cycle like so? I'm looking online for references, but unfortunately there's no explaining on how can I use multiple modes, mostly just running on one fixed mode. I'm kind of confused with that so far.
Any recommendation and suggestion would be greatly appreciated.
Thanks in advance.

This is a difficult question to answer because there are countless ways to approach it, but it's an assigned project so there might be specific patterns you're supposed to demonstrate
*I'm going to assume this is supposed to show OOP fundamentals, so I'll avoid stuff like method references and task communication primitives (which is how I would probably implement a lot of this normally)
I would start with a simple interface that defines all the things the dishwasher can do in a "physical" sense, so drain/wash/heat up/ etc.:
class Dishwasher{
setWaterTemp(temperature) //True starts prewash, false ends prewash
setDraining(enabled) //True starts draining, false ends draining
setPrewash(enabled) //True starts prewash, false ends prewash
setDrying(enabled)
}
Then define a cycle with how long it should take, and what it does to the dishwasher:
class CycleAction{
int howLongToRun;
virtual void run(dishwasher);
}
For example:
class PrewashAction{
constructor(howLongToRun)
override void run(dw){
dw.setPrewashing(true)
vTaskDelay(howLongToRun)
dw.setPrewashing(false)
}
}
class TemperatureAction{
constructor(howLongToRun, whatTempToUse)
override void run(dw){
dw.setTemperature(whatTempToUse)
vTaskDelay(howLongToRun)
}
}
class DrainAction{
constructor(howLongToRun)
override void run(dw){
dw.setDraining(true)
vTaskDelay(howLongToRun)
dw.setDraining(false)
}
}
Now we can define a Program as a list of actions:
class WashProgram{
virtual vector<CycleAction> getActions()
int startingTime;
void startCycle(dishwasher){
startingTime = currentTime
Loop Through GetActions
action.run();
}
getTotalTime(){
totalTime = 0
Loop Through this->getActions()
totalTime += action.
}
int remainingTime(){
return currentTime - startingTime
}
}
Now your Programs are easy to define and update:
class FruitWashProgram : WashProgram{
override void getActions(){
return {
SetTemperatureAction(100 degrees),
DrainAction(2 minutes),
FillAction(2 minutes),
PrewashAction(3 minutes),
DrainAction(2 minutes)
}
}
}
class QuickHotCycle : WashProgram{
override void getActions(){
return {
SetTemperatureAction(250 degrees),
DrainAction(1 minutes),
FillAction(1 minutes),
WashAction(1 minutes),
DrainAction(2 minutes)
}
}
}
class QuickCold : WashProgram{
override void getActions(){
return {
SetTemperatureAction(60 degrees),
DrainAction(1 minutes),
FillAction(1 minutes),
WashAction(1 minutes),
DrainAction(2 minutes)
}
}
}
Now there is a ton of room for improvement, but I leave that as an exercise for you. Some things to think about:
A real washing machine has "fuzzy logic", each step won't take a predefined amount of time but will depend on factors like how hot the tap water was when it started. You could replicate that by adding an "estimate" function to CycleAction
Some of the programs will be very similar. QuickHot and QuickCold for example. Maybe you can make a QuickProgram, then extend that with specific temperatures for Hot and Cold
Maybe certain steps need something to have happened before running. For example, you don't want to dry unless a drain has occurred. You could enforce that in a "validate" function somewhere, or add a way for the dishwasher to communicate it's in an error state
I used psuedo-code that doesn't really match any language, so if you need me to clarify anything just drop a comment and I'll explain as best as I can

Related

Arduino double clap sensing code breaking

I am making a program that turns my lights on when I clap twice. I coded the project to:
1. listen for a noise (first clap)
2. listen for quiet (break between claps) this is to avoid false triggers (talking, etc.).
3. listen for a second noise (second clap).
The code runs through and works properly, but it has several breaking points that I am struggling to find/fix. I know if I make a noise, then I am quiet, then I make another noise repeatedly, and in rapid succession the code either gets stuck in the first while loop, or stops entering the first while loop altogether. The code often breaks when I am talking.
I have provided the code if anybody is willing to spare me some of there time and effort. I will be appreciative of all suggestions as I am still a beginner.
bool quiet = false;
bool loud = false;
int runtime = 1000;
int start = millis();
bool clap = false;
bool clap2 = false;
void setup() {
Serial.begin(9600);
pinMode(2, INPUT);
}
void loop() {
int mic = digitalRead(2);
if (mic == 0) {
Serial.println("loud");
clap = true;
} else {
Serial.println("quiet");
}
if (clap == true) {
clap = false;
Serial.println("clap");
start = millis();
delay(500);
while (start >= millis() - runtime && loud != true) {
mic = digitalRead(2);
if (mic == 0) {
Serial.println("noise detected!");
loud = true;
} else {
Serial.println("scilence");
quiet = true;
}
}
} else {
delay(1);
}
if (quiet == true && loud == false) {
quiet = false;
Serial.println("listening for second clap...");
delay(500);
start = millis();
while (start >= millis() - runtime) {
mic = digitalRead(2);
if (mic == 0) {
clap2 = true;
} else {
delay(1);
}
}
} else {
loud = false;
quiet = false;
}
if (clap2 == true) {
clap2 = false;
Serial.println("clap 2");
delay(1000);
} else {
delay(1);
}
}
Welcome to StackOverflow!
From the program you posted I think you are over-complicating it ;). First of all, the delay() function is a blocking function: nothing can happen during the lapse of time of the delay. Thus it is usually advise to compare times in order to know if you have waited enough: you can then perform other tasks in the meantime.
I would propose something like this for your loop() function:
if(digitalRead(2)==0) //loud
{
unsigned long first_clap_time = millis();
unsigned long elapsed_time = 0;
bool silence = false;
bool exit = false;
while (elapsed_time < 5000 || exit) // allow a max delay of 5sec
{
if (digitalRead(2)!=0) silence = true;
elapsed_time = millis() - first_clap_time;
if (digitalRead(2)==0 && elapsed_time > 500 && silence)
{
Serial.println("Two claps detected!"); //if a second clap is detected 500 milliseconds after the first, and before 5 sec, and a silence was detected
exit = true;
}
}
}
This should be able to detect only two claps, separated by a time between 500 milliseconds and 5 seconds (to adjust of course). I have no way to test this program so do not hesitate to provide feedback!
Hope it helps,

Make one button switch stages of an RGB diode

I want to be able to start off the program with nothing on, then when I push the button once, it should switch to red, then if you push it another time it should switch to green, and push it again and it should go to blue. After all that it should turn off when you push the button again, then it just loops.
Here's what I've been working with but it seems to fail.
When you push the button the first time it always goes to red, if you push it again, it does nothing. If you keep spamming the button it switches randomly through all the colors but never turns off.
void loop() {
int toRed = digitalRead(button);
if (toRed == HIGH){
switchtoRed();
delay(250); // Give you time to take your finger off the button.
int toGreen = digitalRead(button);
if (toGreen == HIGH) {
switchtoGreen();
delay(250);
int toBlue = digitalRead(button);
if (toBlue == HIGH) {
switchtoBlue();
delay(250);
int state = digitalRead(button);
if (state == HIGH) {
return;
}
}
}
}
}
The problem is the logic in your code is flawed. It is acting as if the digitalRead function is waiting until you press the button. Instead what is actually happening is the loop function is being called repeatedly and you're only ever really testing the outermost button test or if you spam the button, you might be lucky enough to get it to cycle through each of the colours.
Instead what you want is to just test the button and if has been pressed, increment a variable to indicate what light should be on. Something like:
int pressed = 0;
int state = 0;
void loop()
{
if(digitalRead(button)==HIGH)
{
if(pressed==0)
{
pressed=1;
switch(state)
{
case 0:
switchToRed();
state++;
break;
case 1:
switchToGreen();
state++;
break;
case 2:
switchToBlue();
state++;
break;
case 3:
switchToOff();
state=0;
break;
}
}
}
else
{
pressed=0;
}
}
You can do something like this with using a state machine design pattern approach:
int nextState = 0;
void loop(){
while(1){
if(digitalRead(button) == HIGH){
switch(nextState){
case 0: // Red Button
switchToRed();
break;
case 1: // Green Button
switchToGreen();
break;
case 2: // Blue Button
switchToBlue();
break;
case 3: // Switch off
switchOff();
break;
}
nextState = (nextState + 1) % 4;
delay(250);
}
// or you can delay here
}
}
And if you don't want to continue after case 3; you can break the loop using a return statement in case 3.

ARDUINO UNO+SIM808(GPS/GSM) SYNCHRONISATION

I started a project quite recently were I intend to combine the arduino uno and the sim808 module which has gps/gsm/gprs all together in one.
Using just the gps functionality works fine, just the gsm both receiving and sending messages also works good. but combining them for what i intend makes the entire system falls apart.
I intend to be able to have some coordinates registered let's say position A position B and position c, and the system i intend to design is put on a moving, let's say car, now anyone on either of the positions will send a message with the alphabet denoting the position to a number lets say "A TO +23*******98 , AND WOULD get a reply of the cars current time from that position.
With all parts combined the program would sometimes not even indicate receiving any message or even if it did the gps part won't even work.
Is there something I am doing wrong or is it not just feasible with what the components I am using pls help as I am very confused right now.
`#include <SoftwareSerial.h>
SoftwareSerial GPRS(7, 8); // RX, TX
String BUSNUM="A"; // THIS SIM IS TO BE INSTALLED ON BUS A
static String sendersnumber;
char* key;
char MESSAGE[280];
String latitude;
String longitude;
String Speed;
enum _parseState
{
PS_DETECT_MSG_TYPE,
PS_IGNORING_COMMAND_ECHO,
PS_READ_CMTI_STORAGE_TYPE,
PS_READ_CMTI_ID,
PS_DETECT_MSG_TYPE2,
PS_IGNORING_COMMAND_ECHO2,
PS_READ_CMGR_STATUS2,
PS_READ_CMGR_CONTENT2,
PS_READ_CMGR_DATE2,
PS_READ_CMGR_STATUS,
PS_READ_CMGR_NUMBER2,
PS_READ_CMGR_NUMBER,
PS_READ_CMGR_SOMETHING,
PS_READ_CMGR_DATE,
PS_READ_CMGR_CONTENT,
PS_READ_VIDEO_CONTENT,
PS_READ_VIDEO2_CONTENT,
PS_READ_CMGR_SOMETHING2,
PS_READ_VIDEO_CONTENT2,
};
byte state = PS_DETECT_MSG_TYPE; // KEEP TRACK OF WHAT STATE WE ARE IN RIGHT NOW
char buffer[100]; // WHAT WE ARE READING INTO
byte pos = 0; //WHAT POSITION WE ARE AT IN THAT BUFFER
int lastReceivedSMSId = 0; // LAST RECIEVED SMS ID
boolean validSender = false; //SOO NOT JUST ANYONE HAS ACESS TO SEND A COMMAND
void resetBuffer()
{
memset(buffer, 0, sizeof(buffer));
pos = 0;
}//BASICALLY TO RESET THE BUFFER
void setup()
{
GPRS.begin(9600);
Serial.begin(9600);
GPRS.println("AT+CGNSPWR=1");
delay(290);
GPRS.println("AT+CGNSURC=0");
delay(300);
GPRS.println("AT");
delay(300);
GPRS.println("AT+CMGF=1"); // INITIALIZE SMS
delay(300);
for (int i = 1; i <= 15; i++)
{
GPRS.print("AT+CMGD=");
GPRS.println(i);
delay(300);
// Not really necessary but prevents the serial monitor from dropping any input SINCE WE KNOW LIMIT TO STORE IS 15, THIS JUST DELETES IT CLEARS IT
while(GPRS.available())
Serial.write(GPRS.read());
}
delay(2000);
GPRS.println("AT+CGNSURC=1");
}
void loop()
{
while(GPRS.available()) //ONLY WHEN THERE IS SOMETHING AVAILABLE,
{
GSM_NUM1(GPRS.read());
//delay(50);
GPRS.println("AT+CGNSINF");
// delay(40);
GPSAnalyzer(GPRS.read());
sendSMS();
}
}
// END OF VOID LOOP
void GSM_NUM1(byte b)
{
buffer[pos++] = b;
if ( pos >= sizeof(buffer) )
resetBuffer(); // just to be safe
switch (state)
{
case PS_DETECT_MSG_TYPE:
{
if ( b == '\n' )
resetBuffer();
else {
if ( pos == 3 && strcmp(buffer, "AT+") == 0 ) {
state = PS_IGNORING_COMMAND_ECHO;
}
else if ( pos == 6 ) {
//Serial.print("Checking message type: ");
//Serial.println(buffer);
if ( strcmp(buffer, "+CMTI:") == 0 ) {
Serial.println("Received CMTI");
state = PS_READ_CMTI_STORAGE_TYPE;
}
else if ( strcmp(buffer, "+CMGR:") == 0 ) {
Serial.println("Received CMGR");
state = PS_READ_CMGR_STATUS;
}
resetBuffer();
}
}
}
break;
case PS_IGNORING_COMMAND_ECHO:
{
if ( b == '\n' ) {
//Serial.print("Ignoring echo: ");
//Serial.println(buffer);
state = PS_DETECT_MSG_TYPE;
resetBuffer();
}
}
break;
case PS_READ_CMTI_STORAGE_TYPE:
{
if ( b == ',' ) {
Serial.print("SMS storage is ");
Serial.println(buffer);
state = PS_READ_CMTI_ID;
resetBuffer();
}
}
break;
case PS_READ_CMTI_ID:
{
if ( b == '\n' ) {
lastReceivedSMSId = atoi(buffer);
Serial.print("SMS id is ");
Serial.println(lastReceivedSMSId);
GPRS.print("AT+CMGR=");
GPRS.println(lastReceivedSMSId);
//delay(500); don't do this!
state = PS_DETECT_MSG_TYPE;
resetBuffer();
}
}
break;
case PS_READ_CMGR_STATUS:
{
if ( b == ',' ) {
Serial.print("CMGR status: ");
Serial.println(buffer);
state = PS_READ_CMGR_NUMBER;
resetBuffer();
}
}
break;
case PS_READ_CMGR_NUMBER:
{
if ( b == ',' ) {
Serial.print("CMGR MSSG SENDERS Number: ");
Serial.println(buffer);
String sendersnumber=buffer;
// Uncomment these two lines to check the sender's cell number
//validSender = false;
//if ( strcmp(buffer, "\"+0123456789\",") == 0 )
validSender = true;
state = PS_READ_CMGR_SOMETHING;
resetBuffer();
}
}
break;
case PS_READ_CMGR_SOMETHING:
{
if ( b == ',' ) {
Serial.print("CMGR something A.K.A SENDER'S NAME: ");
Serial.println(buffer);
state = PS_READ_CMGR_DATE;
resetBuffer();
}
}
break;
case PS_READ_CMGR_DATE:
{
if ( b == '\n' ) {
Serial.print("CMGR date: ");
Serial.println(buffer);
state = PS_READ_CMGR_CONTENT;
resetBuffer();
}
}
break;
case PS_READ_CMGR_CONTENT:
{
if ( b == '\n' ) {
Serial.print("CMGR MESSAGE Content: ");
Serial.print(buffer);
String key=buffer;
// sendSMS();
// GPSAnalyzer();
GPRS.print("AT+CMGD=");
GPRS.println(lastReceivedSMSId);
//delay(500); don't do this!
state = PS_DETECT_MSG_TYPE;
resetBuffer();
}
}
break;
}
}
void GPSAnalyzer(byte b)
{
buffer[pos++] = b;
if ( pos >= sizeof(buffer) )
resetBuffer();// just to be safe
switch (state)
{
case PS_DETECT_MSG_TYPE2:
{
if ( b == '\n' )
resetBuffer();
else {
if ( pos == 9 ) {
// Serial.print("Checking message type: ");
// Serial.println(buffer);
if ( strcmp(buffer, "+UGNSINF:") == 0 ) {
Serial.println("Received CGNSINF:");
state = PS_READ_CMGR_STATUS2;
}
resetBuffer();
}
}
}
break;
//CHECK
case PS_IGNORING_COMMAND_ECHO2:
{
if ( b == '\n' ) {
//Serial.print("Ignoring echo: ");
//Serial.println(buffer);
state = PS_DETECT_MSG_TYPE2;
resetBuffer();
}
}
break;
//THIS WOULD READ FROM +CGNSINF: (TO THE COMMA),
case PS_READ_CMGR_STATUS2:
{
if ( b == ',' ) {
Serial.print("RUN STATUS: ");
Serial.println(buffer);
String runstatus=buffer;
state = PS_READ_CMGR_NUMBER2;
resetBuffer();
}
}
break;
case PS_READ_CMGR_NUMBER2:
{
if ( b == ',' ) {
Serial.print("FIX STATUS : ");
Serial.println(buffer);
String fixstatus=buffer;
fixstatus.replace(","," ");
validSender = true;
state = PS_READ_CMGR_SOMETHING2;
resetBuffer();
}
}
break;
// this is DATE AND TIME i dont need this
case PS_READ_CMGR_SOMETHING2:
{
if ( b == ',' ) {
Serial.print("DATE AND TIME : ");
Serial.println(buffer);
String dateandtime=buffer;
state = PS_READ_CMGR_DATE2;
resetBuffer();
}
}
break;
case PS_READ_CMGR_DATE2:
{
if ( b == ',' ) {
Serial.print("LATITUDE: ");
Serial.println(buffer);
latitude=buffer;
latitude.replace(","," ");
state = PS_READ_CMGR_CONTENT2;
resetBuffer();
}
}
break;
case PS_READ_CMGR_CONTENT2:
{
if ( b == ',' ) {
Serial.print("LONGITUDE: ");
Serial.println(buffer);
longitude=buffer;
longitude.replace(","," ");
state = PS_READ_VIDEO_CONTENT2;
resetBuffer();
//delay(500); don't do this!
}
}
break;
case PS_READ_VIDEO_CONTENT2:
{
if ( b == ',' ) {
Serial.print("ALTITUDE: ");
Serial.println(buffer);
String Altitude=buffer;
state = PS_READ_VIDEO2_CONTENT;
resetBuffer();
//delay(500); don't do this!
}
}
break;
case PS_READ_VIDEO2_CONTENT:
{
if ( b == ',' ) {
Serial.print("SPEED(KM/HR): ");
Serial.println(buffer);
String Speed=buffer;
Speed.replace(","," ");
state =PS_DETECT_MSG_TYPE2;
resetBuffer();
}
}
break;
//use goto to put it at sms begining
}
}
void sendSMS()
{
if ( strcmp(key,"A") == 0 )
{
float lati=7.200970;
float longi=5.181782;
float Speed1 = atof(Speed.c_str());
float latituded = atof(latitude.c_str());
float longituded = atof(longitude.c_str());
float Distance = HaverSine(lati,longi,latituded,longituded);
float duration=Distance/Speed1;
const int StrLen = 10;
char * duration_new ;
double Value = duration;
(void) dtostrf (Value, StrLen, 6, duration_new);
String MESSAGE="BUS A";
MESSAGE+=duration_new ;
Serial.print("THE MESSAGE SENT IS ");
Serial.println(MESSAGE);
}
else if ( strcmp(key,"B") == 0 )
{
float lati=7.290970;
float longi=5.141782;
float Speed1 = atof(Speed.c_str());
float latituded = atof(latitude.c_str());
float longituded = atof(longitude.c_str());
float Distance = HaverSine(lati,longi,latituded,longituded);
float duration=Distance/Speed1;
const int StrLen = 10;
char * duration_new ;
double Value = duration;
(void) dtostrf (Value, StrLen, 6, duration_new);
String MESSAGE="BUS B";
MESSAGE+=duration_new ;
Serial.print("THE MESSAGE SENT IS ");
Serial.println(MESSAGE);
}
delay(300);
GPRS.print("AT+CMGF=1\r\n");
delay(100);
GPRS.println("AT+CMGS=\""+sendersnumber+"\"\r\n");
delay(100);
GPRS.println(MESSAGE);
delay(100);
GPRS.println((char)26);
delay(100);
GPRS.println();
delay(100);
}
float HaverSine(float lat1,float lon1,float lat2,float lon2)
{
String fixstatus;
float ToRad = PI / 180.0;
float R = 6371; // radius earth in Km
float dLat = (lat2-lat1) * ToRad;
float dLon = (lon2-lon1) * ToRad;
float a = sin(dLat/2) * sin(dLat/2) +
cos(lat1 * ToRad) * cos(lat2 * ToRad) *
sin(dLon/2) * sin(dLon/2);
String o= fixstatus + "8";
float c = 2 * atan2(sqrt(a), sqrt(1-a));
float d = R * c;
return d;
}
EXPLANATION After all declarations and initializations the first active part of the entire code is the for loop that just deletes all former messages from the sim card memory.it runs 15 times
for (int i = 1; i <= 15; i++) { GPRS.print("AT+CMGD="); GPRS.println(i); delay(300); while(GPRS.available()) Serial.write(GPRS.read()); }
Now, having functions GSM_NUM1(); GPSAnalyzer(); sendSMS(); Which are defined below in the code
GSM_NUM1(); GPSAnalyzer(); both work similarly they extract needed data which come in separated by commas. For the gps which comes in , in the form
+UGNSINF: ,,,,, ,,, ,,,,,,, ,,,,
lathitude, speed and any other important parameter is extracted.
For GSM_NUM1(); it gets the senders message and number into variable.
sendSMS(); this just does some calculation based on the message received and send a certain result to the number who requested it.
OBERVATIONS
When the program starts nothing happens which is good cause nothing is supposed to until something new comes in. Hence the void loop() { while(GPRS.available()) //ONLY WHEN THERE IS SOMETHING AVAILABLE, { GSM_NUM1(GPRS.read());
//delay(50); GPRS.println("AT+CGNSINF"); // delay(40);
GPSAnalyzer(GPRS.read()); sendSMS(); } Now this is were things go bad, as the first function works good, it waits gets the message and extracts the senders number and message"key" into variables but immediately after that I wantjust one return of the gps info shown below that's why I used ("AT+CGNSINF"); instead of ("AT+CGNSURC=1"); as the later gives continuous gps data such as
+UGNSINF: ,,,,, ,,, ,,,,,,, ,,,,
BUT instead of one line of the gps data to be gotten from were lathitude and some other parameters are extracted into variables "THE PROGRAM HANGS/STOPS for some unknown reason.
SUSPICIONS
Since the SIM808 possess gps/gsm on the same module. It makes it kind of tricky to separate them in the sense that.
IF I WANT THE GPS TO BE ON BUT NOT READ IN ANY DATA UNTIL A VALID REQUEST COMES IN , IN FORM OF AN SMS THEN THE NECESSARY GPS INFORMATION IS PARSED AND SOME CALCULATIONS ARE DONE TO GET A PARAMETER THAT WOULD BE SENT TO THE SAME NUMBER THAT REQUESTED IT.
PERSONNALY, I FEEL THAT GETTING THE GPS AND GSM TO WORK HAND IN HAND WITHOUT CANCELLING EACH OTHER OUT IN SOME WAY,SUCESSFULLY WOULD BE THE END OF MY PROBLEM. AND I THINK IT COMES DOWN TO THE POSITION OF THE AT COMMAND
GPRS.println("AT+CGNSURC=1"); AND/OR GPRS.println("AT+CGNSINF"); AS the former spits out the gps data every GNSS FIX continuously when called once and LATER spits it out just once per one command.
the attached picture just shows the continous nature of the output of ("AT+CGNSURC=1"); , just as ("AT+CGNSINF"); spits out just one line with +CGNSINF: at the begining instead
Please check that is not in overflow SRAM , that produces stranger things when you execute the program. This occur when you declare so much variables, you can use this library to check the use of sram.
I ran into this similar issue with trying to get GPS data from a module over serial but figured it out after painstaking hours. Essentially you need to validate every response from every command and flush the serial port before every write.
Flushing the serial port buffer before you write any command will ensure that you don't accidentally read left over characters from a previous command when you are trying to get the output of the one you just ran. Most TAs (Terminal Adapters) use EOL characters like OK which translates into "\r\nOK\r\n". If you do not read them all, they can hang around and interfere with the next command you send/ read a response from.
use GPRS.flush() to get rid of extra garbage characters in the serial buffer before sending commands.
Also, creating a generic command function to pass all AT commands and validate their output will save you a lot of sleep.
something like
int sendCommand(int fd, char* message, char* eol, char* response){
int wlen, rlen;
char buf[1024];
tcflush(fd, TCIOFLUSH); //flush the serial port to remove anything left over
wlen = write(fd, message, strlen(message)); //write command to terminal
tcdrain(fd); //delay until 1st readable character is written by modem
delay(100); //delay a little longer until all characters are written(hopefully)
rdlen = read(fd, buf, sizeof(buf) - 1); //read from serial port
if(rdlen > 0){ //if readable characters
if(strstr(buf, eol) != NULL){ //if my end of line character is present then
int i = 0; //output from TA is complete
while(buf[i] != '\0'){ //while buffer has more characters
response[i] = buf[i]; //copy string into the string I passed, char by char
}
return 1; //return 1 (i.e.true aka success)
}
}
return 0; //return 0 (i.e. false aka failure)
}
I wrote this for a communicating to a simcom5320 but I didnt use software serial so it'll be a little different for you. Use this function for all your at commands to ensure everything actually succeed like:
char commandReply[512];
if(sendCommand(myFileDescriptor, "AT+CGNSINF\r", "\r\nOK\r\n", commandReply)){
//do something with commandReply or not
} else {
//command failed
//do something else
}
Hope this helps!

Arduino Gcode reader

I made G-code reader on Arduino, but it stops reading. It has many "break;" and I have also many while loops and switches, so I'm thinking that when I break on loop/switch, it will break all.
Another idea is that it goes some kind of loop, but I can't figure out where it loops.
Here is my code:
void Gcode(){
String yy,xx,gg;
char text[64];
int number=1;
while(number!=3){
while (Serial.available()>0) {
delay(3); //delay to allow buffer to fill
char c = Serial.read();
Serial.println(c);
switch(c){
case 'G':
//read_number()
while (Serial.available()>0) {
char k = Serial.read();
if(k==' ' || k=='\n'){
break;
}
else{
gg+=k;
}
}
switch(gg.toInt()){
case 1:
Serial.println(gg);
while (Serial.available()>0) {
c = Serial.read();
Serial.println(c);
switch(c){
case 'X':
while (Serial.available()>0) {
char k = Serial.read();
if(k==' ' || k=='\n'){
break;
}
else{
xx+=k;
}
}
char buf[xx.length()];
xx.toCharArray(buf,xx.length());
x2=atof(buf);
Serial.println(x2);
break;
case 'Y':
while (Serial.available()>0) {
char k = Serial.read();
if(k==' ' || k=='\n'){
break;
}
else{
yy+=k;
}
}
Serial.println(yy);
char buf2[yy.length()];
yy.toCharArray(buf2,yy.length());
y2=atof(buf2);
break;
case 'E':
break;
case 'F':
break;
default:
Serial.print("the end");
}
Serial.print("out of switch");
}
break;
case 2:
break;
default:
Serial.print("nothing");
}
break;
case '\n':
number=3;
break;
default:
Serial.print("default");
}
}
}
if(sizeof(yy)>0){
yy="";
xx="";
gg="";
}
Serial.print("quit");
}
When I send G1 X10.00 Y-100.00 \n It prints only:
G
1
X
10.00
out of s
one of your big problem is that your while end when thwere are nomore carachter. This mean that if your loop consume the buffer FASTER than it get written (remeber:9600 baud mean 960Byte/s, arduino even if slow but can compute 16.000.000 operation/s...).
Another big problem MAY bethe lack of ram, os your output is truncated. there is some function to check real time usage of ram, see http://playground.arduino.cc/Code/AvailableMemory, stopping to use String and even char array is a way better idea; the code is not that hard to write!
so the pc would send "G1 X10.00 Y-100.00 \n"
but at time X your aruino get "G1 X10.00", if you read really fast the buffer now (faster than 1/960 of a second, arduino is a way faster than that!)
so ideally you should change all your while condition removing serial available but instead putting the condition you use in the if with the break; sothe first while from
while (Serial.available()>0)
became
while ( (k=Serial.read()) != ' ' && k != '\n') //yes it is a bit weird like this
maybe a little better, with check that k is a valid caracter, AND timeout
unsigned long timeout_ms = 1000; //timeout after 1 seconds from NOW!
unsigned long start_ms = millis();
int k=Serial.read();
while ( k != ' ' && millis()-start_ms < timeout_ms){// because here we expect "Gx ", why are you was also using k != '\n'? removed, feel free to add it back
if (k == -1){
k=Serial.read(); //read the next char
continue; //return to the beginning of the while
}
[... do thigs...]
k=Serial.read(); //read the next char
//here you may add "start_ms = millis();" if you want to reset the timeout
}

Arduino not entering for loop

I'm having a problem with an if ladder and the for loops in each of them in this gameProcess function. Essentially the for loop in the (mode == 1) loop is not entered at all and I'm not sure why.
I think it's something to do with the positioning because if (mode == 1) is switched with (mode == 0), the (mode == 1) for loop will be entered but the (mode == 0) won't. Been stuck on this for a while and can't seem to spot what's up with the function. Any help would be greatly appreciated. Thanks.
// 5 means 10 switches as one iteration is a change between one mode to another, not on and off.
int gameProcess(int mode) {
Serial.println("> Starting game process.");
// 4 second delay between
int interval = 1000;
int initialDelay = 5000;
enter code here:
//delay(initialDelay);
if (mode == 1) {
// for a standard 25 round with a 2 sec interval
Serial.println("starting mode 1");
for (int i; i < 51; i++) {
Serial.println("In loop");
Serial.println(interval);
flickPin(13);
workingDelay(interval);
}
Serial.println("finished mode 1");
} else if (mode == 2) {
while(true) {
flickPin(13);
int minRandVal = 1000;
int maxRandVal = 15000;
int randomDelay = random(minRandVal, maxRandVal);
Serial.println(randomDelay);
workingDelay(randomDelay);
}
} else if (mode == 0) {
// for 10 rounds. Find out why it needs 35 and not 20.
Serial.println(" - Mode 0 .");
for (int i; i < 35; i++) {
Serial.println(interval);
flickPin(13);
workingDelay(interval);
}
Serial.println(" - finished Mode 0 .");
} else {
char error[80];
sprintf(error, "Unknown mode = %d", mode);
Serial.println(error);
}
}
Here is the main loop and the initializeGame function where the gameProcess function is called from.
int initializeGame(bool started, int mode) {
if (started == true) {
Serial.println(" -> in startMonitor, start button pressed");
Serial.println(mode);
gameProcess(mode);
// if the mode is 0 (none of the lights are on), that means it's in random mode and any interval between 5 and 60 secs come up until you stop it!
// set it back to false and turn the game light off because the game is over.
started = false;
digitalWrite(9, LOW);
} else {
started = false;
}
return started;
}
void loop()
{
// check if the pushbutton is pressed.
mode = stateMonitor(activeButton);
// now set the game mode led.
lightUpModeLed(ledPins[mode]);
// now check to see if the game has been initialized.
started = startMonitor(startButton, ledPins[4], started);
// read the state of the pushbutton value:
// initialize game if it hasn't already started.
// TODO this is where the loop will likely spend the majority of it's time so how can this be
started = initializeGame(started, mode);
saveData();
}
if you are using windows then install Atmel Studio and the Visual Micro Plugin then you can debug and watch what the code is doing and the values of variables.
This will take away the mystery, which it did for me.

Resources