Compare commits

...

3 Commits

20 changed files with 469 additions and 21 deletions

View File

@ -1,5 +1,5 @@
{
"version": "1.8.159",
"version": "1.8.161",
"ext_port": 1111,
"profiles": {
"mcopy": {

2
app/package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "mcopy-app",
"version": "1.8.159",
"version": "1.8.161",
"lockfileVersion": 2,
"requires": true,
"packages": {

View File

@ -1,6 +1,6 @@
{
"name": "mcopy-app",
"version": "1.8.159",
"version": "1.8.161",
"description": "GUI for the mcopy small gauge film optical printer platform",
"main": "main.js",
"scripts": {

View File

@ -1,5 +1,5 @@
{
"version": "1.8.159",
"version": "1.8.161",
"ext_port": 1111,
"profiles": {
"mcopy": {

39
docs/whitepaper/README.md Normal file
View File

@ -0,0 +1,39 @@
---
fontfamily: tgtermes
title: "mcopy: Modular Optical Tool Platform for Small Gauge Motion Picture Film"
documentclass: article
author:
- name: Matthew McWilliams
affiliation: sixteenmillimeter.com
email: hi@mmcwilliams.com
abstract: |
Tools purpose-built for working with 16mm, Super8 and Regular8 film have not been produced commercially since the
The mcopy project proposes a modular, open-source platform for building optical tools for small gauge analog moviefilm formats.
The platform can be used to assemble optical printers, digital transfer units and film recorders for digital images.
bibliography: sources.bib
csl: citation_style.csl
---
# Introduction
# Desktop Application
# Serial Protocol
# Retrofitting Existing Hardware
# New Hardware
Retrofitting existing hardware was always intended as the first step to producing new hardware modules that could eventually completely replace all legacy machine parts.
This approach is sometimes referred to as a "Ship of Theseus pattern"[@wiki-shipoftheseus] and in this application is, simply put: build machines using parts that people and organizations already have until total replacements can be designed.
The practice of retrofitting hardware, in this case, required the kind of inspection that makes designing replacements possible: detailed measurements, documenting electrical diagrams, and review of sourced components.
Two examples of this pattern that have materialized new modular components are the projector and gate designs.
## References
---
refs: |
::: {#refs}
:::
...

View File

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only" default-locale="en-GB">
<info>
<title>Nature</title>
<id>http://www.zotero.org/styles/nature</id>
<link href="http://www.zotero.org/styles/nature" rel="self"/>
<link href="http://www.nature.com/nature/authors/gta/index.html#a5.4" rel="documentation"/>
<link href="http://www.nature.com/srep/publish/guidelines#references" rel="documentation"/>
<author>
<name>Michael Berkowitz</name>
<email>mberkowi@gmu.edu</email>
</author>
<category citation-format="numeric"/>
<category field="science"/>
<category field="generic-base"/>
<issn>0028-0836</issn>
<eissn>1476-4687</eissn>
<updated>2022-07-01T16:03:34+00:00</updated>
<rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
</info>
<macro name="title">
<choose>
<if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<text variable="title" font-style="italic" text-case="title"/>
</if>
<else>
<text variable="title"/>
</else>
</choose>
</macro>
<macro name="author">
<names variable="author">
<name sort-separator=", " delimiter=", " and="symbol" initialize-with=". " delimiter-precedes-last="never" name-as-sort-order="all"/>
<label form="short" prefix=", "/>
<et-al font-style="italic"/>
</names>
</macro>
<macro name="access">
<choose>
<if variable="volume" type="article dataset software" match="any"/>
<else-if variable="DOI">
<text variable="DOI" prefix="doi:"/>
</else-if>
</choose>
</macro>
<macro name="access-data">
<choose>
<if type="dataset software" match="any">
<text variable="DOI" prefix="https://doi.org/"/>
</if>
</choose>
</macro>
<macro name="issuance">
<choose>
<if type="bill book graphic legal_case legislation motion_picture song thesis chapter paper-conference" match="any">
<group delimiter="; " suffix=".">
<group delimiter=", " prefix="(" suffix=")">
<text variable="publisher" form="long"/>
<text variable="publisher-place"/>
<date variable="issued">
<date-part name="year"/>
</date>
</group>
</group>
</if>
<else-if type="article">
<group delimiter=" ">
<choose>
<if variable="genre" match="any">
<text variable="genre" text-case="capitalize-first"/>
</if>
<else>
<text term="article" text-case="capitalize-first"/>
</else>
</choose>
<text term="at"/>
<choose>
<if variable="DOI" match="any">
<text variable="DOI" prefix="https://doi.org/"/>
</if>
<else>
<text variable="URL"/>
</else>
</choose>
<date date-parts="year" form="text" variable="issued" prefix="(" suffix=")"/>
</group>
</else-if>
<else-if type="dataset software" match="any">
<group delimiter=" ">
<text variable="publisher"/>
<text macro="access-data"/>
<date date-parts="year" form="text" variable="issued" prefix="(" suffix=")"/>
</group>
</else-if>
<else-if type="report webpage post post-weblog" match="any">
<group delimiter=" ">
<text variable="URL"/>
<date date-parts="year" form="text" variable="issued" prefix="(" suffix=")"/>
</group>
</else-if>
<else>
<date variable="issued" prefix="(" suffix=")">
<date-part name="year"/>
</date>
</else>
</choose>
</macro>
<macro name="container-title">
<choose>
<if type="article-journal">
<text variable="container-title" font-style="italic" form="short"/>
</if>
<else>
<text variable="container-title" font-style="italic"/>
</else>
</choose>
</macro>
<macro name="editor">
<choose>
<if type="chapter paper-conference" match="any">
<names variable="editor" prefix="(" suffix=")">
<label form="short" suffix=" "/>
<name and="symbol" delimiter-precedes-last="never" initialize-with=". " name-as-sort-order="all"/>
</names>
</if>
</choose>
</macro>
<macro name="volume">
<choose>
<if type="article-journal" match="any">
<text variable="volume" font-weight="bold" suffix=","/>
</if>
<else>
<group delimiter=" ">
<label variable="volume" form="short"/>
<text variable="volume"/>
</group>
</else>
</choose>
</macro>
<citation collapse="citation-number">
<sort>
<key variable="citation-number"/>
</sort>
<layout vertical-align="sup" delimiter=",">
<text variable="citation-number"/>
</layout>
</citation>
<bibliography et-al-min="6" et-al-use-first="1" second-field-align="flush" entry-spacing="0" line-spacing="2">
<layout suffix=".">
<text variable="citation-number" suffix="."/>
<group delimiter=" ">
<text macro="author" suffix="."/>
<text macro="title" suffix="."/>
<choose>
<if type="chapter paper-conference" match="any">
<text term="in"/>
</if>
</choose>
<text macro="container-title"/>
<text macro="editor"/>
<text macro="volume"/>
<text variable="page"/>
<text macro="issuance"/>
<text macro="access"/>
</group>
</layout>
</bibliography>
</style>

View File

@ -0,0 +1,6 @@
#!/bin/bash
set -e
pandoc README.md -o mcopy_whitepaper.pdf --filter pandoc-citeproc --pdf-engine=pdflatex --template=template.tex
pandoc README.md -o index.html --filter pandoc-citeproc

View File

@ -0,0 +1,6 @@
@online{wiki-shipoftheseus,
author={Wikipedia},
title={Ship of Theseus},
url={https://en.wikipedia.org/wiki/Ship_of_Theseus},
urldate={2025-02-20}
}

View File

@ -0,0 +1,68 @@
\documentclass[10pt]{article}
\usepackage[left=1.5in,
right=1.5in,
top=1in,
bottom=1.5in,]{geometry}
\usepackage{authblk}
\usepackage{setspace}
\usepackage{hyperref}
\usepackage{lmodern} % For better font weights
\usepackage{sectsty} % For section formatting
\newlength{\cslhangindent}
\setlength{\cslhangindent}{1.5em}
\newenvironment{cslreferences}%
{\setlength{\parindent}{0pt}%
\everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces}%
{\par}
% Handle conditionals
$if(colorlinks)$
\PassOptionsToPackage{usenames,dvipsnames}{color}
$endif$
% Handle fonts
$if(fontfamily)$
\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
$endif$
% Make sections bolder and adjust spacing
\sectionfont{\large\bfseries}
\allsectionsfont{\bfseries}
% Adjust line spacing
\setstretch{1.1} % Tighter line spacing
\begin{document}
% Thick line above title
\noindent\rule{\textwidth}{5pt}
% Title with tighter spacing and bolder font
\begin{center}
{\fontsize{17}{19}\selectfont\bfseries $title$\par}
\end{center}
% Thin line below title
\noindent\rule{\textwidth}{1pt}
% Authors with tighter spacing
$for(author)$
\begin{center}
{\large\bfseries $author.name$\par}
{\normalsize $author.affiliation$\par}
{\normalsize\ttfamily $author.email$}
\vspace{0.7em}
\end{center}
$endfor$
\vspace{0.5em}
{\begin{center}\large\bfseries Abstract\end{center}}
\begin{quotation}
{\selectfont $abstract$}
\end{quotation}
$body$
\end{document}

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "mcopy",
"version": "1.8.159",
"version": "1.8.161",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mcopy",
"version": "1.8.159",
"version": "1.8.161",
"license": "MIT",
"dependencies": {
"alert": "file:app/lib/alert",

View File

@ -1,6 +1,6 @@
{
"name": "mcopy",
"version": "1.8.159",
"version": "1.8.161",
"description": "Small gauge film optical printer platform",
"main": "build.js",
"directories": {

View File

@ -1,5 +1,5 @@
{
"version": "1.8.159",
"version": "1.8.161",
"ext_port": 1111,
"profiles": {
"mcopy": {

View File

@ -1,4 +1,4 @@
include <./common.scad>;
include <./common/common.scad>;
PART="mount";

View File

@ -1,4 +1,4 @@
include <./common.scad>;
include <./common/common.scad>;
ROD_D = 25.4 * 0.75;
THREAD_D = 12;

View File

@ -1,4 +1,4 @@
include <./common.scad>;
include <./common/common.scad>;
//PINS
PIN_A = [-(18 / 2) + (1 / 2) + 4.5, 2 + (3.5 / 2)];

View File

@ -1,7 +1,7 @@
//
// JK lens assembly
//
include <./common.scad>;
include <./common/common.scad>;
include <./bellows.scad>;
include <./knurledFinishLib_v2.scad>;

View File

@ -43,6 +43,23 @@ FILTER_VOID_X = FILTER_X - 9 + ((4.5 - 2.34) * 2);
ROLLER_SPACING = 95;
MCOPY_TAKEUP_X = 130;
MCOPY_TAKEUP_Y = -85;
BearingOuterDiameter = 21.6;
BearingInnerDiameter = 8.05;
module bearing_void (pos = [0, 0, 0], rot = [0, 0, 0], width = 8, inner = false, outerPad = 0.3, innerPad = 0) {
translate (pos) rotate(rot) {
difference () {
cylinder(r = R(BearingOuterDiameter) + outerPad, h = width, center = true, $fn = 90);
if (inner) {
cylinder(r = R(BearingInnerDiameter) + innerPad, h = width + 1, center = true, $fn = 90);
}
}
}
}
module motor_shaft () {
difference () {
cylinder(r = R(MOTOR_SHAFT_D), h = MOTOR_SHAFT_H, center = true, $fn = 60);
@ -158,11 +175,11 @@ module filter_reinforcement (pos = [0, 0, 0]) {
module roller_bolts () {
translate([ROLLER_SPACING/2, 2, 0]) {
cylinder(r = R(4.25), h = 80, center = true, $fn = 40);
translate([0, 0, 7]) rotate([0, 0, 30]) m4_nut();
translate([0, 0, 7]) rotate([0, 0, 0]) m4_nut(50);
}
translate([-ROLLER_SPACING/2, 2, 0]) {
cylinder(r = R(4.25), h = 80, center = true, $fn = 40);
translate([0, 0, 7]) rotate([0, 0, 30]) m4_nut();
translate([0, 0, 7]) rotate([0, 0, 0]) m4_nut(50);
}
}
@ -187,6 +204,121 @@ module jk_takeup () {
}
}
module mcopy_bearing_mount () {
difference () {
union () {
cylinder(r = R(BearingInnerDiameter - 0.3), h = 10, center = true, $fn = 60);
translate([0, 0, 10 / 2]) cylinder(r = R(9.65), h = 2, center = true, $fn = 60);
}
cylinder(r = R(3.25), h = 20, center = true, $fn = 60);
}
}
module mcopy_takeup_bearings (pos = [0, 0, 0], rot = [0, 0, 0], CouplingD = 46) {
translate(pos) rotate(rot) {
rotate([0, 0, -40]) translate([0, (CouplingD + BearingOuterDiameter - 0.3) / 2, 0]) children();
rotate([0, 0, -140]) translate([0, (CouplingD + BearingOuterDiameter - 0.3) / 2, 0]) children();
rotate([0, 0, 95]) translate([0, (CouplingD + BearingOuterDiameter - 0.3) / 2, 0]) children();
}
}
module m3_bolt_void (pos = [0, 0, 0], Bolt = 20, Cap = 10) {
translate (pos) {
translate([0, 0, -Bolt / 2]) cylinder(r = R(3.25), h = Bolt, center = true, $fn = 40);
translate([0, 0, (Cap / 2) - 0.1]) cylinder(r = R(6.5), h = Cap, center = true, $fn = 40);
}
}
module mcopy_takeup_plate () {
Z = 2.5;
Angle = 142.45;
Rounding = 77;
CouplingD = 46;
BarrelZ = 20;
difference () {
union () {
translate([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) cylinder(r = R(Rounding), h = 11.1, center = true, $fn = 120);
translate([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) cylinder(r = R(Rounding), h = 11.1, center = true, $fn = 120);
translate([0, MCOPY_TAKEUP_Y, Z]) cube([MCOPY_TAKEUP_X * 2, Rounding, 11.1], center = true);
translate([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) {
rotate([0, 0, Angle]) translate([MCOPY_TAKEUP_X / 2, 0, 0]) cube([MCOPY_TAKEUP_X, Rounding, 11.1], center = true);
}
translate([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) {
rotate([0, 0, -Angle]) translate([-MCOPY_TAKEUP_X / 2, 0, 0]) cube([MCOPY_TAKEUP_X, Rounding, 11.1], center = true);
}
translate([0, -50, Z]) cube([AX, 100, 11.1], center = true);
translate([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, -9]) difference() {
cylinder(r = R(60), h = BarrelZ, center = true, $fn = 120);
cylinder(r = R(CouplingD), h = BarrelZ + 1, center = true, $fn = 120);
}
translate([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, -9]) difference() {
cylinder(r = R(60), h = BarrelZ, center = true, $fn = 120);
cylinder(r = R(CouplingD), h = BarrelZ + 1, center = true, $fn = 120);
}
}
translate([0, 62.4, Z]) cube([AX * 2, 100, 11.1 + 1], center = true);
translate([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) {
cylinder(r = R(CouplingD), h = 11.1 + 1, center = true, $fn = 120);
translate([-9, 0, 5]) cube([40, 30, 5], center = true);
translate([-23.75, 8.8, -2]) cylinder(r = R(6.2), h = 40, center = true, $fn = 40);
translate([-23.75, -8.8, -2]) cylinder(r = R(6.2), h = 40, center = true, $fn = 40);
}
translate([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) {
cylinder(r = R(CouplingD), h = 11.1 + 1, center = true, $fn = 120);
translate([9, 0, 5]) cube([40, 30, 5], center = true);
translate([23.75, 8.8, -2]) cylinder(r = R(6.2), h = 40, center = true, $fn = 40);
translate([23.75, -8.8, -2]) cylinder(r = R(6.2), h = 40, center = true, $fn = 40);
}
//bearings voids
mcopy_takeup_bearings([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, -13.1], [0, 0, 180], CouplingD) bearing_void(width = BarrelZ, outerPad = 0.6, innerPad = -0.3);
mcopy_takeup_bearings([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, -13.1], [0, 0, 0], CouplingD) bearing_void(width = BarrelZ, outerPad = 0.6, innerPad = -0.3);
//m3 bolt bearing voids
mcopy_takeup_bearings([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, 5], [0, 0, 180], CouplingD) m3_bolt_void();
mcopy_takeup_bearings([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, 5], [0, 0, 0], CouplingD) m3_bolt_void();
}
//motor mount plates
translate([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) intersection () {
union () {
cylinder(r = R(CouplingD) + 2, h = 11.1, center = true, $fn = 120);
translate([-10, 0, 2.1]) cube([41, 31, 7], center = true);
}
translate([0, 0, 7.315 - Z]) rotate([180, 0, 180]) minimal_mount();
}
translate([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, Z]) intersection () {
union () {
cylinder(r = R(CouplingD) + 2, h = 11.1, center = true, $fn = 120);
translate([10, 0, 2.1]) cube([41, 31, 7], center = true);
}
translate([0, 0, 7.315 - Z]) rotate([180, 0, 0]) minimal_mount();
}
//bearings mounts
mcopy_takeup_bearings([MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, -8], [0, 0, 180], CouplingD) mcopy_bearing_mount();
mcopy_takeup_bearings([-MCOPY_TAKEUP_X, MCOPY_TAKEUP_Y, -8], [0, 0, 0], CouplingD) mcopy_bearing_mount();
}
module mcopy_takeup () {
difference () {
union () {
block();
filter_holder([0, 0, -27.5]);
filter_reinforcement([0, -1.1, -16 + (5.75 / 2)]);
mcopy_takeup_plate();
}
roller_bolts();
}
}
module jk_takeup_halves (HALF = "A") {
difference () {
jk_takeup();
@ -200,7 +332,6 @@ module jk_takeup_halves (HALF = "A") {
translate([0, 0, -10 + 2]) cube([20, BY + 1, 20], center = true);
}
}
}
module idle_roller () {
@ -227,7 +358,6 @@ module idle_roller () {
cylinder(r = R(4.25), h = 20.2 + 1, center = true, $fn = 30);
translate([0, 0, (20.2 / 2) - (5 / 2)]) cylinder(r = R(10), h = 5.1, center = true, $fn = FN);
}
}
module idle_roller_cap () {
@ -236,12 +366,36 @@ module idle_roller_cap () {
cylinder(r = R(4.25), h = 20.2 + 1, center = true, $fn = 30);
translate([0, 0, 1.01]) m4_nut();
}
}
module mcopy_takeup_half (Side = "takeup") {
Width = 30;
difference () {
children();
translate ([-Width / 2, 0, 3]) {
if (Side == "takeup") {
translate([250, 0, 250]) cube([500, 500, 500], center = true);
translate([250 + Width, 0, -249.9]) cube([500, 500, 500], center = true);
} else if (Side == "feed") {
translate([-250 + Width, 0, -250]) cube([500, 500, 500], center = true);
translate([-250, 0, 249.9]) cube([500, 500, 500], center = true);
}
}
for (i = [0 : 5]) {
OffsetX = i == 0 || i == 5 ? 0 : i % 2 == 0 ? -5 : 5;
translate([0, -i * 22, 6]) {
translate([OffsetX, 0, i % 2 == 0 ? 0 : -7]) rotate ([i % 2 == 0 ? 0 : 180, 0, 0]) {
m3_bolt_void();
translate([0, 0, -9]) m3_nut(5);
}
}
}
}
}
//translate([0, 0, 40]) color("red") original_takeup();
PART = "jk_takeup";
PART = "mcopy_takeup_feed";
if (PART == "slip_coupling") {
slip_coupling();
@ -266,6 +420,12 @@ if (PART == "slip_coupling") {
jk_takeup_halves("B");
} else if (PART == "idle_roller") {
idle_roller();
} else if (PART == "mcopy_takeup") {
rotate([180, 0, 0]) mcopy_takeup();
} else if (PART == "mcopy_takeup_takeup") {
rotate([180, 0, 0]) mcopy_takeup_half(Side = "takeup") mcopy_takeup();
} else if (PART == "mcopy_takeup_feed") {
rotate([180, 0, 0]) mcopy_takeup_half(Side = "feed") mcopy_takeup();
} else {
debug_assembled();
}

View File

@ -1,4 +1,4 @@
include <./common.scad>;
include <./common/common.scad>;
/*
CynKen 1Pcs Optical Glass RGB Dispersion Prism X-CUBE for Physics Teach Decoration Art

View File

@ -1,4 +1,4 @@
include <./common.scad>;
include <./common/common.scad>;
include <./knurledFinishLib_v2.scad>
include <./arduino.scad>

@ -1 +1 @@
Subproject commit dbb3eca85a46c0474c7e68e7febf43db508b53a8
Subproject commit 6067dedb861e64a1203a4c5bedae7ebebaae6145