...
 
Commits (14)
......@@ -12,9 +12,14 @@
docs/*.zip
# Ignore automatically built files
Makefile
builds/
docs/Output/
Makefile
*.stl.d
ninja.build
build.ninja
.ninja_deps
.ninja_log
# Ignore IDE files
.vscode/
......
......@@ -6,20 +6,20 @@ stages:
build:
stage: build
image: ubuntu:18.04
before_script:
- apt-get update -qq
- apt-get -y -qq install software-properties-common dirmngr apt-transport-https lsb-release ca-certificates make
- 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
script:
# Build STL files with OpenSCAD
- mkdir -p /root/.local/share
- python3 ./generate_makefile.py
- make -j7
- ./build.py
artifacts:
expire_in: 1 week
name: "${CI_PROJECT_NAME}-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}"
......@@ -83,12 +83,12 @@ deploy:
# 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
# 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" .)
- (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
......
......@@ -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 ``python generate_makefile.py`` and then ``make`. This will generate a makefile and run it to 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 (run ``python generate_makefile.py`` and then ``make`` 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)
ninja.rule(
"openscad", command="openscad $parameters $in -o $out -d $out.d", depfile="$out.d"
)
build_dir = "builds"
def p_string(name, value):
"""
Build an OpenScad parameter string from a variable name and value
Arguments:
name {[str]} -- Parameter name
value -- Parameter value
"""
# Convert bools to lowercase
if type(value) == bool:
value = str(value).lower()
# Wrap strings in quotes
elif type(value) == str:
value = f'"{value}"'
return "-D '{}={}'".format(name, value)
def stage_parameters(stage_size, sample_z):
"""
Return array of common stage parameters for a given size and sample z
Arguments:
stage_size {str} -- Stage size, e.g. "LS"
sample_z {int} -- Sample z position, default 65
"""
return [p_string("big_stage", (stage_size == "LS")), p_string("sample_z", sample_z)]
################################
### GENERAL, WIDELY USED OPTIONS
# All available microscope sizes
stage_size_options = ["LS"]
sample_z_options = [65]
# All permutations of microscope size
microscope_size_options = [
f"{stage_size}{sample_z}"
for stage_size in stage_size_options
for sample_z in sample_z_options
]
###################
### MICROSCOPE BODY
for stage_size in stage_size_options:
for sample_z in sample_z_options:
for beamsplitter in [True, False]:
for brim in [True, False]:
motors = True # Right now we never need to remove motor lugs
outputs = "{build_dir}/main_body_{stage_size}{sample_z}{motors}{beamsplitter}{brim}.stl".format(
build_dir=build_dir,
stage_size=stage_size,
sample_z=sample_z,
motors="-M" if motors else "",
beamsplitter="-BS" if beamsplitter else "",
brim="_brim" if brim else "",
)
parameters = [
*stage_parameters(stage_size, sample_z),
p_string("motor_lugs", motors),
p_string("beamsplitter", beamsplitter),
p_string("enable_smart_brim", brim),
]
ninja.build(
outputs,
rule="openscad",
inputs="openscad/main_body.scad",
variables={"parameters": " ".join(parameters)},
)
#################
### OPTICS MODULE
cameras = ["picamera_2", "logitech_c270", "m12"]
rms_lenses = [
"rms_f40d16",
"rms_f50d13",
"rms_infinity_f50d13",
] # NB: Only RMS lenses are compatible with the beamsplitter
optics_versions = [
("picamera_2", "pilens"),
("logitech_c270", "c270_lens"),
("m12", "m12_lens"),
] + [(camera, lens) for camera in cameras for lens in rms_lenses]
for sample_z in sample_z_options:
for (camera, lens) in optics_versions:
beamsplitter_options = [True, False] if lens in rms_lenses else [False]
for beamsplitter in beamsplitter_options:
outputs = "{build_dir}/optics_{camera}_{lens}{beamsplitter}.stl".format(
build_dir=build_dir,
camera=camera,
lens=lens,
beamsplitter="_beamsplitter" if beamsplitter else "",
)
parameters = [
p_string("sample_z", sample_z),
p_string("optics", lens),
p_string("camera", camera),
]
ninja.build(
outputs,
rule="openscad",
inputs="openscad/optics.scad",
variables={"parameters": " ".join(parameters)},
)
####################
### MICROSCOPE STAND
for stand_height in [30]:
for beamsplitter in [True, False]:
outputs = "{build_dir}/microscope_stand_{stand_height}{beamsplitter}.stl".format(
build_dir=build_dir,
stand_height=stand_height,
beamsplitter="-BS" if beamsplitter else "",
)
parameters = [
p_string("h", stand_height),
p_string("beamsplitter", beamsplitter),
]
ninja.build(
outputs,
rule="openscad",
inputs="openscad/microscope_stand.scad",
variables={"parameters": " ".join(parameters)},
)
ninja.build(
"builds/microscope_stand_no_pi.stl",
rule="openscad",
inputs="openscad/microscope_stand_no_pi.scad",
variables={"parameters": " ".join(parameters)},
)
########
### FEET
for foot_height in [15, 26]:
# Figure out some nice names for foot heights
if foot_height == 26:
version_name = "_tall"
elif foot_height == 15:
version_name = ""
else:
version_name = f"_{foot_height}"
outputs = "{build_dir}/feet{version}.stl".format(
build_dir=build_dir, version=version_name
)
parameters = [p_string("foot_height", foot_height)]
ninja.build(
outputs,
rule="openscad",
inputs="openscad/feet.scad",
variables={"parameters": " ".join(parameters)},
)
###################
### CAMERA PLATFORM
for stage_size in stage_size_options:
for sample_z in sample_z_options:
for version in ["picamera_2", "6led"]:
outputs = "{build_dir}/camera_platform_{version}_{stage_size}{sample_z}.stl".format(
build_dir=build_dir,
version=version,
stage_size=stage_size,
sample_z=sample_z,
)
parameters = [
*stage_parameters(stage_size, sample_z),
p_string("optics", "pilens"),
p_string("camera", version),
]
ninja.build(
outputs,
rule="openscad",
inputs="openscad/camera_platform.scad",
variables={"parameters": " ".join(parameters)},
)
###############
### LENS SPACER
for stage_size in stage_size_options:
for sample_z in sample_z_options:
outputs = "{build_dir}/lens_spacer_picamera_2_pilens_{stage_size}{sample_z}.stl".format(
build_dir=build_dir, stage_size=stage_size, sample_z=sample_z
)
parameters = [
*stage_parameters(stage_size, sample_z),
p_string("optics", "pilens"),
]
ninja.build(
outputs,
rule="openscad",
inputs="openscad/lens_spacer.scad",
variables={"parameters": " ".join(parameters)},
)
##################
### PICAMERA TOOLS
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 = [p_string("camera", "picamera_2")]
ninja.build(
outputs,
rule="openscad",
inputs=inputs,
variables={"parameters": " ".join(parameters)},
)
#################
### SAMPLE RISERS
for riser_type in ["sample", "slide"]:
outputs = f"builds/{riser_type}_riser_LS10.stl"
inputs = f"openscad/{riser_type}_riser.scad"
parameters = [p_string("big_stage", True), p_string("h", 10)]
ninja.build(
outputs,
rule="openscad",
inputs=inputs,
variables={"parameters": " ".join(parameters)},
)
###############
### SMALL PARTS
parts = [
"actuator_assembly_tools",
"actuator_drilling_jig",
"back_foot",
"condenser",
"gears",
"illumination_dovetail",
"lens_tool",
"motor_driver_case",
"sample_clips",
"small_gears",
"thumbwheels",
]
for part in parts:
outputs = f"builds/{part}.stl"
inputs = f"openscad/{part}.scad"
ninja.build(outputs, rule="openscad", inputs=inputs)
###############
### RUN BUILD
build_file.close()
run_build()
This diff is collapsed.