SandBot Software Revamp

Having spent a bit of time on the hardware for my new SandBot design I decided I needed to revamp the software to bring it up to scratch. My main goals were as follows:

  • Make it easy to create and run geometric patterns
  • Find a simple way to provide a human interface to the SandBot
  • Ensure the software was reasonably robust and could run continuously for days

I’m really happy with the result, I’ve built software that hosts a website on the SandBot and that allows patterns to be created with simple trig. To have the SandBot produce the pattern just requires touching (or clicking) the required pattern on the home page. Patterns can also be edited (using the pencil icon) and new patterns created (using the +).

Shifting Sands

Defining a new pattern for the SandBot to draw is something I’ve put quite a bit of effort into. For instance the screen grab below shows how a spiral can be created using some simple calculations. If you recall that a circle can be described by sin() and cos() then it should be reasonably easy for me to explain how this creates a spiral …

New UI for the SandBot – Creating a Spiral

There are three sections on the form for creating a new (or editing an existing) pattern: Name, Setup expressions and Loop expressions. The Name is pretty obvious and just names the pattern.

The Setup expressions form a list where each expression is a simple formula and these are evaluated as soon as the user presses a button on the home page to start the formation of a pattern on the SandBot. For instance in the screen grab below there is one expression which is “t = 0”. So, unsurprisingly, when the user presses the “Spiral” on the home page: internally the software sets the value of something called “t” to zero.

X (first), Y (second) values for the position of the ball-bearing on the SandBot

The Loop expressions are more interesting. They are evaluated in what is called (in software) a “loop” – which basically means doing the same thing over and over again. The first time they are evaluated is just after the Setup expressions and they are responsible for telling the SandBot where to draw. On subsequent occasions they are evaluation when the SandBot is ready for more instructions about where to go next.  So, to continue the example, the value of “x” will be set by the first Loop expression and the value of “y” will be set by the second one. These two values for “x” and “y” are special as they tell the SandBot where to send the ball-bearing to next as shown on the diagram below. I’ll explain further what these particular lines do in the next section – along with the other two lines we haven’t talked about.

Spiraling In

The pattern we have defined above is, of course, a spiral. When the SandBot draws this shape it begins with the ball-bearing at the outer edge of the table and moves around the table clockwise in ever decreasing circles towards the centre. Let’s have a look why it does this…

We now know that the value of “t” is set initially to 0 and we can see from the third line in the Loop expressions that “t” is made a little bit bigger each time around the Loop. That’s what the expression t = t + 0.01 means, basically make t bigger (by 0.01 in this case). You could consider “t” to represent the time it has taken the SandBot to draw the spiral up to a certain point. So the first point of the spiral is at time 0 (like zero hour) and the next point is at time 0.01 – just a little bit later on.

Hopefully this makes the first two lines make a little more sense. When we draw a circle using sin() and cos() values we are basically working out where each point on the circle is and then moving round the circle a little and doing it again. The top of the circle corresponds to t = 0 and at this point x = 0 and y = the radius of the circle (which is 190mm for the this example – and a little bit in from the very edge of the sand table which has a radius of 200mm). A little time later t has moved on, lets say t = 0.1 in this case and the point calculated will be on the spiral that goes round clockwise from the previous point.

The final line of the Loop expressions is “stop = t==10”. Now this will take a little more explanation since it combines two ideas, the first being that there is a value called “stop” which has a special meaning to the SandBot. Whenever “stop” has a value which is not zero the SandBot stops drawing. The other idea in the line “stop = t==10” is the use of the == sign to mean “test whether something has a particular value and give me a zero if it doesn’t and something other than zero if it does”. So we’re testing to see if “t” is exactly equal to 10. If “t” isn’t equal to 10 then stop will get the value zero. But if “t” is 10 then “stop” will get a value that isn’t zero (it doesn’t matter what that value is – it just matters that it isn’t zero) and the robot will stop drawing.

Continuous Motion

Another section in the user interface is the Sequences section. This looks just like Patterns on the front page and you can start a sequence, edit it and create a new one in just the same way as for patterns.  The idea of sequences, however, is that you list a set of patterns and the SandBot generates each in turn and then returns to the start, so you can run indefinitely with constantly shifting sands.

Expression Evaluation

