I learnt Solidworks a bit at uni and used it for quite a while in a job after that – although I haven’t used it in a while, I’d be pretty confident in saying that if I were to come back to it tomorrow, I’d be back to high productivity pretty quick. The workflow makes logical sense to me, first making your sketch in two dimensions, and then using that to build the 3D object. The ease of rolling back features to make changes, or dimensioning things parametrically, works well and is easy.
So, considering that this logical workflow makes good sense to me, I started looking into open source alternatives that I could use for the long term for personal projects. It seems like there are a fair few options out there that do some bits and pieces but as I suspected, nothing that was great when treated as a direct substitution for Solidworks. The two options I’ve spent the most time exploring are:
FreeCAD
After looking at my available options, this seemed like the fullest featured option: A viewport to work in and review and sketching and drawing tools just like my beloved. But as I tried to use it, I just couldn’t seem to figure out how to do some things. Each new task I tried to do required looking at tutorials or the docs, and then there were some things I just couldn’t figure out at all. The different workspaces were confusing (though it does seem like this might be less of an issue with the current version), and I just couldn’t seem to create an assembly of my project.
Disclaimer: This was quite a while ago for me now, and I didn’t spend a huge amount of time with FreeCAD before I decided to move on. My memory is a bit shady on some of the details!
OpenSCAD
The idea of OpenSCAD is an interesting one. Instead of creating your objects in a viewport, we directly write the code that builds up the object as series of steps from lines and polygons, to extrusions and revolutions, which can then be positioned relative to each other to be added or subtracted. While it is essentially what’s happening in the more standard method, it’s certainly a different way of going about the task.
I’d heard of modelling in this way before and I do think there are some strengths in comparison to visually modelling an item:
- Easy to modify any specific part of the object without messing with the rest – or at least your part is less likely to catastrophically explode when you roll back to make a change to the initial sketch
- You can very precisely position different subsections of your object, or parts in your assembly, even when there’s no clear or simple method to do so, such as a mating surface on parts that are in contact
- For an open source project, sharing of parts is as easy as sharing a text file or cloning a git repo – all settings and details required to build the part are contained in a small amount of text
- Similarly, I can pick it up for a short while on any machine – either just writing some code, or with the GUI open to view the part as I work. No need for a beefy PC for simple work
I think I’ve now spent long enough working in OpenSCAD that I’d be justified in making my judgement. The first and second iterations of my jogwheel design have been done entirely in code (available for perusal in the repo) and I’ve done the test prints to see if they worked out. For the most part, I’m happy with the resulting objects, however the workflow hasn’t felt particularly productive to me. I have a pretty busy schedule so when I get a chance to work on some extracurricular project, it can be really disappointing to spent the majority of that time trying to figure out how I can do something, instead of actually doing it. In essence, it feels like I’m having to fight against OpenSCAD to get my work done, instead of working with it.
An example of what I’m talking about is the confusion between use <__.scad>
and include <__.scad>
and, which one should be used in a certain situation. One directly calls the code in the parent file containing the include
and the other only makes the module available for use
within the parent. This is complicated further by the way that variables are set (the last assignment of a value to the variable is the variable’s value for all instances, even those used previously), although this is a one-off gotcha that you learn and account for.
The trouble is if you have parameters that are all dependent on each other – think clearances, dimensions driven off other key dimensions, etc. – where do you put them? If you set them in the parent file which calls other modules, you can’t have a default value in that module – it would overwrite the parent’s value. You can’t directly access the key dimensions from the parent file within the submodule. The solution I’ve come up with is one that I very much dislike, but is the only one I’ve been able to get working so far. I set the key dimensions in the parent file, calculate the driven dimensions off them, and then pass the dimensions to the submodules as module arguments. This allows me to have a set of default dimensions when displaying the submodule on its own (which may differ from the overall assembly’s dimensions), but still get the right dimensions when doing the full assembly. Unfortunately, this is how it ends up looking:
// calculated off input parameters
mid_vert_offset = sensor_base_supp_height + sensor_thick + thickness;
jogwheel_height = jogwheel_outer_rad - jogwheel_inner_rad;
inner_bear_rad_offset = jogwheel_mid_rad - 10;
inner_bear_vert_offset = bear_OD / 2 + 3;
outer_bear_rad_offset = jogwheel_inner_rad + 1+6;
outer_bear_vert_offset = bear_OD / 2 + 1;
bearing_params = [outer_bear_rad_offset, outer_bear_vert_offset, inner_bear_rad_offset, inner_bear_vert_offset, bearing_dims, screw_length];
clearance = 1;
outer_clear = 5;
spring_diff = mid_vert_offset - (spring_base_supp_height + thickness);
bearing_grooves = [bearing_groove_dim, bearing_groove_depth, inner_bear_rad_offset, outer_bear_rad_offset];
clearances = [clearance, outer_clear, spring_diff];
// draw settings
// $fn=50;
module jogwheel_assembly() {
union() {
inner_params = [jogwheel_inner_rad, inner_wall, inner_thickness, inner_height, tooth_params, bearing_grooves, clearances];
translate([0,0,jogwheel_height-inner_height+8])
jogwheel_inner(inner_params);
outer_params = [jogwheel_outer_rad, jogwheel_inner_rad, jogwheel_height, thickness, bearing_params, tooth_params, bearing_grooves, clearances];
translate([0,0,8])
jogwheel_outer(outer_params);
contd...
It’s a difficult to mentally parse and so effectively becomes more difficult than I’d like for other people to edit, which is far from ideal for something I was hoping would be easily user-modifiable. If I’ve done a good job of parameterizing things off a few key dimensions it should be less of an issue, but there will always be people who want more customization (and I want it to be easy for me to edit the details too!)
Other than features of the scripting language itself, some other things I think are missing but quite important for a 3D modelling program are:
- Section views out of the box – this can (clunkily) be done reasonably fast with a large cube and a difference(), but when looking at an assembly to review for clashes or clearance, the ability to slide a section cut along an axis is invaluable. As far as features in the software go, it shouldn’t actually be that hard either, so this would be an easy win for user-friendliness
- Fillets. This one’s a tricky one to implement, no lie. Even on Solidworks it can sometimes behave strangely so I don’t doubt it would be very tricky to get right. But it’s also one of the most common things you’d be required to do to an item. Curved corners not only feel nicer and more polished in a part, but in 3D printing they can also assist with reducing localised high stress regions, and spread the load over more layers to reduce risk of breaking for certain geometries. It can be done on a case by case basis but it’s a lot of extra time
- Rendering speed is pretty slow when bumping up the quality level, to the point where the program seems to often be non-responsive and sometimes crash for me
- Export control for animation is very limited (and also doesn’t tell you what it’s doing)
- The docs are a bit light on in details for some of the usage issues I’ve come across, which makes it tricky to figure out what’s going on and how to fix it
- The log messages when building could use some work – sometimes unclear, and the location isn’t always right
I think a lot of this could very potentially be a me-problem, and not an OpenSCAD problem. I likely have a different background to a lot of its users, and maybe I haven’t spent long enough looking at other peoples’ ways of doing things to learn what works best. I am absolutely not an export in either 3D modelling not programming, and I’m sure there are better ways to do what I need to do. There are some amazing libraries out there such as NopSCADlib which I’ve been meaning to look at for inspiration and a bit of an OpenSCAD styleguide on how to make good parts.
Next Steps
I’m well into the process with OpenSCAD for my jogwheel design so I think I’ll be sticking with it for now, and looking at some libraries for inspiration on how to model parts better. Maybe in time I’ll become more productive with it once I learn how to avoid the pitfalls.
On the other hand, I’ve had a bit of a look at Blender and think I might give it a go in another project I’ve previously modelled up some printed parts in Solidworks for, but don’t have a computer with it on any longer. I’ve used it a little for programmatic mesh generation which can subsequently be turned into solids for printing, however the mesh editor interface appears very powerful – although possibly less suited to use cases where highly accurate dimensions and clearances are necessary. I’ll spend some time on this when I have a chance and post with some feedback
If you know how to use OpenSCAD better than I do, or if I’m just doing something dumb, let me know!