I have a personal project I have been working on over time (here and there)... and have recently started to purchase some hardware for said project.
This is your typical 'barbot' project.. (liner/slide rails stepper motors....automation of drink making)..
As I am waiting on hardware.... I started to think about the 'interface' I'd like to have for 'ordering' said drinks from a menu.
This may be better suited for a Raspberry Pi forum.. but since it does include communication with an Arduino, I figured I'd start here..
So here we go!
Being a web developer by trade.. using a Raspberry Pi with LAMP installed seemed like the most logical approach for serving up an interface to be used as the 'drink menu'
ie: There is an admin page that allows the 'user' to set the bottled name/code and order in which it exists in the barbot physical location.
This all gets saved to a table..
There is a 'menu page' where my PHP/MySQL code creates a page of drinks based on the available 'alcohol' set in the admin page (ie: if there is no vodka set to active order number or set to inactive.. no vodka based drinks will display in the menu page)...
So the web aspect of this is 85% complete... some minor CSS/style tweaks left.. and creation of the 'serial command protocol' I need to create/finalize.
And here is where the collective brain trust of members here can help me maybe streamline things.. or suggest something I may over overlooked or not accounted for.
This is a two part question/post:
- One talks about the serial protocol I'm putting together
- One talks about the web site being served/hosted on the RaspberryPi, and how can I get external serial data to 'trigger' change the state of the web app/interface... (example.. when a drink icon is selected.. the RPi will send that serial data out to the Arduino.. and then change the web page to display a 'drink making in progress' screen... but when the drink is complete on the Arduino side.. I want to send some sort of alert/notification that it is complete.. and to go back to showing the drink menu.
1.) The serial 'protocol'... and how it should be put together.
I have done other serial comm. based projects before.. but usually in a limited fashion (sending minor data/values).. or sending some RGB value(s) to be parsed and applied. (I'm altering this approach to hold some more data)
This is the typical start/end packet 'character' that is checked for.. then parsed once end packet has been met..etc..
Which was normally like this format:
<r=255>
(but not I am changing it up to add another value that will need to be parsed)
<b=1:1>
(I havent wrapped my brain around strtok yet on how to do the sub parsing of the x:x data)
Do I need to account for the ':' character in there? (and skip over it? like re-assign that token value twice?
ie: token3 = ':' and then re-assign token3 again after that like: char *valueToken = strtok(NULL, "\0");?
However, I'm not clear on how that works if the data/values between the starts & end packets are NOT the same length.. how does that affect the char array? (it can be less without issue.. but can not be more/longer? Is that correct?) (sorry I'm a spoiled web dev, and we dont have to worry about allocating space/resources and stuff like this.. so I always forget the process)
- What I'm also not sure about here is..if I parse the first packet.. and then execute the actions.. (ie: move stepper to position x, then dump alcohol 'x' amount of time(s)......).. am I going to loose the other incoming serial data? while the first packet 'actions' are being performed? (I dont want any packet loss/dropping where an ingredient of the drink recipe is missing/skipped obviously)
This project will need a multi-action/serial command type of approach. (per drink/recipie). (as there is no telling the ingredients or the amount.. so a set/hardcoded character count wont work here.. so I'm trying to figure out a nice way to declare: (so far)
- action type (used to determine if this is a bottle 'shot' dump... or a valve 'pour' type of action)
- bottle order
- amount(s)
Here is my attempt (I'm at work.. and have no IDE to test anything as of yet) at the parsing routine:
example (projected) incoming serial data:
//example recipe format
//<b=1:1><b=2:1><m=6:200> = bottle#1/1 shot, bottle#2/1 shot, mixer#6/200ms
- Is this flawed?
- Can it be improved? (I have looked at other examples that use an array of delimiters, and while loops...is this a preferred approach?)
- Should I just use the same delimiter?
- I am again concerned about how this works.. when the next 'packet' (instruction) comes in? (ie: the next of values).. will I loose anything because I am executing the first set of actions/values?
#define SOP '<'
#define EOP '>'
bool hasStarted = false;
bool hasEnded = false;
char incomingSerialData[8];
byte index;
int positionValue = 0;
int amountValue = 0;
void setup(){
//serial monitor output
Serial.begin(9600);
}
//example recipie format
//<b=1:1><b=2:1><m=6:200> = bottle#1/1 shot, bottle#2/1 shot, mixer#6/200ms
void loop(){
// Read all serial data available, as fast as possible
while(Serial.available() > 0){
char incomingCharacter = Serial.read();
//Serial.println(incomingCharacter);
if(incomingCharacter == SOP){
index = 0;
incomingSerialData[index] = '\0';
hasStarted = true;
hasEnded = false;
}else if(incomingCharacter == EOP){
hasEnded = true;
break;
}else{
if(index < 8){
incomingSerialData[index] = incomingCharacter;
index++;
incomingSerialData[index] = '\0';
}
}
}
// Packet data done...parse/evaluate data
if(hasStarted && hasEnded){
//putstring("VALUE TOKEN: ");
Serial.println(incomingSerialData);
char *actionToken = strtok(incomingSerialData, "="); //split action value from location/amount values
if(actionToken){
//check if bottle 'action' data coming over
if(strcmp(actionToken, "b") == 0){
//grab position value
//char *positionToken = strtok(NULL, "\0");
char *positionToken = strtok(NULL, ":");
if(positionToken){
//putstring("VALUE TOKEN: ");
//Serial.println(positionToken);
positionValue = atoi(positionToken);
//now grab 'amount' value
char *amountToken = strtok(NULL, "\0");
if(amountToken){
amountValue = atoi(positionToken);
}
}
}
//check if mixer action data coming over
if(strcmp(actionToken, "m") == 0){
char *positionToken = strtok(NULL, ":");
if(positionToken){
//putstring("VALUE TOKEN: ");
//Serial.println(positionToken);
positionValue = atoi(positionToken);
//now grab 'amount' value
char *amountToken = strtok(NULL, "\0");
if(amountToken){
amountValue = atoi(positionToken);
}
}
}
}
// Reset for the next packet
hasStarted = false;
hasEnded = false;
index = 0;
incomingSerialData[index] = '\0';
}
}
The second (and last) part of this: (as mentioned above)
Is how to trigger the webpage 'change' on feedback/response from the Arduino (ie: once the drink is complete)
Since this will be run on the Raspberry Pi.. (which is a Linux based)... I should NOT have an issues talking over serial via PHP....correct?
I know on a Windows platform I can only use serial comm. one way (from PHP >> Arduino). but not the other way around (Arduino >> PHP)..
But on Mac/Linux..etc my understanding is that is not a problem.....correct?
If this is correct.. then the only way I can even think of doing this is to, once the 'drink is being made' message/page is displayed.. I have some sort of loop that checks for any incoming serial response? (and then output whatever I want as the new HTML/markup)..
I am NOT a fan of this 'polling' type of approach.. but in this project/case scenario.. I think its valid enough (since the project wont be doing anything/shouldnt be anything until the drink is finished being made).. but I'm open to other suggestions/approaches as well?
To be clear though.. I using Apache, PHP & MySQL as my base currently.