Perhaps the most interesting thing in the software is the expression evaluator – i.e. the piece of code that actually computes the value of expressions like “y = 190 * cos(t)”. if you are writing software using a compiler (as most software of this kind is written) then you can include computations like sin() and cos() at compile-time but you can’t easily string them together in formula at run-time. So a piece of code called an expression evaluator is needed. The job is generally split into two phases “parse” and “evaluate”. The “parse” phase involves running through the formula and detecting variables (things like y and t in the example above), functions (cos in this example), constants (190) and operators (the * and =). These are split into a tree structure so that it is quick to move from one part of the expression to the next and the structure of the expression is maintained.

I used a third-party expression evaluator called tinyexpr which does the parsing (its called compile in tinyexpr) job well and is written for microcontrollers with small amounts of memory. However, I needed to extend it a little to add the ability to define variables and evaluate boolean values with operators like ==. My code is in the PatternEvaluator.h file and the section which parses (compiles) an expression and stores the elements is shown below.

And here’s where an expression is evaluated:

The Sand UI Software

I mentioned at the start that the SandBot creates a web server and that the page used to control the SandBot is generated by that server. This means that the SandBot must be on your WiFi network in order to work and I’ll explain how that can be done later on. But first let’s have a look at the HTML file that creates the web pages we’ve seen above.

Since the whole visible page is generated in javascript the body section of the HTML is absolutely minimal:

Even the buttons are generated from SVG code and this allows the page to be contained in a single HTML file which reduces the burden on the web server.

In keeping with all web pages there is no state stored in the page itself. So when the page is first shown it goes back to the server and uses a REST API “/getsettings” to access the current state of the robot.

And the information requested is returned in JSON.

Particle vs Espressif

Particle Photon (left) and Adafruit Huzzah 32 (right)

Now one of the things that I haven’t explained so far is that I have two versions of the firmware for the SandBot. My original firmware – which still works fine – is based on the Particle Photon which is a small microcontroller board based on an ARM Cortex M3 with WiFi + 1Mb flash and 128K RAM. The newer version is based on the Adafruit Huzzah32 based on a module called Espressif ESPWROOM32 which is also a small (though somewhat bigger as you can see in the photo) microcontroller board with WiFi but this time based on a processor from chinese company Espressif and with a larger flash (4Mb), a lot more RAM (520KB) and dual cores.

The main reason for wanting to re-do the firmware was to enlarge the number of patterns that can be stored on the device and also because I had had some issues with WiFi stability although this now appears to have been due to my own WiFi setup at home.

The two versions are in the software repository in the folders “ParticleSw” and “PlatformIO” and they share the same code for their WebUI.

Code Structure

In the reorganization of code that I did in working on the ESP32 version I moved a lot of code into libraries. This included the WiFi manager and REST API management as well as code to handle common tasks such as JSON parsing and debug logging. In addition the ESP32 version relies on a very good third party which provides an asynchronous web server on ESP32.

The code to run the robot itself is based around the idea of a workflow and a pipeline – each being a queue but at different levels. So the workflow works at the level of a command and may include GCODE statements that directly request movement of the robot arm to a specific X,Y position. The purpose of the workflow queue is to allow lots of these commands to sit waiting to be actioned so that there is always a command ready to perform next and the robot doesn’t “stutter” between movements. Each command is then broken down into smaller movements to ensure that motion isn’t “jerky”. In the SandBot the pipeline deals with individual movements of 1mm each. By splitting any motion into such small segments the geometry of the robot (which is intrinsically circular) doesn’t corrupt the linear motion that is expected when the robot is instructed to move from one X,Y point to another.

Planning Motion

When motion is needed between two points it is handled by the MotionPlanner. Its job is to ensure smooth transitions from acceleration, through continual motion at (up to) a maximum speed and finally into deceleration as needed. To do this the motion planner uses a look-ahead and look-back model to set the optimum profile of motion across different blocks in the pipeline.

Consider what happens when the robot is stationary and then ten blocks are added to the pipeline which all demand motion that is in a straight line (or a gentle curve). In this case the robot needs to start accelerating while it is processing the first few blocks (as each block is only 1mm long it will not get up to maximum speed for about 5 blocks) and then level off the speed when it reaches the maximum desired. It then needs to look ahead to see if more blocks have been added to the pipeline and if the straight line (or gentle curve) is continuing or if a more abrupt change of direction (or hard stop) is required. In each of these cases the MotionPlanner needs to take the appropriate action: either continuing at a constant speed or decelerating to enable a change of direction (or stop).

