-
Notifications
You must be signed in to change notification settings - Fork 23
FabMo Developers Guide
FabMo is a system of firmware, software, and cloud components that bring an apps ecosystem to the world of CNC machining. The advantage of a FabMo capable tool is the ability for that tool to run apps. FabMo apps are much like apps for your PC, phone, or tablet. They are custom software applications, usually specialized in performing one specific type of task. In the case of the FabMo environment, these apps are usually designed to take design inputs, and transform them into physical objects using the FabMo API to communicate with a CNC tool. In this document we will:
- Introduce the FabMo environment and its parts
- Explain the installation and configuration of the current state-of-the-art FabMo implementation
- Develop a simple App
The FabMo Core The FabMo core is the real-time firmware at the heart of the motion control portion of FabMo. It is the software component that is closest to the hardware, and is responsible for accepting commands from the computer running the FabMo Engine, and turning those commands into motion of a CNC tool.
The FabMo Engine The FabMo Engine is a software service that runs on a computer that is connected to a CNC tool. Ideally, this computer is a single-board computer that is built into the tool itself, much like a Raspberry Pi, a BeagleBone or similar. The purpose of this service is to communicate with the hardware motion system running the FabMo Core, to publish the FabMo API, and to host the FabMo Dashboard.
The FabMo API The FabMo API is a web API for communicating with a FabMo capable tool. The FabMo API provides a means of monitoring and controlling the tool directly as well as access to higher level functions such as the exchange of CNC data, management of Job queues, and access to apps and configuration data.
FabMo Apps FabMo apps are single purpose software applications designed to run within the FabMo environment. Apps are written in the language of the web, and are really just a collection of html and javascript files that are specially packaged, and designed to be hosted within the FabMo environment. FabMo apps are client side web applications. They live in the browser, and communicate back to the tool using the FabMo JSON API.
To get started with FabMo, you need to run the FabMo Engine. The steps in the following tutorial assume the following:
- That you have a FabMo compatible core device, running G2 firmware, such as an Arduino Due with a ShopBot Shield, or a Synthetos V9
- That you are installing the engine on a Linux/Mac/Windows PC
When you have satisfied the prerequisites, follow the steps below:
Step 1: Install node.js If you using a linux operating system, you may wish to do this through your package manager or using homebrew on the mac. On windows, head over to http://nodejs.org and follow the installation instructions for your platform.
Step 2: Checkout the FabMo Engine source code Use your favorite git client to checkout the FabMo-Engine repository: https://github.com/ShopBotTools/FabMo-Engine.git If you are new to git or to github, checkout the online help at github: https://help.github.com/
Step 2a: Make sure there's a place for the engine to store its files The engine needs a directory to store things like configuration information, temporary files, and app archives. On linux/macos this is in /opt/fabmo. On windows, it's C:\opt\fabmo. Make sure this directory exists and that the user running the FabMo Engine has write access to it.
Step 3: Install the engine dependencies Like any node.js application, the FabMo Engine relies on a number of packages to run. To get these packages, simply run the following command:
npm installFrom within the FabMo-Engine directory you just checked out. This will download, build, and install all of the required packages to run the FabMo Engine.
Step 4: Make sure the core is hooked up
Now is the time to make sure the FabMo compatible core device is hooked up. Plug the arduino, V9 or v300 board into the host PC via USB and make sure it is powered on. On linux/mac/windows make sure the device turns up as /dev/ttyACMx, /dev/cu.usbmodemx, or COM1 respectively.
Step 5: Run the engine for the first time! To run the engine, simply execute the following command from the FabMo-Engine directory:
npm startThis should provoke a flurry of log activity in the console, as shown below:
If your output does not look similar, you may yet be missing some dependencies. Go back to step 3, and observe the console output for the install process to see if any dependencies fail in their installation.
Step 6: Tweak the engine configuration The default configuration of the engine is fine in most cases, but on occasion, some adjustment needs to be made. This is most common in the selection of the COM or serial port used by the engine. The engine configuration lives in /opt/fabmo/config/engine.json (or c:\opt\fabmo\config\engine.json on windows) - If your engine is having difficulty connecting to the core.
Step 7: Visit the dashboard Once the engine is running, you can visit the FabMo dashboard on your local machine in a browser. Using chrome or firefox, navigate to http://localhost:9876/ or http://0.0.0.0:9876/ on some machines. If you changed the hosted port in your engine.json, substitute it here. You should see the dashboard as shown below:

Congratulations! You have entered the world of FabMo.
The FabMo Dashboard is the "home screen" for all tool operation. Outside of any external CAD/CAM workflow you might be using, this is where you'll operate your tool. The home screen shows the apps that are installed. On the left side are the major application options and built-in apps. On the right side is the DRO (digital readout) which gives an indication of tool position, and direct control over the tool with the keyboard and mouse. Either control pane can be collapsed to make more room for apps. (The DRO is collapsed by default)

The DRO (digtal readout) is located on the right hand side, and provides access to manual tool functions. When the DRO is visible, you can drive the tool manually by clicking on the arrows, or using the keyboard arrow keys to move the tool in the X, Y and Z directions. Control of the tool using the physical keyboard is still experimental, and may not behave predictably at all times. In addition to the manual tool controls, there are buttons to zero out each of the axes, and indicators of each of the axes current positions.

The job queue screen shows the job queue for the tool, as well as the job history, and the progress of the current job. The parts of the Job Queue screen are indicated below:

Usually, jobs enter the queue as the result of running an app, but CNC data (G-code or OpenSBP files) can be also added to the queue manually by browsing for the file using the job queue screen. This allows us to use our traditional CAD/CAM workflow as it suits us.
Apps are launched from the app home screen (accessible from the menu on the left hand side) Just like your phone or tablet's native apps, apps are activated by clicking on them. When an app is running you still have access to the dashboards major functions, such as the left hand menu and the DRO, but individual apps have the ability to restrict access to some of these features for various reasons.
Apps can range in functionality from a simple hole cutter to a full-featured CAD/CAM workflow. To illustrate the app workflow, we will use the table surfacer, which is a simple app that is designed to surface a specified area. To use the table surfacer app, follow the steps below:
Step 1: Click the Table Surfacer app icon on the app home screen. It should take you to the app, which looks like this:

Step 2: Fill in your surfacing parameters. For the sake of demonstration, you may wish to choose a size that is small so that surfacing doesn't take too long.
Step 3: Click the RESURFACE TABLE button
After step 3, you should be taken to the Job queue manager automatically, and you will notice that the queue now contains a single job (assuming you had no jobs pending already) The new job is the result of the surfacing operation we just described, and it indicates so in its title and description.

