Friday, 25 April 2014

Using OpenSCAD to design a basic LCD enclosure

Regular readers will be aware I am a big fan of using scripted CAD, specifically OpenSCAD, as a design tool. I have gone into my reasoning before, which I won't repeat now. This is a further worked example showing the steps I took to design a case for a basic LCD+Click encoder controller for a 3d printer. This posts will try not to repeat too much ground covered in my previous OpenSCAD "How To": the OpenSCAD manual will help following along.

As always this is Open Source Hardware so the OpenSCAD source and supporting control knob file is shared on GitHub.


The electronics to encase


The PanelOne is a simple back board for a 20x4 character LCD with a encoder, a SD card board and brightness and contrast pots. I will go into the rationale and design of it in another post.



The aim for the case is to be quick and easy to print and use the the minimum of additional screws and other fixings.

Step 1 - Measurements


First step is to take measurements of the dimensions of the electronics - these can be taken from the CAD files if you have them:


This shows using the dimension function in KiCAD, although you can read the co-ordinates directly. The other, and my preferred, option is to take direct measurements:


This allows for the effect of the assembly processes to be taken into account easily.

Step 2 - Model the Electronics


Depending on how complex a case you are making, this step can be very simple or very complex. For a great example of how complex a circuit model model can be, check out UrielGuy's model of the Sanguinololu electronics




In this case I am going to keep it simple.

Start by assigning the measurements to variables - you will thank yourself many times over as you come to reuse or modify these.:

clearance=0.8;
wall_width=1.6; //minimum wall width //should be a multiple of your extruded dia
layer_height=0.2;

//LCD screen
lcd_scrn_x=99;
lcd_scrn_y=40.5;
lcd_scrn_z=9.4;

lcd_board_x=99;
lcd_board_y=61;
lcd_board_z=1.6; //does not include metal tabs on base

lcd_hole_d=3.4;
lcd_hole_offset=(lcd_hole_d/2)+1;

//board edge to center of first connector hole
lcd_connect_x=10.2;
lcd_connect_y=58.4;

//PanelOne circuit board
pl_x=136;
pl_y=lcd_board_y;
pl_z=4; //excluding click Encoder and SD card and cable headers, but including the soldered bottoms of the through hole connectors
pl_mounting_hole_dia=3.4;
pl_mounting_hole_x=133.6;
pl_mounting_hole1_y=3.4; //only bothering with 2 holes at this point
pl_mounting_hole2_y=58.4;

//rotary encoder
click_encoder_x=13.2;
click_encoder_y=12.6;
click_encoder_z=6;
click_encoder_shaft_dia=6.9+clearance;
click_encoder_shaft_h=12.2;
click_encoder_knob_dia=24;
click_encoder_offset_x=112.2;
click_encoder_offset_y=30.8;


//contrast and brightness holes
cb_dia=4; //hole diameter for adjustment screw
cb_h=15;
con_offset_x=107.2;
con_offset_y=16.1;
con_offset_z=pl_z;
bri_offset_x=117.1;
bri_offset_y=16.0;
bri_offset_z=con_offset_z;

//headers
//lcd connection header
lcd_h_x=(16*2.54)+2.54;
lcd_h_y=2.54;
lcd_h_z=3; //this is the gap between the circuit board caused by the plastic spaces on 2.54mm headers
lcd_h_offset_x=lcd_connect_x;
lcd_h_offset_y=lcd_connect_y;
lcd_h_offset_z=pl_z;

//IDC headers, use the clearance required for the plug
//these are much bigger on z than the actual headers for clearance
idc_h_x=16; //not all will be within case
idc_h_y=14+clearance;
idc_h_z=pl_z+click_encoder_z;
idc1_offset_x=128.4;
idc1_offset_y=20.5-clearance/2;
idc1_offset_z=-wall_width;
idc2_offset_x=idc1_offset_x;
idc2_offset_y=39.6-clearance/2;
idc2_offset_z=idc1_offset_z;

//SD card slot
SD_slot_x=24.5+clearance; //wider for clearance
SD_slot_y=29.5;
SD_slot_z=4;
SD_slot_offset_x=100.5-clearance/2;
SD_slot_offset_y=39.5;
SD_slot_offset_z=pl_z;