Code to perform this task is commonly found in 3D printers (e.g. Marlin firmware for Arduino) and CNC machines (e.g. GRBL). I could have used the code from these places but instead I decided to build my own planner with the idea that I would split the code into suitable sections so that driving a more capable stepper motor controller (like the TMC5072 which has its own motion controller built in). It was quite an interesting challenge to build a capable MotionPlanner and I think I’ve found a few ways to improve on the designs in the Marlin and GRBL versions – albeit at higher cost in instruction time as my calculations are more complicated – but this doesn’t really matter as the ESP32 is a much more capable processor than the 8 bit designs running most 3D printers.

Getting the software onto the Bot

The procedure for getting the SandBot software onto the SandBot microcontroller is different in each case (Photon or Huzzah32).

In the Photon case the easiest way I have found is to download the Particle Dev (desktop IDE) and use it to open the ParticleSw folder from my github repository. Connect the Photon with a micro USB cable and the use the “lightning strike” button in the Particle Dev UI to flash the firmware into the Photon – see the Flashing device section of this document.

In the Huzzah32 case I have found PlatformIO to be the best way to get going. Follow the instructions here – I use Microsoft VS Code – and once PlatformIO is set up you can add the Arduino extension (click the circled button in the image below).

Arduino Extension in PlatformIO

Now, in Visual Studio Code, open the project folder which is called PlatformIO in the github repository.  The board and library requirements are described in the platformio.ini file which is in the root of the PlatformIO folder in the github repository so they should be set automatically without you having to make changes.

Finally you will need to program the Huzza

h32 using the forward-facing arrow in the toolbar at the bottom of the PlatformIO screen. One thing to watch out for is that I sometimes hard-code the upload_port setting in the platformio.ini file. If this is set and you only have one serial device connected then comment this line out – otherwise change the port to the one you need.

In either case you can use the following details to check that the firmware is loaded correctly.

Getting on the Net

Once the SandBot is connected to your WiFi network you can use the web UI as described above and all the functions of the SandBot are available through that UI. However, I haven’t yet described how to connect the SandBot to WiFi or how to find the web address where you can access the UI once you are on.

Getting SandBot onto your WiFi network is most easily done through the USB connection on the Particle Photon or Adafruit Huzzah32 boards. In the case of the Photon you may already have got onto the WiFi network using the “getting started” procedure recommended by Particle and in that case all you need to do is find the IP address as described below.

In either case:

  • Connect a normal micro-USB cable to the USB connector on the Photon or Huzzah
  • Download a “terminal emulator” software – my favourite is TeraTerm
  • Install the terminal emulator and run
  • Open the Serial Port Setup in the terminal emulator and select a port (the one the Photon or Huzzah is connected to) and baud-rate of 115200

At this point you should see information coming from the SandBot as shown below. If you don’t then it would be a good idea to ensure that you have programmed the flash memory of the device correctly.

SandBot with no WiFi connection

The screen grab shows the situation where the SandBot has no current WiFi connection – you can tell this is the IP section of the listing shows 0.0.0.0 as it does in the image above shown circled in red.  If you do see an IP address listed that is not 0.0.0.0 then you can ignore the remainder of this section if you want to – however the section does explain how to give a name to your SandBot and, in the case of browsers like Chrome, this can allow you to refer to your SandBot by a name you give it rather than the IP address when you type it into your browser’s address bar.

To give your SandBot an IP address you use a command which you type into the terminal emulator. Note that while you are typing the command the normal logging of debugging information continues so it can be a bit tricky to see what you have typed. However, it will be interpreted correctly if you get it right and you can just try again if it doesn’t work. So enter the following command and press enter afterwards:

Replacing:

  • SSID with the name of your WiFi network (mine is rdint01 as you will see in a screen grab below)
  • PASSWORD with your WiFi password
  • HOSTNAME with the name you want your sandbot to be called

You should see something like the following:

Setting WiFi on SandBot

The command I typed starts on the fourth line and I used “mypassword” for the password – which of course isn’t my password but you get the idea. The debugging line interjected before I’d finished typing so the name I typed for the HOSTNAME which was SandBot appears on the following line. Assuming you actually did enter your SSID and password correctly you should see:

WiFi Connected

The IP address that has been assigned to the SandBot (192.168.86.58) is shown circled in red.