Step 4: Click the "Play" button in the job queue manager. Careful! Once you press the play button, the current job advances and is run by the tool. When the tool is running, new controls will appear to allow you to pause/stop the job, and to provide progress information. When the tool is finished, the active job will be removed, and will appear in the job history.
This is the complete app workflow, from launching an app, to filling in parameters, to performing the machining task. In the following section, we will learn how to develop an app of our own.
As mentioned in above, a FabMo “app” is simply a collection of html and javascript files, which are bundled with a manifest that describes the application. In this section, we will create a new app and add it to our FabMo dashboard.
To get started, unpack the example_app.zip file to a local directory and examine its contents. Inside you will find:
index.html - this is the main page for the app, which will be the page seen when the app is launched. package.json - The manifest that describes the app, it’s author, source, etc. js - A folder containing the javascript dependencies for the app, notably the dashboard.js file that allows our app to communicate with the dashboard. icon.png - An app icon. This is the icon that will appear on the dashboard when the app is installed
The app we’re going to develop cuts a square. This is not a terribly useful application, but serves at least to illustrate the finer points of app development, and should provide a good starting point for more complex projects.
Editing the Manifest The first thing to do with our new app is edit package.json, which is the manifest that describes the app. We want to give our app a name and an author, and make sure we’ve specified any other configuration information for the app. The contents of the package.json file are listed below:
{
"name":"Example App",
"main":"./index.html",
"icon":"icon.png",
"icon_color":"black",
"version":"0.0.1",
"author":"John Woodcutter",
"target":[],
"website":"http://www.example.com/"
}The important parameters above are the name, the index file, and the icon file. The index file we can safely leave alone, but the name and icon file we'll want to change to reflect the name and icon we want for our App. We’ll also want to specify our own information for the author and website.
{
"name”:”Square Cutter",
"main":"./index.html",
"icon":"icon.png",
"icon_color":"black",
"version":"0.0.1",
"author”:”Ryan Sturmer",
"target":[],
"website":"http://www.ryansturmer.com/"
}The Index Page Currently, app development is extremely open ended, and the user interface can really take any form you like. For the purpose of instruction, the app we develop in this example will not be complex or highly styled. We leave that as an exercise for the reader. In the future, an app style library may be provided so that a consistent look and feel can be maintained across app, though, at the time of this writing no such library exists.
index.html looks much like the start of any other web application. In the case of our FabMo app, we are going to add some inputs to accept user parameters, and call a function to pass the result of our parametric design to the tool to be machined. Starting with the example, our app looks like this:
<html>
<head>
<title>App Title</title>
</head>
<body>
<div class="header">App Title</div>
<div class="description">App Description</div>
<button id="run-button">RUN</button>
</body>
<script src="./js/jquery.js"></script>
<script src="./js/dashboard.js"></script>
<script type="text/javascript">
$('#run-button').click(function(evt) {
program = ''
fabmoDashboard.submitJob(program, {
'name' : 'Job Name',
'description' : 'Job Description',
'filename' : 'job.nc'
});
});
</script>
</html>Accepting User Input For our square cutter, we’re going to want to accept some user inputs such as the origin of our square, and its size. We will realize these as simple text boxes, but a more complex app might include graphical input, accept information from a local file, or pull data from a source on the web, to name a few examples. To add the user inputs, create a form with some labeled text boxes:
<form>
<p>Origin: X<input type="text" id="input-xorigin" value="0">
Y<input type="text" id="input-yorigin" value="0"></p>
<p>Size: X<input type="text" id="input-xsize" value="24">
Y<input type="text" id="input-ysize" value="18"></p>
<p>Plunge:<input type="text" id="input-plunge" value="-0.5"></p>
<p>Safe Z Pullup:<input type="text" id="input-safez" value="-0.5"></p>
</form>Computing a Toolpath The manifold techniques of toolpath generation are well outside the scope of this tutorial. For the sake of illustrating how an app works, the toolpath generation we will use is very simple. To cut our square, we will:
Pull the cutter up to the safe Z height Turn on the spindle Jog to the origin of our square Plunge to the specified depth Cut the four sides of our square Return to the save Z height Turn off the spindle Return to 0,0
The toolpath will be computed when the user clicks the RUN button that was provided with the example app. We use jquery to bind a handler to the button, which will be executed when the user clicks on it. This handler has already been created, and lives in the script at the bottom of the example:
$('#run-button').click(function(evt) {
program = ''
fabmoDashboard.submitJob(program, {
'name' : 'Job Name',
'description' : 'Job Description',
'filename' : 'job.nc'
});
});For now, ignore the submitJob call, which is what will ultimately send our G-code program to the tool. Instead let’s write some code that will create the G-code program that we intend to cut:
xsize = parseFloat($('#input-xsize').val())
ysize = parseFloat($('#input-ysize').val())
xorigin = parseFloat($('#input-xorigin').val())
yorigin = parseFloat($('#input-yorigin').val())
plunge = parseFloat($('#input-plunge').val())
safez = parseFloat($('#input-safez').val())
feedrate = parseFloat($('#input-feedrate').val())*60.0
var program = [
'G17 (XY Plane)',
'G0 Z' + safez + ' (Pullup to safe Z height)',
'M4 (Spindle On)',
'G0 X' + xorigin + ' Y' + yorigin + ' (Move to origin of square)',
'G1 Z' + plunge + ' F' + feedrate + ' (Plunge)',
'G1 X' + (xorigin+xsize) + ' F' + feedrate,
'G1 Y' + (yorigin+ysize) + ' F' + feedrate,
'G1 X' + (xorigin) + ' F' + feedrate,
'G1 Y' + (yorigin) + ' F' + feedrate,
'G0 Z' + safez + ' (Pullup to safe Z height)',
'M5 (Spindle Off)',
'G0 X0 Y0 (Return to origin)'
]
program = '\n'.join(program);Here again we are using jquery (our only dependency) to extract the values of the user inputs. We parse them as floats (so that we can do arithmetic on them) and then use them to generate a list of G-code blocks (lines) - The particulars of G-Code generation are outside the scope of this tutorial, but it’s pretty clear what’s going on here. Thus specified, the g-codes are then joined into a single string separated by newlines (‘\n’) We now have CNC data ready to be cut!
dashboard.js and the fabmoDashboard object What we’ve swept under the rug until now is how our CNC data actually gets to the tool. Since FabMo apps are hosted by the dashboard, they have access to dashboard functionality, such as the ability to submit jobs, show the DRO, etc. These functions are exposed in dashboard.js (included in the app example) through the fabmoDashboard object. The fabmoDashboard object is a global defined by dashboard.js and it provides methods for interacting with the dashboard that is hosting the app. For our purpose, it contains one useful method: submitJob(program, options):
fabmoDashboard.submitJob(program, {
'name' : 'Job Name',
'description' : 'Job Description',
'filename' : 'job.nc'
});when submitJob is called, it passes the program data and options to the dashboard, which in turns communicates it to the tool using the FabMo API. The dashboard then closes the app and takes the user directly to the Job manager where the new job is waiting in the queue. This is sort of the equivalent to hitting the “print” button. Now in the job manager, the user can click the play button (as we did above) to begin machining their file.
Note that in the options that we pass to submitJob, there are fields that describe the data we’re passing in. This will provide a name and description to display in the job manager, and will enhance the searchability of jobs in the future. The name and description should accurately describe the job, giving parametric details where possible. Although for our square cutting application, the above call would work, a better configuration would be as follows:
fabmoDashboard.submitJob(program, {
'name' : 'Square Cut',
'description' : 'Cut a ' + xsize + 'x' + ysize + ' square at location (' + xorigin + ',' + yorigin ')',
'filename' : 'square.nc'
});We have revised the name, description and filename to include a better representation of our CNC data. This improves the experience for the user, who may wish to re-run a previously submitted job, and can use this information for reference.
<html>
<head>
<title>Square Cutter</title>
</head>
<body>
<div class="header">Square Cutter</div>
<div class="description">Cuts a very simple square.</div>
<form>
<p>Origin: X<input type="text" id="input-xorigin" value="0">
Y<input type="text" id="input-yorigin" value="0"></p>
<p>Size: X<input type="text" id="input-xsize" value="24">
Y<input type="text" id="input-ysize" value="18"></p>
<p>Plunge:<input type="text" id="input-plunge" value="-0.5"></p>
<p>Safe Z Pullup:<input type="text" id="input-safez" value="-0.5"></p>
<p>Feedrate:<input type="text" id="input-feedrate" value="3.0"> inches/sec </p>
</form>
<button id="run-button">RUN</button>
</body>
<script src="./js/jquery.js"></script>
<script src="./js/dashboard.js"></script>
<script type="text/javascript">
$('#run-button').click(function(evt) {
xsize = parseFloat($('#input-xsize').val())
ysize = parseFloat($('#input-ysize').val())
xorigin = parseFloat($('#input-xorigin').val())
yorigin = parseFloat($('#input-yorigin').val())
plunge = parseFloat($('#input-plunge').val())
safez = parseFloat($('#input-safez').val())
feedrate = parseFloat($('#input-feedrate').val())*60.0
var program = [
'G17 (XY Plane)',
'G0 Z' + safez + ' (Pullup to safe Z height)',
'M4 (Spindle On)',
'G0 X' + xorigin + ' Y' + yorigin + ' (Move to origin of square)',
'G1 Z' + plunge + ' F' + feedrate + ' (Plunge)',
'G1 X' + (xorigin+xsize) + ' F' + feedrate,
'G1 Y' + (yorigin+ysize) + ' F' + feedrate,
'G1 X' + (xorigin) + ' F' + feedrate,
'G1 Y' + (yorigin) + ' F' + feedrate,
'G0 Z' + safez + ' (Pullup to safe Z height)',
'M5 (Spindle Off)',
'G0 X0 Y0 (Return to origin)'
]
program = '\n'.join(program);
fabmoDashboard.submitJob(program, {
'name' : 'Square Cut',
'description' : 'Cut a ' + xsize + 'x' + ysize + ' square at location (' + xorigin + ',' + yorigin ')',
'filename' : 'square.nc'
});
});
</script>
</html>