//case variables
shell_split_z = pl_z+SD_slot_z; //board split in the top of the slots
shell_width=wall_width+clearance;

shell_top = pl_z+click_encoder_z+2;

Then I write a number of small functions to draw up the components:

module LCD_assembly() {
    translate([0,0,lcd_h_offset_z+lcd_h_z])
        lcd();
        pl_board();
   //lcd connection header
    color("black")
        translate([lcd_h_offset_x,lcd_h_offset_y,lcd_h_offset_z])
            cube([lcd_h_x,lcd_h_y,lcd_h_z]);
}

//LCD screen
module lcd() {
    difference(){
        union(){
            color("OliveDrab")
                translate([0,0,0])
                    cube([lcd_board_x,lcd_board_y,lcd_board_z]);
            color("DarkSlateGray")
                translate([(lcd_board_x-lcd_scrn_x)/2,(lcd_board_y-lcd_scrn_y)/2,lcd_board_z])
                    cube([lcd_scrn_x,lcd_scrn_y,lcd_scrn_z]);
        }
        for(i=[lcd_hole_offset,lcd_board_x-lcd_hole_offset]){
            for(j=[lcd_hole_offset,lcd_board_y-lcd_hole_offset]){
                translate([i,j,lcd_board_z])
                    cylinder(r=lcd_hole_d/2,h=lcd_board_z+3,$fn=12,center=true);
            }
        }
    }
}

//PanelOne circuit board simplified
module pl_board() {
    difference(){
        union(){
            color("lightgreen")cube([pl_x,pl_y,pl_z]);
            //click encoder
            color("darkgrey"){
                translate([click_encoder_offset_x,click_encoder_offset_y,pl_z+(click_encoder_z)/2])
                    cube([click_encoder_x,click_encoder_y,click_encoder_z],center=true);
                translate([click_encoder_offset_x,click_encoder_offset_y,pl_z+click_encoder_z+(click_encoder_shaft_h)/2])
                    cylinder(r=click_encoder_shaft_dia/2,h=click_encoder_shaft_h,center=true);
            //contrast and brightness pots
                  translate([con_offset_x,con_offset_y,con_offset_z+cb_h/2])
                    cylinder(r=cb_dia/2,h=cb_h,center=true);
                  translate([bri_offset_x,bri_offset_y,bri_offset_z+cb_h/2])
                    cylinder(r=cb_dia/2,h=cb_h,center=true);
            }        
        }
        translate([-0.1,-0.1,-0.1]){
            cube([93,45,pl_z+2]);
            cube([6,lcd_board_y+1,pl_z+2]);
        }
        //mounting holes
        translate([pl_mounting_hole_x,pl_mounting_hole1_y,(pl_z+3)/2])
            cylinder(r=pl_mounting_hole_dia/2,h=pl_z+3,center=true);
        translate([pl_mounting_hole_x,pl_mounting_hole2_y,(pl_z+3)/2])
            cylinder(r=pl_mounting_hole_dia/2,h=pl_z+3,center=true);
    }
    //SD board 
    color("lightblue")    
        translate([SD_slot_offset_x,SD_slot_offset_y,SD_slot_offset_z]) 
            cube([SD_slot_x,SD_slot_y,SD_slot_z]);
   //IDC headers
    color("darkgrey"){
        translate([idc1_offset_x,idc1_offset_y,idc1_offset_z])
            cube([idc_h_x,idc_h_y,idc_h_z]);
        translate([idc2_offset_x,idc2_offset_y,idc2_offset_z])
            cube([idc_h_x,idc_h_y,idc_h_z]);
    }
}



It is a good idea to split down the design into logical blocks - these can be reused. The LCD module is re-used from the Panelolu2 case design for example.

I used the color function within OpenSCAD to make this render easier to view:

Step 3 - The Case


The case will be a simple design with back and front halves, along with a knob for the click encoder. It will be held together with M3 screws. A mounting method will be discussed in a later post.

The back and front halves are very simple to code, since the hard work has already been done in defining the electronics which is used to "cut" the holes required in the case.