Getting to the UI

The information shown in the screen grab above includes the IP address of the SandBot (circled in red) and that is all you need to connect to it and see the web UI. In a browser such as Chrome enter the IP address in the following form:

Replacing 192.168.86.58 with whatever the IP address of your SandBot is. You should be greeted with the web UI and you are good to go.

SandBot Web UI

Smooth Sand Art

One of my main concerns when creating the SandBot was to ensure that it was quiet and that the motion was very smooth. In order to achieve this I’ve used Trinamic SilentStepStick stepper motor controllers on my PCB.

Stepper PCB Showing Adapter for ESP32

Stepper PCB with ESP32

Also, in order to avoid creating a special PCB for the ESP32 version I’ve designed a board to convert from Particle to Huzzah pinouts. This is available on EasyEDA here: https://easyeda.com/robdobsn/Huzzah32ToParticle

Adapter PCB to convert to Huzzah32 from Particle Photon

Resources

And the main PCB is here: https://easyeda.com/robdobsn/Pi_Stepper_Hat-iZzxFXf9q

And finally the software is here: https://github.com/robdobsn/RBotFirmware

robSandBot Software Revamp

Comments 19

  1. Dave B

    Are there specific stepper drivers that should be used (2208, 2130, etc)? I noticed reference to the 2130 on some of your other blogs, so I’m guessing that is the one used, but it appears there are a few different versions of those…just want to be sure I don’t buy something that doesn’t work with this.

    Thanks!

    1. Deon Gerber

      Hi
      To answer your qeustion……..should you use Robs pcb design then yes you should use the same as what he used or something with the same foot print at least. Just make sure the pin assignments is the same. On the other hand the software works with any stepper driver. In my case I made a big 1.2 meter table and use hybrid closed loop steppers and all works fine. Hope it helps. Happy building.
      Deon.

  2. Pingback: Introducing the Stepper Hat Trio | robdobson.com

  3. Michael

    Hi Rob,

    I’ve got the latest version installed and my sand table robot doesn’t stay idle after it completes a pattern. There is a slight noise going on with the motors and they very, very slow are turning. I’m not sure what could be causing this. I’ve tried two different versions of motor drivers and if I use some basic arduino stepper motor code to spin the motors, the motor’s will stop. Anything you can suggest to check or how to work out what’s going on?

    Thanks
    Michael

    1. Post
      Author
      rob

      Hi Michael,

      Did you manage to get this sorted out? Are you using stepper motor drivers like the Pololu ones or different ones?

      Let me know and I’ll try to help.

      Regards

      Rob

  4. Chris SH

    Hi Rob,
    do you still have some of the PCBs available? I can´t find your PCB on EasyEDA by using the links your provided.
    I will use the huzzah32 to set up my Sandbot.

    Thanks in advance
    Chris

    1. Post
      Author
  5. Pingback: Shred Your Own Banksy [Maker Update #98] • Maker Project LabMaker Project Lab

  6. Deon

    Hi again

    small steps at a time. I figured out last night, if you go to github directly to clone the repository by downloading the zip file you dont get the complete project.
    If you use VSCode to clone the repository you get a extra folder called Libs with all Robs private librarys inside. A small issue here its called Libs with a s. VSCode is looking for a folder called Lib without the s. The building of the code went much better……….still somthing wrong but it got late so I will give it a go again tonight when I get home.

    Thanks again for your work Rob.

    1. Matt G

      I think I’m lost here.. I’m trying to compile the platform IO code, but keep getting the error:

      src\AxisParams.h:6:20: fatal error: RdJson.h: No such file or directory

      I don’t see that file anywhere, and assume that’s one of Rob’s files. I tried cloning in and out of VS Code.

      1. Post
        Author
        rob

        Hi Matt

        Sorry, I realised that the files you were missing were not in the repository. So I’ve fixed that.

        You should be able to do “git pull” in the base folder and get the new files.

        Let me know how you get on

        Rob

        1. Matt G

          That worked!

          N: WiFiManager: WiFi not connected – WiFi.begin with SSID [My SSID]
          N: WiFiManager: GotIP 192.168.1.170
          N: WiFiManager: mDNS responder started with hostname sandbot
          N: WebServer: begun
          N: 130025 sandbot SSID [My SSID] IP 192.168.1.170 Heap 189560 Avg 40.65uS Max 49800uS Min 36uS Slowest Robot 2068, Web 1096

          When I navigate to the page I see “undefiined” on your webUI background. I don’t have the board connected to the bot – still waiting on the PCBs. Does it need to be connected to everything for the webUI to work?

  7. Deon

    Hi again

    OK small steps at a time. I figured out last night, if you go to github directly to clone the repository by downloading the zip file you dont get the complete project.
    If you use VSCode to clone the repository you get a extra folder called Libs with all Robs private librarys inside. A small issue here its called Libs with a s. VSCode is looking for a folder called Lib without the s. The building of the code went much better……….still somthing wrong but it got late so I will give it a go again tonight when I get home.

    Thanks again for your work Rob.

  8. Deon

    Forgot to ask……….LED d7…..

    Are there a reason that it flashes sometimes and other times it is off and sometimes its one fulltime.
    Is this some sort of message?

  9. Deon

    Hi Rob

    Re-flashed the photon with old firmware and yeahhhh I have movement.

    But my sandtable thinks its a mugbot. Ha ha ha. The Page header displays Mugbot and I get some sort of a cnc interface as a UI.

    I do still get a error in the developer tools network tab on Chrome.

    VM52:1 Uncaught SyntaxError: Unexpected end of JSON input
    at JSON.parse ()
    at settingsCallback ((index):14)
    at XMLHttpRequest.n.onreadystatechange ((index):14)
    settingsCallback @ (index):14
    n.onreadystatechange @ (index):14
    XMLHttpRequest.send (async)
    callAjax @ (index):14
    robotTypesCallback @ (index):14
    n.onreadystatechange @ (index):14
    XMLHttpRequest.send (async)
    callAjax @ (index):14
    bodyIsLoaded @ (index):14
    onload @ (index):21

    This time I am getting these first three lines.
    IP Address status 200
    GetRobotTypes status 200
    getsettings status 200

    Busy trying to get all the librarys in place to try the new firmware.

    One last question …..Are there any settings inside the code that needs to be set like Steps/Rot , micro stepping vs full steps, Speed or acell etc.

  10. Deon

    HI Rob

    Thanks for going to such extreme to try and help…………….but…………
    Still battling.
    I am advancing in small steps though.
    this is the error I am getting now.
    “Uncaught SyntaxError: Unexpected end of JSON input
    at JSON.parse ()
    at sandTableInfoCallback ((index):127)
    at XMLHttpRequest.xmlhttp.onreadystatechange ((index):90)
    sandTableInfoCallback @ (index):127
    xmlhttp.onreadystatechange @ (index):90
    XMLHttpRequest.send (async)
    callAjax @ (index):100
    updateDisplay @ (index):492
    bodyIsLoaded @ (index):81
    onload @ (index):681”

    I now get two lines in the network tab of the debugger.
    They are my IP adress and Getsetting both showing status 200.

    To be honest I have not loaded the newest firmware where the platformIO ‘s code is included.Still trying to get it to compile.
    Dont know if that will be the cause though.
    Should you be using a photon the IP adress can also be found in the Particle App on android.
    just be carefull it shows 2 IP address’s . One like 41.13.250.129 under the info tab and then on the Data tab you will find the one to use..192.158.34.92.

    Something maybe worth mentioning are that on the events tab you get a active message every 30 seconds where your ID ,IP and then Low Ram 64280 and the date and time displays………..
    Do I have to be concerned about the LOW RAM part……….

    Thought about chucking the photon and getting a adafruit but that will only arive in about 6-8 weeks……no local stock. Blahhhh.

    Thanks for taking the time to read my rambling…..

    Deon

  11. Deon Gerber

    Hi Rob

    Tested and done as you described. However I do get 1 error mesage. “Failed to load file:///c:/getsettings:Cross origin requests are only supported for protcol schemes:http, data, chrome, chrome-extension, https.
    Error shown comes from line100 in the code. “xmlhttp.send ();”

    Does this help

    Thanks

    1. Post
      Author
      rob

      Hi Deon

      I’ve added a couple of extra sections in the description above to help you with this. You need to access the Web UI through the IP address of the Photon rather than from a folder on your computer. The cross-origin request (CORS) problem you are having is because a security feature is getting in the way of proper operation. So if you can find the IP address of your SandBot, simply type http://your-ip-address into the browser and you should see more positive results.

      Regards

      Rob

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.