Files
caperren-com/src/pages/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate.astro
Corwin Perren ec6cfba9ba
All checks were successful
Build and Test - Staging / test (pull_request) Successful in 6m24s
Build and Test - Staging / build_and_push (pull_request) Successful in 5m23s
Build and Test - Staging / deploy_staging (pull_request) Successful in 2s
Content for mars rover software lead and embryo pick and plate, small padding tweak to printed circuit board notes
2025-12-17 20:05:12 -08:00

317 lines
14 KiB
Plaintext

---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
import H2 from "@components/H2.astro";
import H3 from "@components/H3.astro";
import Li from "@components/Li.astro";
import CustomCarousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import Video from "@components/Media/Video.astro";
import PageGroup from "@components/PageGroup.astro";
import Paragraph from "@components/Paragraph.astro";
import Paragraphs from "@components/Paragraphs.astro";
import PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
import PrintedCircuitBoard from "@components/PrintedCircuitBoard.astro";
import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro";
import Timeline from "@components/Timeline/Timeline.astro";
import Ul from "@components/Ul.astro";
import type { carouselGroup } from "@interfaces/image-carousel.ts";
import { timelineFromPrintedCircuitBoard } from "@interfaces/printed-circuit-board.ts";
import type { categorySkills } from "@interfaces/skill-matrix.ts";
import type { timelineEntry } from "@interfaces/timeline.ts";
import {
subTitles,
workingTimeline,
} from "./osu-sinnhuber-aquatic-research-laboratory.ts";
import {
pnpControl,
pnpLights,
} from "./zebrafish-embryo-pick-and-plate-pcbs.ts";
import installation_and_tuning from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/installation-and-tuning.jpg";
import interface_tuning_and_detection from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/interface-tuning-and-detection.png";
import off_controls_lid_overview from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-controls-lid-overview.jpg";
import off_controls_syringe_overview from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-controls-syringe-overview.jpg";
import off_controls_top_overview from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-controls-top-overview.jpg";
import off_front_working_area_overview from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-front-working-area-overview.jpg";
import off_front from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-front.jpg";
import off_left from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-left.jpg";
import off_lighting from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-lighting.jpg";
import off_rear from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-rear.jpg";
import off_right from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-right.jpg";
import off_touchoff from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/off-touchoff.jpg";
import on_dishes_lighting_reflection from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/on-dishes-lighting-reflection.jpg";
import on_front_dishes_beakers from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/on-front-dishes-beakers.jpg";
import on_front_overview from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/on-front-overview.jpg";
import on_front from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/on-front.jpg";
import on_screen from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/on-screen.jpg";
import on_touchoff_block_isometric from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/on-touchoff-block-isometric.jpg";
import pick_and_placing from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pick-and-placing.mp4";
import precision_homing from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/precision-homing.mp4";
import InlineLink from "@components/InlineLink.astro";
import { DateTime } from "luxon";
const headerCarouselGroup: carouselGroup = {
animation: "slide",
images: [
installation_and_tuning,
on_front_overview,
interface_tuning_and_detection,
on_front,
on_front_dishes_beakers,
on_screen,
off_touchoff,
on_touchoff_block_isometric,
off_controls_top_overview,
off_controls_syringe_overview,
off_controls_lid_overview,
off_front,
off_front_working_area_overview,
off_left,
off_rear,
off_right,
off_lighting,
on_dishes_lighting_reflection,
],
};
const timeline: timelineEntry[] = [
...workingTimeline,
...timelineFromPrintedCircuitBoard(pnpLights),
...timelineFromPrintedCircuitBoard(pnpControl),
{
event: "Project Started",
eventDetail: "Initial Requirements Given",
date: DateTime.fromISO("2013-12-01"),
},
{
event: "Project Finished",
eventDetail: "Delivered Units to Lab",
date: DateTime.fromISO("2016-09-01"),
},
];
const categorizedSkills: categorySkills[] = [
{
category: "Software & Environments",
skills: [
{
item: "Version Control",
subItems: [{ item: "Git" }],
},
{
item: "Programming",
subItems: [
{
item: "Languages",
subItems: [
{ item: "Python 2" },
{ item: "Bash Shell Scripting" },
{ item: "Low-Level Embedded C/C++ (Atmel Studio)" },
],
},
{
item: "Frameworks",
subItems: [{ item: "OpenCV" }, { item: "Qt" }],
},
],
},
{
item: "Operating Systems",
subItems: [
{
item: "Linux",
subItems: [{ item: "Debian" }],
},
{ item: "Microsoft Windows" },
],
},
],
},
{
category: "Electrical",
skills: [
{
item: "Schematic & PCB Design",
subItems: [
{
item: "Software",
subItems: [
{ item: "Altium Designer" },
{ item: "Mentor Graphics PADS" },
],
},
{
item: "Manufacturing",
subItems: [
{ item: "Gerber Export" },
{ item: "BOM Management" },
{ item: "In-House Assembly" },
],
},
],
},
{
item: "Electrical Diagnostics",
subItems: [
{ item: "Multimeters" },
{ item: "Electronic Loads" },
{ item: "Oscilloscopes" },
],
},
{
item: "Harnessing Fabrication",
subItems: [{ item: "DC Low-Power & Signal" }],
},
],
},
{
category: "Mechanical",
skills: [
{
item: "Fabrication",
subItems: [{ item: "CNC" }, { item: "Hand Tools" }],
},
],
},
];
const videos: string[] = [pick_and_placing, precision_homing];
---
<ExperienceLayout title="Zebrafish Embryo Pick and Plate" subTitles={subTitles}>
<CustomCarousel carouselGroup={headerCarouselGroup} />
<PageGroup>
<Fragment slot="header"><H2>Summary</H2></Fragment>
<PageGroup>
<Fragment slot="header"><H3>Timeline</H3></Fragment>
<Timeline timeline={timeline} />
</PageGroup>
<PageGroup>
<Fragment slot="header"><H3>Key Takeaways</H3></Fragment>
<Ul>
<Li
>Delivered a design, and multiple built units, of a custom embryo
pick-and-plate machine</Li
>
<Li>Reduced cost from ~$150,000 for previous generation to ~$10,000</Li>
<Li
>Reduced the size from 4.5'x4.5'x8' for previous generation to
1'x1'x1.5'</Li
>
</Ul>
</PageGroup>
<SkillMatrix categorizedSkills={categorizedSkills} />
</PageGroup>
<PageGroup>
<Fragment slot="header"><H2>Details</H2></Fragment>
<Paragraphs>
<Paragraph>
For some quick context on why such a machine was even needed, the
Sinnhuber Aquatic Research Lab performs toxicology research using
Zebrafish. This means tha the lab is also a breeding facility,
generating a few thousand eggs a day, which need to be processed and
isolated prior to being introduced to experimental conditions. At one
point in time, these processes were done by hand, with all researchers
spending a significant portion of their day simply prepping the embryos.
Later on, they hired a contractor to design an automated solution to the
isolation problem, and while they delivered, the units were industrial
overkill, using massive <PopoverWordDefinition key="SCARA" /> arms and enclosures
to pick up embryos which were roughly half a millimeter in diameter. They
were also very expensive, costing around $150k per machine, and the lab had
four installed. Thus, the engineering team was tasked with cost and size reducing
them so that more could fit in the same space and throughput could be higher.
</Paragraph>
<Paragraph>
My coworker, <InlineLink href="https://dylanthrush.com"
>Dylan Thrush</InlineLink
>, and I got to work. He focussed on the mechanical side, while I worked
on electrical and software. I had recently been learning PCB design
after becoming more familiar with it through the OSU robotics club, and
decided that a good place to start would be to create a motion
controller. Dylan and I had already landed on a simple stepper-motor
based system to more than meet the needs of a task like this, and both
of us already had experience with stepper-based CNC machines, making it
a great jumpoff point. My first PCB was unfortunately a massive failure,
because while I did include a quad stepper motor driver,
microcontroller, general purpose I/O, and usb to serial interface, I
failed to export the gerbers correctly. This resulted in a PCB with no
drills, making it completely useless (outside of a good learning
experience)! It was also just a poor layout overall, which isn't
surprising considering it was my first ever PCB design. If you want to
see this embarrassing result, check out the PCB section at the end of
this page!
</Paragraph>
<Paragraph>
For the second revision, we'd made some progress in other places, but
most importantly had decided that we would use a <InlineLink
href="https://www.beagleboard.org/boards/beaglebone-black"
>Beaglebone Black</InlineLink
> single-board-computer to run the whole system. In an effort to simplify
the assembly, I decided that the next revision would include headers to directly
mount the Beaglebone to the unit, providing power and a serial interface over
those pins. This version actually worked as expected, with only a few very
minor bodges to the microcontroller's crystal, and some bulk capacitance on
the power input. Since things were working, I began writing embedded C to
control motion through some higher-level interfaces. Not long into this process,
I realized I might have bitten off more than I could chew. Not only was I
having to learn the deep ins and outs of microcontroller programming, kinematics,
and serial interfaces, but I would still have to greatly improve my Python
skills, learn to create graphical user interfaces, and figure out how to detect
embryos using a camera and computer vision. While I was sad to scrap this,
we decided to fall back on a motion controller called <InlineLink
href="https://synthetos.com/project/tinyg">TinyG</InlineLink
>, which would simply require gcode to be sent over serial to function.
</Paragraph>
<Paragraph>
Dylan built up a mechanical testbed, which we could mount a camera to,
and I began to focus on embryo detection. I was relatively new to
Python, but quickly found the Qt framework for building decent-looking
interfaces, and OpenCV for providing generic detection capabilities via
webcams. Over the next few years (remember, we were students doing this
part time, and working on other projects simultaneously), I eventually
created a fairly comprehensive user interface that would allow
researchers to tune detection and motion parameters on-the-fly. This was
shown on a touchscreen that the beaglebone plugged into, making it quite
intuitive. Dylan had also created a mechanical foundation providing
repeatable alignment for a petri dish with embryos, the 96-well plate
for placement, and a waste container to get rid of extra water in our
metal pipette tip that would be used to pick up the embryos. I'd also
created some very bright lighting boards to mount to the unit's
extrusion, illuminating the embryos from the side, something that was
absolutely required for consistent detection with the camera. After a
long journey, we finally delivered multiple units to the lab! Seeing
such small devices performing the same task next to the behemoths which
were the prior versions was quite amusing. You could easily fit a two by
two grid of these in the working area of each of those machines.
Overall, this was a highly ambitious project, but it developed some of
my most successful skills I gained while at OSU while accelerating the
research at the lab!
</Paragraph>
</Paragraphs>
</PageGroup>
<PageGroup>
<Fragment slot="header"><H2>Videos</H2></Fragment>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
{
videos.map((video) => (
<Video
videoPath={video}
autoPlay={true}
loop={true}
playsInline={true}
/>
))
}
</div>
</PageGroup>
<PageGroup>
<Fragment slot="header"><H2>Printed Circuit Boards</H2></Fragment>
<PrintedCircuitBoard pcb={pnpLights} />
<PrintedCircuitBoard pcb={pnpControl} />
</PageGroup>
</ExperienceLayout>