module case_screw_holes(nut_trap=false,z_height=0, dia=lcd_hole_d) {
for(i=[lcd_hole_offset,pl_mounting_hole_x])
for(j=[lcd_hole_offset,pl_mounting_hole2_y]){
if (nut_trap) {
translate([i,j,z_height])
cylinder(r=dia/2, h=shell_width*2, $fn=fn);
translate([i,j,z_height])
cylinder(r=m3_nut_diameter_bigger/2+layer_height*2, h=shell_width, $fn=6);
} else {
translate([i,j,z_height])
cylinder(r=dia/2,h=shell_width*2+30,$fn=12,center=true);
}
}


}

module back() {
    difference(){
        translate([-shell_width,-shell_width,-shell_width])
            cube([pl_x+shell_width*2,pl_y+shell_width*2,shell_split_z+shell_width]);
        translate([-clearance,-clearance,-clearance])
            cube([pl_x+clearance*2,pl_y+clearance*2,shell_split_z+clearance+0.01]);
        LCD_assembly();
        case_screw_holes(false,-shell_width);
    }
    //support pillar
    translate([6,6,0])
        difference(){
            cube([10,10,pl_z+lcd_h_z]);
            translate([wall_width,wall_width,0])
            cube([10-wall_width*2,10-wall_width*2,pl_z+lcd_h_z+0.1]);
        }
    
}



module front() {
    difference(){
        translate([-shell_width,-shell_width,shell_split_z])
            cube([pl_w+shell_width*2,pl_y+shell_width*2,shell_top-shell_split_z+shell_width]);
        translate([-clearance,-clearance,shell_split_z-0.01])
            cube([pl_w+clearance*2,pl_y+clearance*2,shell_top-shell_split_z+clearance]);
        LCD_assembly();
        case_screw_holes(false,shell_top+shell_width);
    }
}


The difference() function used in the code above subtracts a cube that is "shell_width" - "clearance" from the overall front or back shell. It then subtracts the LCD_assembly and the case holes.  The following two pictures (with elements made transparent/hidden) helps to illustrate the process.




Step 4 - Tweak


The great thing with rapid prototyping is the ability to quickly test out designs and make improvements. The first rough print had a couple of issues:


support for the LCD needed

clearance for the IDC connectors needs moving up

Overall the following issues were noted:

  • The holes for the IDC plugs for the cables need to be wider and higher up in the case, easiest to replace with a single cutout.
  • The box spacer used as a support in the back interfered with the back of the LCD
  • To hold the board more rigidly some supports are required - the corners are the easiest place for these.

Fixes:


Change the IDC header dimensions, only one "header" needed in the model now:

//IDC headers, use the clearance required for the plug
//these are much bigger on z than the actual headers for clearance
idc_y_x=16; //not all will be within case
idc_y_y=37.9;
idc_y_z=6.39+2.5;
idc1_offset_x=128.4;
idc1_offset_y=18.1;

idc1_offset_z=1.61;



Remove the box spacer and add supports to the front and back:

module back() {
    side=8; //for the supports
    difference(){
        union(){
            difference(){
                translate([-shell_width,-shell_width,-shell_width])
                    cube([pl_x+shell_width*2,pl_y+shell_width*2,shell_split_z+shell_width]);
                translate([-clearance,-clearance,-clearance])
                    cube([pl_x+clearance*2,pl_y+clearance*2,shell_split_z+clearance+0.01]);
                LCD_assembly();
            }
            //corner supports
            for(i=[-wall_width,pl_y-side+wall_width]){
                translate([-wall_width,i,-shell_width])
                    cube([side,side,8.75]);
                translate([pl_x-side+wall_width,i,-shell_width])
                    cube([side,side,4.35]);
            }
            //additional support
            translate([lcd_board_x-side,-wall_width,-shell_width])
                cube([side,side/2,8.75]);
        }
        case_screw_holes(false,0);
    }
}

  

