Switch - Case Question - C Code
ajward
Posts: 1,130
Still working on my hybrid Boe/Activity Bot and I've run into a bit of a problem. I'm using Switch - Case to determine a course of action... that is selecting a function to turn Bob based on the return from a Ping.
Everything seems to work, up to the point of switch-case selecting the proper function. I've Googled and can't find quite what I'm looking for. Does anyone have a link to a detailed explanation of the switch-case statement?
Many thanks,
Amanda
Edit: I'll probably have more questions. This is the most complex C program I've written and I have almost certainly overlooked something critically "trivial". ;-)
Everything seems to work, up to the point of switch-case selecting the proper function. I've Googled and can't find quite what I'm looking for. Does anyone have a link to a detailed explanation of the switch-case statement?
Many thanks,
Amanda
Edit: I'll probably have more questions. This is the most complex C program I've written and I have almost certainly overlooked something critically "trivial". ;-)
Comments
Try this link:
http://www.cplusplus.com/doc/tutorial/control/
About 3/4s way down is the discussion on switch/case.
I have an example that I wrote for my ActivityBot where I combined a couple C Learning Tutorials to use of a remote control (Sony DSLR Camera SIRC remote) and whiskers that take control when the bot runs into something. To give immediate action when a whisker hits, I run that in a separate cog. The program is somewhat complex. But the remote control part uses the Case statements. One thing to remember is that each of the case arguments has to be a constant. In my program I used #define to assign the SIRC remote value to a more descriptive constant name (e.g. #define fwd 58 ). If you have a Sony compatible remote and know the numeric codes for the keys, you could actually change the numeric values in the define statements and run the program. There is a program in the Learning C tutorials that reads and displays SIRC codes from a remote.
This was one of my early programs so it is probably a lot more complex than it needs to be, but I think it illustrates the use of the switch-case statement with the use of "break" to end or exit each case.
Tom
As I look at things more, I'm less sure that Switch-Case (My implementation of it anyhow.) is causing my headaches.
What is supposed to happen is:
Bob runs in a straight line till he gets within ~8 inches of an obstacle, then stops and the Ping scans 45 and 90 degrees, left and right.
The code then determines which of the four directions is the longest, turns the 'bot in that direction and starts off in a straight line again.
The last option is to do a 180 and take off again.
The problem is Bob will make a turn, but never the way I think he should and sometimes goes to the default of doing a 180 when there are better options.
Things I (may) have overlooked:
I may not be allowing enough time for Ping to get each distance into the array.
I need to make sure that the "longest distance" is far enough to be useful.
I need to make sure I'm getting the sub-scripts for the array right. (I kind of dislike arrays, but they "can" be pretty useful!)
Not asking for solutions here. Just thinking out loud... in print. I thought about posting my code, but at this point, I didn't want y'all to spend your entire weekend laughing! ;-)
Lastly, a shameful admission! Although I've found C horrendous for larger projects, using it to program my 'bot is rather enjoyable... even preferable to Spin.
Now... off for that second cup of coffee! Keep tinkering!
Amanda
Can you post a zip file archive of your project?
If you are using SimpleIDE, under the Project menu, there is a sub-menu item labeled Zip. If you click Zip, it will archive the entire project, so that you may upload and then we may be able to provide more worthy assistance in your endeavors.
Attached is the zip for Bob's navigation program, 'tis far from perfect. It kind of works except when Switch/Case selects a turn routine, it never seems to be the right one. I know I have to fine tune the distance analysis and possibly add more delay time after the Ping reads a distance. Anyway, here it is...
Bob_roam1.zip
-Tor
Someone recently said... There is no such thing as too many comments....... Well now, I may beg to differ
I realize you are just learning, so I will just say that there is no need to comment the obvious. If I am not mistaken, I believe the archive below should solve your problem, but I do not have your bot to test. Additionally, I doctored up the file to give you an idea of what it should look like, however there are a variety of programming techniques and this is just mine. I just noticed the tabs got messed up, but you should get the idea.
You had a problem in eval_dist() and turn_Bob(). Hope this works for you Compare these functions, and you will see what I did.
When I have comments that wrap around to the next lline I either indent under the statement or break it into pieces so all the \\ line up.
Also, at the top of the program you can use a comment block instead of a comment line.
It's also a good idea to comment functions with what they do, their inputs (if any), and their outputs (if any).
It's also always a good idea to have blank lines between groups of statements that do different things and functions or code blocks.
It's also good practice to put comments before blocks of code explaining what they do.
I've only had time to glance at the code. My "part-time" job has me swamped at the moment. I appreciate you looking and will test it soon. Thank You!
Amanda
Oh... all the comments were just me being goofy. ;-)
Sorry about grilling you over your comments since it looks a lot better in SimpleIDE than Wordpad.
I've deciphered most of the code since my C is very rusty and I don't have an ActivityBot.
Idbruce fixed some errors especially dealing with Arrays. Remember that an array starts at element 0 even though you refer to it at Sector 1.
I see a lot of repeating code that would be better done with a function. For example, your multiple beeps before moving to a sector.
I myself prefer to define constants for things that are easily changed. Idbruce may know whether to use #degine or const.
I do know that #define is used by the Pre-processor, same as the BASIC Stamp editor, while const is treated just like other variables including having a memory location assigned to it.
I do wonder why you use the Differential Drive library instead of the Servo library for the Ping Servo.
The Ping servo is a standard servo while differential drive robots use continuous rotation servos.
There is even a lesson and some code on how to use the standard servo with C here:
http://learn.parallax.com/propeller-c-simple-devices/standard-servo
I also see that you have 2 Global variables that aren't being used. I don't see why you just don't have counter be a global variable since you only use it for looping.
The other one, direction, doesn't appear to be used anywhere.
After studying the ActivityBot tutorial I can see where you got some of your code from.
This program would be a lot cleaner if you first defined what it's supposed to do and then build and test it one function at a time.
Say for example get the Ping servo code working, and also Bob's movement code working before you add them to Main.
It's also a good idea to have separate programs that test each piece of hardware to be sure it's working properly.
Sorry about grilling you over your comments since it looks a lot better in SimpleIDE than Wordpad.
I've deciphered most of the code since my C is very rusty and I don't have an ActivityBot.
Idbruce fixed some errors especially dealing with Arrays. Remember that an array starts at element 0 even though you refer to it at Sector 1.
I see a lot of repeating code that would be better done with a function. For example, your multiple beeps before moving to a sector.
I myself prefer to define constants for things that are easily changed. I see that Andy uses const in the Propeller C Tutorials.
http://learn.parallax.com/node/157
http://learn.parallax.com/propeller-c-simple-protocols/bit-masks-better-code
http://learn.parallax.com/propeller-c-simple-protocols/half-duplex-serial
I do wonder why you use the Differential Drive library instead of the Servo library for the Ping Servo.
The Ping servo is a standard servo while differential drive robots use continuous rotation servos.
There is even a lesson and some code on how to use the standard servo with C here:
http://learn.parallax.com/propeller-c-simple-devices/standard-servo
I also see that you have 2 Global variables that aren't being used. I don't see why you just don't have counter be a global variable since you only use it for looping.
The other one, direction, doesn't appear to be used anywhere.
After studying the ActivityBot tutorial I can see where you got some of your code from.
This program would be a lot cleaner if you first defined what it's supposed to do and then build and test it one function at a time.
Say for example get the Ping servo code working, and also Bob's movement code working before you add them to Main.
It's also a good idea to have separate programs that test each piece of hardware to be sure it's working properly.
@genetix - I did build all the functions separately and they all did their thing. Problem is, when glued together they start mis-behaving. :-(
Amanda
Amanda,
One of the things I do when I'm trying to debug my robot software when I have put all the functions together is to put the robot on a stand so the wheels aren't touching anything, add some print statements at various points in the program, run with terminal, and hold an object at different distances from the ping. Then see what values I get from ping, what value I get for the case statement, and make sure they make sense. If so then do the wheels turn in the right direction? If the ping and case results don't make sense, you will be able to start to isolate the problem.
Tom
I don't have my bot available so I tried to make do with just running the code from post #9 on my quickstart board without the servo and ping functions. I took the code and commented out all of the functions and calls for the servos and ping. I added print statements in each case that just printed "case 0" for case 0, "case 1" for case 1 etc. as shown below.
I loaded ping_dist[] with 5 values with the maximum a specific array elements. Each time I ran the program, I changed the element that had the max value and the terminal showed the correct case#. So the case statement works.
Does the ping servo turn the ping to the correct direction? I've not used the servo_set command, but normally use servo_angle. With that command, I have to have a sufficient pause to allow the servo time to reach its desired direction. I would suggest that you put a pause between the servo_set command and the ping_cm command, to make sure that ping is pinging in the correct direction.
For case 2, the drive_goto command is commented out. That makes sense, since Bob was stopped from moving forward because it was too close to something. But instead of commenting out that command, I'd recommend using the drive_goto(53, -57) to do a 180 (are those numbers correct?).
I also think that as written the code only goes through main one time? It drives straight ahead until it gets too close to something. It then scans and pings and turns to the furthest distance, then proceeds fwd until it gets too close to something, then stops and ends. If the ping reads the furthest distance as straight ahead, it won't turn, will start to move fwd, but then drop through the while statement and stop before it moves.
Tom
I'm beginning to think I'm expecting too much from the Ping sensor. In my tests, I'm driving the 'bot into a "T" shaped area not unlike part of a maze. Again, I "think" the distance readings for straight ahead and 90 degrees right and left are correct, But the returns for 45 degrees each way are being artificially extended because the echo doesn't come straight back to the sensor, but bounces around a bit before the Ping reads it. Does this make sense?
Going to take a look at the "dist_eval" function to see if I can filter out these "erroneous" readings.
@
Sorry I missed your reply of Post #15.
The eval_dist() function and the case statements should be correct, with all of this being dependant upon the following code:
as established in the scan_ahead() function.
Whether or not the intented execution code is workable, I could not verify, but eval_dist() and the case statements were verified as working.
Amanda,
I think your concern regarding the 45 degree angle is the issue. The product guide for ping can be downloaded from this link:
https://www.parallax.com/sites/default/files/downloads/28015-PING-Sensor-Product-Guide-v2.0.pdf
It shows an example of the sound path for different reflection angles, and 45 degrees (or any too 'shallow' an angle) does not directly return to the ping. Also it shows in "test 2" the acceptance angle for a wall parallel to the backplane of the sensor (perpendicular to the axis of the sound path) to be quite narrow -- at 4 ft it is about 10 degrees to either side, further away it drops to about 5 degrees.
If you drew a scale sketch of your "maze" and put the virtual 'BOB' at different points, draw a line from Bob to the wall at 45 degrees and trace the reflection as it bounces off the walls, you can get an idea of how long the path is when (and if) it intersects the ping. Try different angles; you may be able to find an angle that isn't too shallow and works well enough.
If you had a bunch of cylinders as obstacles the 'main beam' of the sound would return directly to ping, but there would also be extraneous reflections that could take multiple paths before returning to the ping. I'm not sure how easy it would be to filter out the extraneous returns.
For now, I'd recommend staying with 0 and +/- 90 degrees (and if the sketch shows an angle that works, that one also), maybe shortening the 'too close' range so that 90 degrees will show an opening.
Hope this helps
Tom