This is meant as an educational/practice project.
I'm planning to use a nano and simple 2 motor(wheel) h-bridge board. As usual the code will be my challenge and I'm not sure what the simplest method will be. The goal is to have the simplest possible input string which would consist of 4 possible commands: F(orward), B(ack),(R)ight,(L)eft for which I could add any combination and length of letters to yield a series of pre-programmed robot actions which carry out upon startup. Clearly the code below won't work yet but this is what I've got so far.
Thanks for any advice!
Variable names cannot start with a digit.
This is nonsense.
It is unclear what you are attempting.
Look at line follower projects for the basic steps and valid syntax.
Thanks! That's helpful, but part of my question here is how to form functions or whether to use "case" instead to basically define a robot path by a line of characters defined in a string. The trouble with the followers is that they use sensor inputs to follow that line and so the instructions don't particularly benefit from brevity. Imagine instead that you wanted to follow a line but instead of sensors you just wanted to tell it in the program to move forward, then turn right, then forward again, etc. The examples do help with syntax of course. I didn't know that variables couldn't start with a number (for example) so updated the code.
Your response is nonsense. I'm trying to learn syntax & code. Comments & description indicate what I'm attempting. Thank you for at least the helpful variable detail. I've updated accordingly.
It is unclear what you hope this will achieve.
It will probably compile (I haven't tried, but if you'd correctly qualified A1 and A2 as "const" at least you'd get an error as a hint that what you've written is nonsense), but I think I can guarantee that what it does will be nothing like what you imagine.
Noted.
Good luck with your project.
Please do not go back and edit previous posts that have already been commented on. Just add updated code in a new message.
Regarding your request. Let the compiler do so some work for us. If it won't compile without errors, there really isn't anything to talk about, except why they occur. That is perfectly harmonious with your goal of learning the C language. I suggest you do not chastise people who are helping you. It will discourage other helpers from participating.
If you can not produce any code that will compile, it is too complex for you and you need to study examples and work on some simpler projects before attempting more difficult ones.
The 'switch' value must be an integer (char, byte, int, long int, etc) and the 'case' values must be integer constants. If you are receiving single characters from Serial, like:
int c = Serial.read();
you can use that value directly by comparing with single-character constants:
void loop() {
int c = Serial.read();
switch(c) //F = Forward B = Back R = Right L = Left
{
case 'F':
Note the 'single quotes' on either side of character, making it a character constant.
Note: You can't use double-quotes ("F") because that would be a 'string' (pointer to an array of characters ending with a 'null' (zero value) character) which is not an integer.
I'm sorry I wrote and/or posted this before coffee. "Nonsense" seemed a bit antagonistic to me and I'm still just trying to learn basics here. To me the intent was clear, but I guess its fair to call the resulting code/syntax "nonsense" since it doesn't work.
Its been a while since I tried coding and having just resumed I'm just remembering some of the ins and outs. I think it was probably premature to post here before reviewing some of the code I had written previously. I'll spend some more time sorting it out tonight & I know I can get it compiling and running the robot as intended, but what I was really trying to get to is the best approach to organization of functions and/or "cases" (this is where the waters started to get particularly muddy for me) so that I could update the code with a string of characters that would result in a driving path for the robot. I'd imagined (for example): "FFRFLB" as a single line of code in the program that would result in the robot moving two steps forward, turning right, then forward, then left, and then back. Clearly this can be achieved by cutting and pasting code blocks, but clearly that's not a very refined approach.
Anyway, sorry for this morning's grumpyness and thanks for the help. I'll spend more time in review and refinement before posting here again, but here is the present code partly thanks to todays feedback.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
int pinPWMA = 1;
int pinPWMB = 2;
int pinA1 = 3;
int pinA2 = 4;
int pinB1 = 5;
int pinB2 = 6;
int Ttime = 1000;
int Mtime = 3000;
pinMode (pinPWMA, OUTPUT);
pinMode (pinPWMB, OUTPUT);
pinMode (pinA1, OUTPUT);
pinMode (pinA2, OUTPUT);
pinMode (pinB1, OUTPUT);
pinMode (pinB2, OUTPUT);
}
void loop() {
digitalWrite (pinA1, HIGH);
digitalWrite (pinA2, LOW); //left side wheel fwd
digitalWrite (pinB1, LOW);
digitalWrite (pinB2, HIGH); //right side wheel fwd
delay (Mtime); // wait (Mtime) seconds
digitalWrite (pinA1, LOW);
digitalWrite (pinA2, LOW); //initiate stop
digitalWrite (pinB1, LOW);
digitalWrite (pinB2, LOW);
digitalWrite (pinA1, LOW);
digitalWrite (pinA2, HIGH); //left side wheel rev
digitalWrite (pinB1, HIGH);
digitalWrite (pinB2, LOW); //right side wheel rev
delay (Mtime); // wait (Mtime) seconds
digitalWrite (pinA1, LOW);
digitalWrite (pinA2, LOW); //initiate stop
digitalWrite (pinB1, LOW);
digitalWrite (pinB2, LOW);
digitalWrite (pinA1, HIGH);
digitalWrite (pinA2, LOW); // turn right
digitalWrite (pinB1, HIGH);
digitalWrite (pinB2, LOW);
delay (Ttime); // wait (Ttime) seconds
digitalWrite (pinA1, LOW);
digitalWrite (pinA2, LOW); //initiate stop
digitalWrite (pinB1, LOW);
digitalWrite (pinB2, LOW);
digitalWrite (pinA1, LOW);
digitalWrite (pinA2, HIGH); //turn left
digitalWrite (pinB1, LOW);
digitalWrite (pinB2, HIGH);
delay (Ttime); // wait (Ttime) seconds
digitalWrite (pinA1, LOW);
digitalWrite (pinA2, LOW); //initiate stop
digitalWrite (pinB1, LOW);
digitalWrite (pinB2, LOW);
}
}
Note that these variables are defined inside setup() so they can't be used in any other function. For variables that you want to use in multiple functions, declare them outside of any function (and before the first function in which they are used).
If the name represents a constant value, like a pin number, please declare the variable as 'const'. That will provide the compiler with more opportunities to optimize your code and will allow it to tell you when you are accidentally trying to change the value.
Thank you for your patience & help, johnwasser. This is what I'd hoped to find here at the forums. I'll try to remember your advice and will spend more time making & correcting my mistakes before posting next time! There surely is a lot to learn!
You could make these chunks into functions:
void forward(int someTime){
digitalWrite (pinA1, HIGH);
digitalWrite (pinA2, LOW); //left side wheel fwd
digitalWrite (pinB1, LOW);
digitalWrite (pinB2, HIGH); //right side wheel fwd
delay (someTime);
}
...then use forward(Mtime);
in your code.
case 'F':
forward(Mtime);
break;
...
I'd combine it with something like the processIncomingByte function in NickGammon's serial parsing state machine.
I'd set up your default command string like:
char initialCommands[] = "FRFFFLBB";
...
void setup(){
...
//for (int ii = 0; ii<sizeof(initialCommands);ii++) // edited per #14
for (int ii = 0; ii<strlen(initialCommands);ii++)
{
processCommandChar(initialCommands[ii]);
}
...
}
Thanks DaveX, I'll need to read and google this quite a few more times before I understand it but I can see that it's definitely answering my original question. Of course I have questions but I'll wait till I have a better grasp on things to ask.
I'd suggest "strlen"
Oh yes--the sizeof() introduces an off-by-one because of the addition of the null terminator to the string. And since strlen looks for the end of the string, not the end of the storage, it would be safer when you use a buffer. Edited..
Ok, this is going better than I expected considering how loosely I understand what I'm doing right now, so I will ask this one question for the moment: The variable "Mtime" is meant to represent move time which of course translates to distance this robot will move forward or back. In the function example you cited "someTime" - is that intended to represent the same value or some other variable needed to execute the master plan?
I pursposefully used someTime in the function, to identify it as a distinct parameter from the Mtime. Later I called it as
forward(Mtime);
...which substitutes the value of Mtime
for sometime
with the context of the function.
With that parameter, it could be possible to call forward(2*Mtime)
; or forward(1);
, and providing for possibly later parsing a command string like "FF R 7500F 270L 5000B".
Aha. okay, thanks for the clarification! So it's basically just an improvement involving some foresight to the end result. As this is just a learning effort for the moment I'll probably just keep it as simple as I can until I better understand the concepts like cases & functions and how to implement them correctly.
I think that using a function is simpler than cut and paste, since you don't need to read every little bit to tell the differences between chunks.
And if you are writing a function, I think it is simpler to use local variables and parameters rather than depend on globals, so everything important is on one screen.
Yes, you are right and that's what my original question was asking. I definitely want to define these 5 actions as functions so that I can just call them in one string. Other than that I want to keep the code at a bare minimum until I can understand how everthings works better. Following that I might try some improvements like the someTime variable, but I don't want to do anything fancy until I get my head around the rest of it.