module front() {
    side=8; //for the supports
    difference(){
        union(){
            difference(){
                translate([-shell_width,-shell_width,shell_split_z])
                    cube([pl_x+shell_width*2,pl_y+shell_width*2,shell_top-shell_split_z +shell_width]);
                translate([-clearance,-clearance,shell_split_z-0.01])
                    cube([pl_x+clearance*2,pl_y+clearance*2,shell_top-shell_split_z +clearance]);
                LCD_assembly();
            }
            //corner supports
            for(i=[-wall_width,pl_x-side+wall_width])
                for(j=[-wall_width,pl_y-side+wall_width]){
                    translate([i,j,shell_split_z])
                        cube([side,side,shell_top-shell_split_z+wall_width]);
                }
            //additional supports
            for(i=[-wall_width,pl_y-side/2+wall_width]){
                translate([lcd_board_x-side,i,shell_split_z])
                cube([side,side/2,shell_top-shell_split_z+wall_width]);
            }
        }
        case_screw_holes(false,shell_top+shell_width);
    }
}


The final case:


Step 5 - Optional Extras


For models I use often or that go through many iterations where I want to quickly change between different parts it makes sense to simplify the selection of what part of the model to display. At the top of the scad file I have:

///////////////////////////////////////////////////////////
//front, back or Assembly
///////////////////////////////////////////////////////////
side=2; //1 = front, -1 = back 2=printing layout -2 Electronics module 0=assembly model
///////////////////////////////////////////////////////////

This then determines what is rendered using a list of if statements used because, annoyingly, OpenSCAD does not appear to support a "switch" statement.

///////////////////////////////////////////////////////////////////////////////////////
// front
if (side==1)
{
    front();
}
// back
else if(side==-1)
{
    back();
}
//Printing plate
else if(side==2)
{
    translate([shell_width,pl_y*2+shell_width*4,shell_top+shell_width])
        rotate([180,0,0])
            front();
    translate([shell_width,shell_width,shell_width])
        back();
    translate([pl_y*0.5,pl_y*1.5+shell_width*2,shell_width])
    knob_assembly(click_encoder_knob_dia/2);
}
//Electronics
else if(side==-2)
{
    LCD_assembly();
}
//assembly
else
{
    back();
    front();
    LCD_assembly();
 translate([click_encoder_offset_x,click_encoder_offset_y,wall_width+ click_encoder_shaft_y+click_encoder_z-2])
        knob_assembly(click_encoder_knob_dia/2);
}
///////////////////////////////////////////////////////////////////////////////////////

Thus changing one number allows you pick the render you want:




That's all for now - I hope to get a blog post out about the PanelOne itself soon.

Monday, 14 April 2014

Using the Duet with a WiFi router

UPDATE: If you are thinking about getting a Duet 0.8.5 and then adding the wifi solution to it you should consider getting a DuetWifi instead. Loads of cool features. Check out www.duet3d.com

Monday, 31 March 2014

Setting up Eclipse for Arduino Due to allow for compilation and upload of RepRap Firmware on the Duet

UPDATE: Have a look at the comments below- Jantje, the author of the Arduino plugin for eclipse has posted some updated advice, the key piece being:
First of all I advice "people not using eclipse already" to use the Product version. This is one install that includes eclipse and the plugin. You can find a download link for your os here: http://eclipse.baeyens.it/download.php. I advise to us the latest version. Mac users must install the latest version due to a change in arduino folder policy on mac.
This is a guide to installing and configuring the Eclipse environment on Windows in order to modify and compile the RepRap Firmware for Duet electronics. It may be generally useful for getting Eclipse to play nicely with the Arduino Due board as well.

Note that many printer settings can be changed in g-code within the RepRap firmware and you may not need to edit and compile a new firmware binary to run the RepRap firmware on your printer.

This guide draws from a number of sources: Adrian's initial guide, 3D-ES's post on the RepRap forum and personal experience. I would really appreciate comments and feedback on how this works on other versions of Windows. If anyone is able to do a similar guide for Mac/Linux that would be greatly appreciated.

Installation


32 Bit. Throughout this guide I have stuck with using the 32bit version of Eclipse. This should work in more situations than the 64 bit version however let me know if you are successful with the 64 bit versions.

Paths. To keep it simple I have used C:\arduino, C:\eclipse and C:\workspace\RepRapFirmware as directory paths in this example - other paths should work but ensure you substitute the new paths in the instructions below.

Install Arduino: download 1.5.6-rc2, Extract and move to C:\arduino

Install Eclipse: download Juno C/C++ SR2. Extract and move into C:\eclipse

