More state problems

I’ve seen several posts with similar problems, but their fixes don’t seem to be helping me. I’ve created a travel patch that takes speed for left & right motors, and time to run, then uses h-bridge node:

I’ve tried replacing the if-else with gate-number, but that failed to stop motors on exit.

In my test patch, if I use boot > defer-pulse > travel > done. It does exactly what I would expect. If I add another defer-pulse > travel before the done, the debug still shows exactly what I would expect, but if left or right motor have a new value for speed, that motor doesn’t run during the 1st travel call. If I add a 3rd travel call, then lcd never gets updated and motors never run; as far as I can tell, nothing is done.

In this example, 1st travel goes forward & 2nd travel goes backward, so motors don’t run on 1st call. If 2nd call does a spin, the motor with same speed 1st & 2nd call will run for both calls (but the other only runs on 2nd call).

[new user can only post 1 image, but it is just boot > defer-pulse > travel (forward) > defer-pulse > travel (back) > done]

That was weird. I took a look at the code for h-bridge to see if some C++ thing was causing the problem. When I saw it just used standard nodes, I copied it to a new patch & added the 2nd direction pin to it instead of controlling it separately in the travel patch. Now it works when there are 2 travel nodes in the main code, but still does nothing when there are 3 travel nodes. There is one difference, though: originally with 3 travel nodes, the LCD display kept old values, now it is getting cleared.

Here is my main patch (currently called test):

The delay-pulse after boot is required, but the others don’t make any difference if I remove them. This has 3 travel nodes, so running it just clears LCD screen. Removing any of the travel commands allows it to work properly. It is configured to go forward 2 sec, spin 2.5 sec, backward 0.5 sec. The travel patch always stops motors before exiting. Different times for each travel makes debug easier to trace.

I can only post one image per reply, so here is my new h-bridge node…pretty trivial…

OK. I broke down & tried gate-number instead of if-else in travel. Now I seem to be able to use any number of travel nodes in main (I just have to explicitly stop now, so I may as well remove time input from travel node), but I found an interesting curiosity…

If I try to tie gate-number to concat for lcd debug, on boot the lcd clears and nothing else happens. OK, not too surprising…probably trying to print a null pointer when gate is not enabled. However, tying the Lsp input to concat does the same thing. The debug worked fine with if-else instead of gate-number. But it gets even weirder.

On a whim, I tried tying Time input to 1st concat since it was working on 2nd concat…clear screen and nothing else happens. I tried deleting 1st concat & re-creating. Now If I clear all the static stings of 1st concat and have no wires to it, it runs “normal” – meaning it runs through each travel node in main (skipping the 1st one – or at least not printing to lcd if it is not skipping) with no pulse, then runs travel nodes with pulse. If I put static text for any of the inputs, it clears the screen, runs each travel node in main (skipping the 1st one) with no pulse, then repeats (board reset?).

So…besides the problem with lcd debug breaking things, why does it run through nodes on main patch without pulse before it starts the 1st deferred pulse after boot?

Hello!

Your logic makes sense. But when things converge to sharing a resource in XOD we have the well-known mess problems. Until we solve them completely, here are rules of thumb:

  1. Place a gate-* node right before each shared resource input
  2. If you want to set a value as a final action before leaving a state, place the if-else in addition to the gate, right before the gate
  3. Use 1-2-3 defer-pulse nodes on the road between state switches to give a chance for the gate and if-else to settle down.

In other words, you did everything correctly, but:

I’ve tried replacing the if-else with gate-number, but that failed to stop motors on exit.

You have to add if-else as an extra before the gate-number. Do not remove the gate-number completely.

I finally got it working. I had to switch pins I was using for left motor; original pin would not work once I activated servo. I assume this was due to timer conflicts between delay timers & PWM. I created a new servo-enable node using attach/detach code provided in another discussion for use in state-driven projects; just putting gate-number in front of servo was not sufficient. servo-enable does not need gate-number feeding it.

Side note: h-bridge was using pwm-output without attach/detach & seemed to work fine. I assumed it would also work for servo, but my test using it failed.

I also modified ultrasonic range node to return maxUs if echo failed instead of 0. I can still check for excessive return value, but don’t have to check for (>0 && <crash-distance) or assume that 0 is > 0.15 in my code.

hmmm…I guess as a new user I cannot upload my code…

Additional notes:

  • using lcd or watch nodes on main patch seems to work, but usually caused program to freeze on initialization if used on other patches (at least ones that get called multiple times)
  • I could not figure out how to simplify any further, but I’m still about 40 bytes of RAM short of being able to use lcd in final program. I was only able to use it in smaller test patches.
  • Program is for obstacle avoidance for differential drive robot with servo-mounted ultrasonic range finder. I’d love to share it to get suggestions for improvements and/or as a sample state-machine code…the traffic light example is a good start, but it is a huge jump to add lights for 2nd direction with no hints how to handle conflicts controlling a single pin from multiple nodes (I’m still not sure how I would do it…). Tips for reducing variable space usage especially appreciated.
1 Like

Thanks for sharing your thoughts. That’s valuable.

:thinking: That’s possible and I did not think about it.

:+1: good improvement. I wonder, maybe a +Infinity value (Numbers allow it) for such cases has better semantics.

That’s strange. Are you sure you switch back to the desired entry point patch before upload? Otherwise, you upload the currently opened patch, not main.

If that’s not a problem, you would help a lot if share an example project and the scenario to reproduce freeze.

Yep, the current version of transpiler produces memory-hogs. You fall out of SRAM limits pretty quickly. Fortunately, @awgrover has suggested an idea we were able to implement. So starting from 0.18.0 (upcoming until the end of the month) the RAM consumption should drop dramatically.

Thanks to all who created this project! I have a feeling it is going to salvage my robotics course that I am in the middle of teaching. A majority of the students could not control an LED with a button in the Arduino IDE on the mid-term after drilling it into them it would be on the test :-(. It has become very obvious that students with reading problems especially can NOT handle writing code; they just do not grasp the details needed (like spelling built-in functions correctly…).

In this case, MaxUs resulted in 4m & my device is lucky to see beyond 1m. While using lcd for debug, 4 fit much better than infinity would and has the same affect (but is more “random” than a really big number would be).

Yeah…the whole “entry point is current tab” was causing me problems for a while… I guess maybe that is another thing that should be added to the introductory tutorial.

Ironically, I just finished a traffic-light project that has LCD on multiple patches (I was way too lazy to wire up 9 LEDs…) and it works fine.

I don’t know if the xodball will include my changes for the ultrasonic library… All I did was set time variable to #define for MAX value where you now have “return <failure_value>”. I also changed it to return OK, but you could also emit value for all return values instead of only OK.

Hmmm…I just realized my project is basically the answer for any robotics class. Should I avoid posting the whole solution? I’m thinking at least posting code that shows using gate-number to feed PWM for motor and the servo-enable would be useful without giving everything away. I’d still like to share the entire project with at least some people to get feedback and maybe work out how much of it could be added to the site for a tutorial that goes the next step beyond the existing traffic-light example. Maybe it could be modified to perform a different goal so all the techniques could be demonstrated without just dumping the answer in student’s laps.

1 Like

If you would have something to say, we’ll be very happy to see it in XOD Magazine :clap: or in any other place.

Bah…I guess they would have to be looking pretty hard to find the code here anyway…

obstacle-avoidance.xodball (43.5 KB)

1 Like