Commits (54)
......@@ -14,6 +14,12 @@ docs/*.zip
# Ignore automatically built files
# Ignore IDE files
image: ubuntu:18.04
- apt-get update -qq
- apt-get -y -qq install software-properties-common dirmngr apt-transport-https lsb-release ca-certificates make
- add-apt-repository -y ppa:openscad/releases
- apt-get update -qq
- apt-get install -y -qq openscad
- build
- deploy
# Build STL files
stage: build
image: ubuntu:18.04
- apt-get update -qq
- apt-get -y -qq install software-properties-common dirmngr apt-transport-https lsb-release ca-certificates python3-pip
- add-apt-repository -y ppa:openscad/releases
- apt-get update -qq
- apt-get install -y -qq openscad
- pip3 install -r requirements.txt
# Build STL files with OpenSCAD
- mkdir -p /root/.local/share
- ./build.py
expire_in: 1 week
- builds/*.stl
- tags
- merge_requests
- web
# Build docs
stage: build
image: ubuntu:18.04
- apt-get update -qq
- apt-get -y -qq install software-properties-common
- apt-get -y -qq install git git-lfs
# Build documentation
# TODO: Implement git-building to render .md to .html
- git lfs install
- git config --local lfs.fetchexclude "/docs/original_images,/design_files"
- git lfs fetch
- git lfs checkout
- python3 ./build_docs.py
expire_in: 1 week
- builds/
- tags
- merge_requests
- web
# Deploy to builds.openflexure.org
stage: deploy
- build
- build-docs
image: ubuntu:latest
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- ssh-add <(echo "$SSH_PRIVATE_KEY_BATH_OPENFLEXURE_BASE64" | base64 --decode)
- mkdir -p ~/.ssh
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- mkdir -p /root/.local/share
- make -j7
- builds/
\ No newline at end of file
# Install rsync if not already installed
- 'which rsync || ( apt-get update -y && apt-get install rsync -y )'
# Upload the builds folder to openflexure-microscope builds
- rsync -hrvz -e ssh builds/ ci-user@openflexure.bath.ac.uk:/var/www/build/openflexure-microscope/${CI_COMMIT_REF_NAME} --delete
# Zip the builds folder and upload it to the openflexure-microscope build root
- 'which zip || ( apt-get update -y && apt-get install zip -y )'
- (cd builds && zip -r "../${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}.zip" .)
- rsync -hrvz -e ssh "${CI_PROJECT_NAME}-${CI_COMMIT_REF_NAME}.zip" ci-user@openflexure.bath.ac.uk:/var/www/build/openflexure-microscope/
# Run update-latest.py on the build server
- ssh -t ci-user@openflexure.bath.ac.uk "/var/www/build/update-latest.py"
- tags
- web
......@@ -2,10 +2,7 @@
The microscope is modelled using OpenSCAD. This means there's a collection of scripts that, when run, generate STL files that you can then print. The best way to get hold of the latest STL files is to generate them yourself. To do this, you will need [OpenSCAD](http://www.openscad.org/) (available for Windows, Mac and Linux). The simplest way to build all the necessary STL files is to use GNU Make. If you use Linux you will almost certainly have this, Mac OS should either have it or be able to get it from homebrew etc., and Windows you can get it through Cygwin or MinGW.
To build all the STL files (NB you don't need to print all of these, there are some alternatives), simply change directory to the root folder of this repository and run ``make all``. This will compile the files and put them in the ``builds/`` directory.
## Make on Windows
I was happy to find out that [you can use make in MSYS](https://gist.github.com/evanwill/0207876c3243bbb6863e65ec5dc3f058), which comes bundled with Git for Windows. If you install Git for Windows, you can then download a copy of the executable file for make and put it in the bin directory. For me, this was ``C:\Users\me\AppData\Local\Programs\Git\mingw64\bin`` though your installation may be different. NB to start MSYS on Windows, look for "Git Bash" in your Start menu.
To build all the STL files (NB you don't need to print all of these, there are some alternatives), simply change directory to the root folder of this repository and run ``pip3 install -r requirements.txt`` and then ``./build.py`. This will generate a Ninja build file and run it to compile the files and put them in the ``builds/`` directory.
## OpenSCAD command line
You'll need to make sure OpenSCAD is in your executable path so the build script can [run it from the command line](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_OpenSCAD_in_a_command_line_environment). This is probably the case on Linux, but on Windows I just ran ``PATH="$PATH:/c/Program Files/OpenSCAD/"`` before running make. A more permanent solution is to put that command line into a text file ``.bash_profile`` in your home directory (i.e. ``C:\Users\me\.bash_profile``). If it doesn't exist, just create a new text file with that as the only line. Once you've done this, OpenSCAD will automatically be added to your path every time you start MSYS (aka Git Bash). NB the filename does not have a ``.txt`` extension, and it won't work if you leave one there. Symlinking the OpenSCAD binary into your mingw64 binaries folder seems to break things like the OpenSCAD includes directory, so use the method above in preference if you can.
......@@ -53,4 +53,4 @@ Most of the Openflexure Microscope stuff lives on GitHub, under [my account](htt
* Some [characterisation scripts for analysing images of the USAF resolution test target](https://github.com/rwb27/usaf_analysis/)
## Compiling from source
If you want to print the current development version, you can compile the STL from the OpenSCAD files - but please still consult the documentation for quantities and tips on print settings, etc. You can use GNU Make to generate all the STL files (just run ``make all`` in the root directory of the repository). More instructions, including hints for Windows users, are available in [COMPILE.md](COMPILE.md).
If you want to print the current development version, you can compile the STL from the OpenSCAD files - but please still consult the documentation for quantities and tips on print settings, etc. You can use Ninja build to generate all the STL files (run ``pip3 install -r requirements.txt`` and then ``./build.py`` in the root directory of the repository). More instructions are available in [COMPILE.md](COMPILE.md).
#!/usr/bin/env python3
from ninja import Writer, ninja as run_build
build_file = open("build.ninja", "w")
ninja = Writer(build_file, width=120)
"openscad", command="openscad $parameters $in -o $out -d $out.d", depfile="$out.d"
for brim in ["", "_brim"]:
size = "65"
motors = "-M"
outputs = "builds/main_body_LS" + size + motors + brim + ".stl"
parameters = ["-D big_stage=true", "-D sample_z=65", "-D motor_lugs=true"]
if brim == "":
parameters.append("-D enable_smart_brim=false")
parameters.append("-D enable_smart_brim=true")
variables={"parameters": " ".join(parameters)},
cameras = ["picamera_2", "logitech_c270", "m12"]
rms_lenses = ["rms_f40d16", "rms_f50d13", "rms_infinity_f50d13"]
optics_versions = [
("picamera_2", "pilens"),
("logitech_c270", "c270_lens"),
("m12", "m12_lens"),
] + [(camera, lens) for camera in cameras for lens in rms_lenses]
for (camera, lens) in optics_versions:
outputs = f"builds/optics_{camera}_{lens}_LS65.stl"
parameters = ["-D big_stage=true", "-D sample_z=65", "-D enable_smart_brim=false"]
parameters.append(f"-D 'optics=\"{lens}\"'")
parameters.append(f"-D 'camera=\"{camera}\"'")
variables={"parameters": " ".join(parameters)},
camera_platform_versions = ["picamera_2", "6led"]
for version in camera_platform_versions:
outputs = f"builds/camera_platform_{version}_LS65.stl"
parameters = ["-D big_stage=true", "-D sample_z=65", "-D enable_smart_brim=false"]
parameters.append("-D 'optics=\"pilens\"'")
parameters.append(f"-D 'camera=\"{version}\"'")
variables={"parameters": " ".join(parameters)},
feet_versions = ["", "_tall"]
for version in feet_versions:
outputs = f"builds/feet{version}.stl"
if version == "_tall":
parameters.append("-D foot_height=26")
variables={"parameters": " ".join(parameters)},
parameters = ["-D big_stage=true", "-D sample_z=65", "-D enable_smart_brim=false"]
parameters.append("-D 'optics=\"pilens\"'")
variables={"parameters": " ".join(parameters)},
picamera_2_tools = ["cover", "gripper", "lens_gripper"]
for tool in picamera_2_tools:
outputs = f"builds/picamera_2_{tool}.stl"
inputs = f"openscad/cameras/picamera_2_{tool}.scad"
parameters = ["-D 'camera=\"picamera_2\"'"]
variables={"parameters": " ".join(parameters)},
stand_versions = ["", "_no_pi"]
for version in stand_versions:
output = f"builds/microscope_stand{version}.stl"
inputs = f"openscad/microscope_stand{version}.scad"
parameters = ["-D big_stage=true", "-D sample_z=65", "-D enable_smart_brim=false"]
variables={"parameters": " ".join(parameters)},
riser_types = ["sample", "slide"]
for t in riser_types:
outputs = f"builds/{t}_riser_LS10.stl"
inputs = f"openscad/{t}_riser.scad"
parameters = ["-D big_stage=true", "-D h=10"]
variables={"parameters": " ".join(parameters)},
parts = [
for part in parts:
outputs = f"builds/{part}.stl"
inputs = f"openscad/{part}.scad"
......@@ -5,60 +5,68 @@ import sys
import shutil
import re
def insert_markdown(infile, outfile):
"""Insert content into the target markdown file"""
def process_markdown(infile, outfile):
"""Remove the title of a markdown file, and add Jekyll front matter"""
preamble_lines = []
"""Process and copy a markdown file, and scan for images used in the file"""
images = set()
extracted_title = False
with open(infile, 'r') as input, open(outfile, 'w') as output:
for line in input:
if not extracted_title:
if line.startswith("# "):
# once we have the title, write the YAML block, then regurgitate the preceding bit of the file.
title = line.strip("# \n")
output.write("layout: page\n")
output.write(f"title: {title}\n")
output.write("nav: false\n")
extracted_title = True
print(f"Added header for '{title}' ({infile})")
output.write(line) # copy over the file
with open(infile, 'r', encoding='utf8') as input_file, open(outfile, 'w', encoding='utf8') as output_file:
print(f"Opened {infile}...")
# Inject extra markdown only if the file isn't special
if (os.path.basename(infile)[0] != "_"):
insert_markdown(infile=infile, outfile=outfile)
print(f"File {infile} is special. Copying without modification.")
# Copy the basic markdown content into the new file, and find images
for line in input_file:
# Copy over the line
output_file.write(line) # copy over the file
# Search for images
m = re.search(r"images/([^.]*\.(jpeg|jpg|JPG|JPEG|png|PNG))", line)
if m:
return images
if __name__ == "__main__":
output_dir = "../builds/docs"
# Find all relevant directories
here = os.path.dirname(os.path.realpath(__file__))
docs_dir = os.path.abspath(os.path.join(here, "docs"))
parts_dir = os.path.abspath(os.path.join(docs_dir, "parts"))
output_dir = os.path.abspath(os.path.join(here, "builds/docs"))
# Delete the output directory if it exists
if os.path.isdir(output_dir):
# Create the output directory and the folder structure
os.mkdir(os.path.join(output_dir, "parts"))
for f in os.listdir("parts"):
if os.path.isdir(os.path.join("parts",f)):
for f in os.listdir(parts_dir):
if os.path.isdir(os.path.join(parts_dir, f)):
os.mkdir(os.path.join(output_dir, "parts", f))
os.mkdir(os.path.join(output_dir, "images"))
# Copy our docsify index page
shutil.copyfile(os.path.join(docs_dir, "index.html"), os.path.join(output_dir, "index.html"))
# Create a set to note our used image files
images = set()
# This should be recursive or something - but for now, I just enumerate the parts directory
for indir in ['.', 'parts'] + [os.path.join('parts',d) for d in os.listdir("parts") if os.path.isdir(os.path.join("parts", d))]:
for f in os.listdir(indir):
# TODO: This should be recursive or something - but for now, I just enumerate the parts directory
for input_dir in ['.', 'parts'] + [os.path.join('parts', d) for d in os.listdir(parts_dir) if os.path.isdir(os.path.join(parts_dir, d))]:
input_dir_abs = os.path.join(docs_dir, input_dir)
for f in os.listdir(os.path.join(docs_dir, input_dir)):
if f.endswith(".md"):
f_images = process_markdown(os.path.join(indir, f), os.path.join(output_dir, indir, f))
f_images = process_markdown(os.path.join(input_dir_abs, f), os.path.join(output_dir, input_dir, f))
# copy over only the images that are actually used
# Copy over only the images that are actually used
for f in images:
shutil.copyfile(os.path.join("images", f), os.path.join(output_dir, "images", f))
shutil.copyfile(os.path.join(docs_dir, "images", f), os.path.join(output_dir, "images", f))
\ No newline at end of file
- [Home](./index.md)
- [Obtaining non-printed parts](./0_bill_of_materials.md)
- [Printing parts](./0_printing.md)
- [Assembling the actuators](./1_actuator_assembly.md)
- [Optics module](#)
- [Basic optics module](./2a_basic_optics_module.md)
- [High resolution optics module](./2b_high_resolution_optics_module.md)
- [Illumination](./3_illumination.md)
- [Sample clips and wiring](./4_clips_and_wiring.md)
- [Motors](./5_motors.md)
- [Motor controller boards](./6_motor_controllers.md)
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>OpenFlexure Documentation</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple.css">
:root {
--theme-color: #c5247f;
--sidebar-name-text-align: left;
a {
color: var(--theme-color)
.markdown-section img {
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15), 0 2px 5px rgba(0, 0, 0, 0.12);
border-radius: 4px;
<a href="https://openflexure.org">OpenFlexure Homepage</a>
<div id="app"></div>
window.$docsify = {
homepage: 'index.md',
loadSidebar: '_navigation.md',
relativePath: true,
subMaxLevel: 3,
auto2top: true,
name: 'OpenFlexure Documentation',
nameLink: '#/',
themeColor: '#c5247f'
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
# The OpenFlexure Microscope - Assembly Instructions
# OpenFlexure Microscope - Assembly Instructions
The OpenFlexure Microscope is a 3D printable microscope, with a very precise mechanical translation stage. It can be fitted with basic webcam-based optics, or more expensive optics based on a traditional microscope objective for higher image quality. It can also be motorised. These instructions will take you through how to assemble the microscope optical and mechanical parts.
## Printing the parts
......@@ -4,18 +4,18 @@ This part is the main body of the microscope, including all the flexure mechanis
## Printing Instructions
This should be printed without support material. On smaller/less well calibrated machines, I print this part on its own and then print the rest of the parts in a second print. Which version of the body you need depends on two things: firstly, the height of the stage, and secondly whether you want attachment lugs for motors. The microscope body takes around 10 hours on a RepRapPro Ormerod (and many other low-end printers) or about 8 hours on Ultimaker, MakerBot, or Prusa i3 Mk3 and the like.
![A picture of the main body](./images/main_body.jpg)
![A picture of the main body](../../images/main_body.jpg)
### STL File
The main body is printed from ``main_body_LS<height>.stl``, or ``main_body_LS<height>-M.stl`` where ``<height>`` is either 65 or 75 depending on how tall you want the microscope to be. We almost exclusively use a height of 65mm, and if a taller stage is required (e.g. to use a larger microscope objective) we combine it with a [sample riser](./sample_riser.md). The ``-M`` in the filename means it includes motor lugs - these allow you to attach stepper motors to the microscope and move it automatically. If in doubt, print ``main_body_LS65-M.stl`` because you can always just ignore the lugs, and add a riser, if it turns out you have the wrong one!
### Actuator cleanup
After printing, you may run a 3mm drill bit through the 3mm holes in each actuator, to ensure the screws can rotate freely (usually this is not necessary).
![drilling out the hole for the actuator](./images/main_body_drill.jpg)
![drilling out the hole for the actuator](../../images/main_body_drill.jpg)
### Brim cleanup
If the bottom layer has oozed out too much, or if you used a brim you might need to clean up the bottom so it looks like this - it's important that the moving parts aren't stuck to the body with a thin layer of plastic.
![The bottom of the microscope body](./images/main_body_bottom.jpg)
![The bottom of the microscope body](../../images/main_body_bottom.jpg)
### Cleaning up the bridges
You may need to use needle-nose pliers to pull strings of plastic from the underside of the microscope stage. If your printer is correctly calibrated there shouldn't be much, and I often get away without any - but some printers (particularly if using ABS) are prone to a bit of "spaghetti" under the stage.
from __future__ import print_function
import re
import argparse
import functools
"""This script generates the Makefile for the Openflexure Microscope.
It is intended to be run whenever you need a new makefile. The makefile lives in
the repository and is versioned, so most people never need to run this script.
body_versions = [size + motors + brim for size in ["LS65", "LS75"]
for motors in ["-M"] # NB we only want versions with motor lugs!
for brim in ["", "_brim"]]
match_body_versions = [size + motors + brim for size in ["LS65", "LS75"]
for motors in ["-M", ""] # Non-lugged versions are needed for optics modules
for brim in ["", "_brim"]]
# NB the above ugly hack restores the non-motorised bodies, for the purposes of the optics modules
# (optics modules are named LS65 etc. which will only match the now-obsolete versions without
# motor lugs. This will all be fixed in the new build system much more nicely!)
cameras = ["picamera_2", "logitech_c270", "m12"]
lenses = ["pilens", "c270_lens", "m12_lens", "rms_f40d16", "rms_f50d13", "rms_infinity_f50d13"]
optics_versions_LS65 = ["picamera_2_pilens", "logitech_c270_c270_lens"]
optics_versions_LS65 += [cam + "_" + lens for cam in cameras for lens in lenses if "rms" in lens] + ["m12_m12_lens"]
optics_versions = [v + "_LS65" for v in optics_versions_LS65]
sample_riser_versions = ['LS10']
slide_riser_versions = ['LS10']
stand_versions = ['LS65-30', 'LS65-160']
def body_parameters(version):
"""Retrieve the parameters we pass to OpenSCAD to generate the given body version."""
p = {"motor_lugs": False, "sample_z":-1, "big_stage":None}
matching_version = ""
for v in match_body_versions: # first, pick the longest matching version string.
if v in version and len(v) > len(matching_version):
matching_version = v
m = re.match("(LS|SS)([\d]{2})((-M){0,1})((_brim){0,1})", matching_version)
p["big_stage"] = m.group(1)=="LS"
p["motor_lugs"] = m.group(4)=="-M"
p["sample_z"] = m.group(2)
p["enable_smart_brim"] = m.group(6)=="_brim"
return p
def optics_module_parameters(version):
"""Figure out the parameters we need to generate the optics module"""
m = re.search("({cam})_({lens})_({body})".format(
if m is None:
raise ValueError("Error finding optics module parameters from version string '{}'".format(version))
p = {"camera": m.group(1), "optics": m.group(2)}
return p
def stand_parameters(version):
m = re.match("({body})-([\d]+)$".format(body="|".join(match_body_versions)), version)
p = body_parameters(m.group(1))
p["h"] = int(m.group(2))
return p
def riser_parameters(version):
"""extract the parameters for sample risers"""
m = re.match("(LS|SS)([\d]+)", version)
p = {}
p["big_stage"] = "LS" == m.group(1)
p["h"] = int(m.group(2))
return p
def openscad_recipe(**kwargs):
output = "\t" + "openscad -o $@"
for name, value in kwargs.iteritems():
except ValueError:
# numbers and booleans are OK, but strings need to be double-quoted on the command line.
if value not in ["true", "false"]:
value = '"{}"'.format(value)
if type(value) == type(True): #need to convert boolean values
value = "true" if value else "false"
output += " -D '{name}={value}'".format(name=name, value=str(value))
output += " $<\n"
return output
def merge_dicts(*args):
"""Merge dictionaries together into a single output."""
out = args[0].copy()
for a in args[1:]:
return out
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate the Openflexure Microscope makefile")
parser.add_argument("--version_numstring", help="Override the defined version string", default=None)
args = parser.parse_args()
extra_defines = {}
if args.version_numstring:
extra_defines['version_numstring'] = args.version_numstring
def openscad_recipe_baked(**kwargs):
"""An openscad recipe, with additional definitions baked in."""
return openscad_recipe(**merge_dicts(extra_defines, kwargs))
with open("Makefile","w") as makefile:
def M(line):
makefile.write(line + "\n")
M("# Makefile for the openflexure microscope")
M("# Generated by generate_makefile.py")
M(".PHONY: all cleanstl")
M("SOURCE = openscad")
M("OUTPUT = builds")
M("body_versions = " + " ".join(body_versions))
M("optics_versions = " + " ".join(optics_versions))
M("sample_riser_versions = " + " ".join(sample_riser_versions))
M("slide_riser_versions = " + " ".join(slide_riser_versions))
M("TOOLS := actuator_assembly_tools lens_tool")
M("TOOLS := $(TOOLS) picamera_2_cover picamera_2_gripper picamera_2_lens_gripper actuator_drilling_jig")
M("ACCESSORIES := picamera_2_cover $(sample_riser_versions:%=sample_riser_%) $(slide_riser_versions:%=slide_riser_%) microscope_stand microscope_stand_no_pi motor_driver_case back_foot")
M("COMMONPARTS := feet feet_tall gears sample_clips small_gears thumbwheels")
M("BODIES := $(body_versions:%=main_body_%)")
M("OPTICS := $(optics_versions:%=optics_%) camera_platform_picamera_2_LS65 camera_platform_6led_LS65 lens_spacer_picamera_2_pilens_LS65 lens_spacer_picamera_2_pilens_LS75")
M("ILLUMINATIONS := illumination_dovetail condenser")
M("parameters_file := $(SOURCE)/microscope_parameters.scad")
M("utilities_file := $(SOURCE)/utilities.scad")
M("all_deps := $(parameters_file) $(utilities_file) #All targets depend on these")
M("all: $(ALLSTLFILES)")
M("\t"+"rm $(STLFILES)")
M("#parameter and utilities files affect everything")
M("$(OUTPUT)/%.stl: $(all_deps)")
M("main_body_dep_names := compact_nut_seat dovetail logo z_axis")
M("main_body_deps := $(main_body_dep_names:%=$(SOURCE)/%.scad)")
for version in body_versions:
M("$(OUTPUT)/main_body_" + version + ".stl: $(SOURCE)/main_body.scad $(main_body_deps)")
for version in match_body_versions:
M("$(OUTPUT)/illumination_dovetail_" + version + ".stl: $(SOURCE)/illumination_dovetail.scad $(main_body_deps) $(SOURCE)/illumination.scad")
M("$(OUTPUT)/condenser_" + version + ".stl: $(SOURCE)/condenser.scad $(main_body_deps) $(SOURCE)/illumination.scad")
M("optics_dep_names := dovetail cameras/camera")
M("optics_deps := $(optics_dep_names:%=$(SOURCE)/%.scad)")
for version in optics_versions:
M("$(OUTPUT)/optics_" + version + ".stl: $(SOURCE)/optics.scad $(optics_deps)")
for b in ["LS65", "LS75"]:
for n in ["camera_platform_picamera_2", "lens_spacer_picamera_2_pilens"]:
M("$(OUTPUT)/{}_{}.stl: $(SOURCE)/{}.scad $(optics_deps)".format(n, b, n.split("_picamera_")[0]))
M(openscad_recipe_baked(camera="picamera_2", optics="pilens", **body_parameters(b)))
for b in ["LS65", "LS75"]:
n = "camera_platform_6led"
M("$(OUTPUT)/{}_{}.stl: $(SOURCE)/{}.scad $(optics_deps)".format(n, b, n.split("_6led")[0]))
M(openscad_recipe_baked(camera="6led", optics="pilens", **body_parameters(b)))
M("riser_dep_names := main_body")
M("riser_deps := $(optics_dep_names:%=$(SOURCE)/%.scad)")
for version in sample_riser_versions:
M("$(OUTPUT)/sample_riser_" + version + ".stl: $(SOURCE)/sample_riser.scad $(riser_deps)")
for version in slide_riser_versions:
M("$(OUTPUT)/slide_riser_" + version + ".stl: $(SOURCE)/slide_riser.scad $(riser_deps)")
M("stand_dep_names := main_body")
M("stand_deps := $(optics_dep_names:%=$(SOURCE)/%.scad)")
for version in stand_versions:
M("$(OUTPUT)/microscope_stand_" + version + ".stl: $(SOURCE)/microscope_stand.scad $(stand_deps)")
M("$(OUTPUT)/picamera_2_%.stl: $(SOURCE)/cameras/picamera_2_%.scad $(all_deps)")
M("$(OUTPUT)/feet_tall.stl: $(SOURCE)/feet.scad $(all_deps)")
M("$(OUTPUT)/actuator_assembly_tools.stl: $(SOURCE)/actuator_assembly_tools.scad $(all_deps)")
M("$(OUTPUT)/%.stl: $(SOURCE)/%.scad $(all_deps)")
......@@ -128,7 +128,7 @@ module motor_clearance(h=15){
// NB does not include cable clearance, I assume that goes on the outside.
// The centre of the body is at the origin, NB this is NOT the shaft location.
// The shaft is not included.
hull() reflect([1,0]) translate([35/2,0]) circle(r=4.5);
......@@ -30,14 +30,14 @@ $fn=32;
// These are the most useful parameters to change!
big_stage = true; //this option is obsolete and must now always be true...
motor_lugs = true;
version_numstring = "5.20.1";
version_numstring = "6.0.0-b.1";
camera = "picamera_2"; //see cameras/camera.scad for valid values
optics = "rms_f50d13"; //see optics.scad for valid values
led_r = 4.5/2; //size of the LED used for illumination
endstops = false; //whether to build mounts for optical endstops inside the microscope.
feet_endstops = false; //whether to include cut-outs for endstop switches in the feet.
beamsplitter = false; //enables a cut-out in some optics modules for a beamsplitter
smart_brim_r = 3;
smart_brim_r = 5;
enable_smart_brim = false;
// This sets the basic geometry of the microscope
......@@ -39,8 +39,7 @@ module pi_connectors(){
translate([32-25/2, -99, -2]) cube([25,100,18]);
// micro-SD card
translate([0,raspi_board[1]/2+6,0]) cube([80,12,8], center=true);
translate([-4,raspi_board[1]/2,0]) cube([16,12,20], center=true);
translate([-25,raspi_board[1]/2-16,-10]) cube([30,30,16]);
......@@ -204,7 +204,7 @@ module z_motor_clearance(){
module z_axis_casing(condenser_mount=false){
// Casing for the Z axis - needs to have the axis subtracted from it
linear_extrude(h=999) minkowski(){
linear_extrude(height=999) minkowski(){
hull() projection() z_axis_struts();