Create workspace: make directories:  C:\workspace,  C:\workspace\RepRapFirmware and C:\workspace\RepRapFirmware\Libraries

Run Eclipse: C:\eclipse\eclipse.exe. When prompted for the workspace enter C:\workspace and choose not to be prompted again. Close the welcome help window.

Install the Arduino Eclipse plugin: Select the Help Menu, Install new software. Paste http://www.baeyens.it/eclipse/V2 in the "work with" field and click "Add". It will prompt you to name the repository, use "Arduino Plugin". Uncheck "Group items by category" checkbox then select "Arduino eclipse extensions" item. Click through Next a few times then accept the agreement and finish. Yes to unsigned content, then restart Eclipse.


Setup the Arduino Eclipse plugin:  Select Window menu, "Preferences",  "General",  "Workspace" Check "Save automatically before build". Then click "Arduino" and enter C:\arduino  in the Arduino IDE path and C:\workspace\RepRapFirmware\Libraries in the Arduino Library path. Apply the changes.

Note the "bossac" port number: With your Duet board plugged into USB (but not 12V) press the "erase" button (next to the ethernet port), then the reset button (next to the USB port). If you have not done this before on your PC it may start to install the driver for the native USB port. One this is done go to Control Panel, Devices and Printers and you will see the native USB port. For some reason Windows thinks this is a GPS camera for me:


This shows the port as COM8, note this for the next step

Setup the RepRap Firmware project: Select Arduino menu, "New Sketch". Set the project name to "RepRapFirmware". go next then select C:\arduino\hardware\arduino\sam\boards.txt and select Arduino Due (Native USB Port) as the board.
             NOTE the Arduino Due (Programming Port) will not work with the Duet. 
Set the port to "COM8" or whatever you found in the previous step.
Exit Eclipse

Get the RepRap Firmware source:  Get the version of RepRapFirmware you want to work with. Good options are:

The choice depends on what you are using the firmware for, and you can change to a different branch later. Whichever version you choose, click "Download ZIP" button on the right side of the page and copy the contents of the zip file into  C:\workspace\RepRapFirmware
Only overwrite "RepRapFirmware.cpp" and "RepRapFirmware.h" do not overwrite the other files.


Copy the Libraries: Download the Libraries (click download zip on the right hand side). Copy the sub directories of "Arduino-libraries-master" into the C:\workspace\RepRapFirmware\Libraries\
directory. Next copy C:\arduino\hardware\arduino\sam\libraries\Wire
to C:\workspace\RepRapFirmware\Libraries\

Setup the Paths: Open eclipse, in the Project Explorer window on the left click on the "RepRapFirmware" project and select refresh. All the source files should now appear in the project explorer tree. Next right click on the RepRapFirmware project again and select properties. Navigate to C/C++ General, Paths and Symbols:



the core and variant entries will already be there, add the rest making sure you select "Is a workspace path" and "Add to all languages":



Except the "C:\arduino\hardware\arduino\sam\system\libsam\include" path which needs to be added as a filesystem path:





Note If using the Dc42 version on the firmware you must add the "flash" directory as well:




Once they are all added click apply, choose to rebuild the index and select OK to close the window.

Eclipse is now setup and ready to compile the firmware.

Compiling RepRap Firmware: The compilation output is visible on the console tab selected at the bottom center. Choose the Project menu, clean, clean all, OK. Then click on the green tick to "Verify", ie compile the code.

The progress of the compilation will show in the console window and when complete there will output something like this:



Uploading the Firmware: With the Duet plugged into USB if you have not erased the loaded firmware click the erase button, then the reset button on the Duet. Then click the green arrow on the toolbar "Upload Sketch". The upload will start, shoose "always run in background". In the console windown the upload progress and then the verify progress will be shown:



The compiles firmware is now uploaded to the Duet board. Note if you look in devices and printers the port will have changed to the Arduino Due port:



With a different com port, this is the one you use in Pronterface to talk to the firmware over USB.

Firmware Modification


Detailed information modifying the firmware is outside the scope of this blog post. Printer configuration defaults are in Platform.h:



The screenshot above shows part of the platform.h for the Multi Extruder branch which defines all 8 channels for the Duet and Duex4.

I hope this post has been useful!