Merge pull request 'mars rover and embryo pick and plate content' (#19) from website-content-updates into main
Reviewed-on: #19
4
Makefile
@@ -84,7 +84,9 @@ convert_video_times:
|
|||||||
-init_hw_device vaapi=va:/dev/dri/renderD128 \
|
-init_hw_device vaapi=va:/dev/dri/renderD128 \
|
||||||
-filter_hw_device va \
|
-filter_hw_device va \
|
||||||
-i $(input) \
|
-i $(input) \
|
||||||
-vf 'format=nv12,hwupload,scale_vaapi=-2:720,trim=start=$(start):end=$(end)' \
|
-ss $(start) \
|
||||||
|
-to $(end) \
|
||||||
|
-vf 'format=nv12,hwupload,scale_vaapi=-2:720' \
|
||||||
-c:v h264_vaapi \
|
-c:v h264_vaapi \
|
||||||
-rc_mode CQP \
|
-rc_mode CQP \
|
||||||
-qp 28 \
|
-qp 28 \
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ Altium
|
|||||||
ASSEM
|
ASSEM
|
||||||
astrojs
|
astrojs
|
||||||
Atmel
|
Atmel
|
||||||
|
automations
|
||||||
barebones
|
barebones
|
||||||
|
beaglebone
|
||||||
Bitwarden
|
Bitwarden
|
||||||
Candian
|
Candian
|
||||||
caperren
|
caperren
|
||||||
@@ -24,6 +26,8 @@ ELMI
|
|||||||
fhhs
|
fhhs
|
||||||
flowbite
|
flowbite
|
||||||
flowrate
|
flowrate
|
||||||
|
gcode
|
||||||
|
gerbers
|
||||||
Gitea
|
Gitea
|
||||||
HDFS
|
HDFS
|
||||||
headshot
|
headshot
|
||||||
@@ -38,15 +42,20 @@ leconte
|
|||||||
Loctite
|
Loctite
|
||||||
luxon
|
luxon
|
||||||
MGMT
|
MGMT
|
||||||
|
microcontroller
|
||||||
|
microcontroller's
|
||||||
Micropumps
|
Micropumps
|
||||||
Millis
|
Millis
|
||||||
|
modbus
|
||||||
Mokai
|
Mokai
|
||||||
Multimeters
|
Multimeters
|
||||||
nixos
|
nixos
|
||||||
|
nvme
|
||||||
offroad
|
offroad
|
||||||
Onshape
|
Onshape
|
||||||
OSSM
|
OSSM
|
||||||
OSURC
|
OSURC
|
||||||
|
panelized
|
||||||
Passthroughs
|
Passthroughs
|
||||||
pcbs
|
pcbs
|
||||||
Perren
|
Perren
|
||||||
@@ -58,8 +67,10 @@ RFID
|
|||||||
Rito
|
Rito
|
||||||
RSSI
|
RSSI
|
||||||
SARL
|
SARL
|
||||||
|
SCARA
|
||||||
showerheads
|
showerheads
|
||||||
Shuttlebox
|
Shuttlebox
|
||||||
|
simplemotion
|
||||||
sinnhuber
|
sinnhuber
|
||||||
sitemapindex
|
sitemapindex
|
||||||
Smartsheet
|
Smartsheet
|
||||||
@@ -71,9 +82,11 @@ Steller
|
|||||||
Tanguay
|
Tanguay
|
||||||
Teamcenter
|
Teamcenter
|
||||||
timelapse
|
timelapse
|
||||||
|
touchoff
|
||||||
triaging
|
triaging
|
||||||
trivago
|
trivago
|
||||||
Truong
|
Truong
|
||||||
|
Ubiquiti
|
||||||
Unstow
|
Unstow
|
||||||
uuidv
|
uuidv
|
||||||
vaapi
|
vaapi
|
||||||
|
|||||||
|
After Width: | Height: | Size: 4.7 MiB |
|
After Width: | Height: | Size: 1013 KiB |
|
After Width: | Height: | Size: 6.8 MiB |
|
After Width: | Height: | Size: 9.2 MiB |
|
After Width: | Height: | Size: 8.8 MiB |
|
Before Width: | Height: | Size: 8.5 MiB After Width: | Height: | Size: 8.5 MiB |
|
After Width: | Height: | Size: 6.3 MiB |
|
After Width: | Height: | Size: 1017 KiB |
|
After Width: | Height: | Size: 878 KiB |
|
After Width: | Height: | Size: 7.1 MiB |
|
After Width: | Height: | Size: 605 KiB |
|
After Width: | Height: | Size: 826 KiB |
|
After Width: | Height: | Size: 7.1 MiB |
|
After Width: | Height: | Size: 6.1 MiB |
|
After Width: | Height: | Size: 6.9 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 8.3 MiB |
|
After Width: | Height: | Size: 7.5 MiB |
|
After Width: | Height: | Size: 7.2 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 4.6 MiB |
|
After Width: | Height: | Size: 4.6 MiB |
|
After Width: | Height: | Size: 4.4 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 438 KiB |
|
After Width: | Height: | Size: 224 KiB |
|
After Width: | Height: | Size: 437 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
5
src/components/H4.astro
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<h4 class="md:text-md text-xs sm:text-sm"><slot /></h4>
|
||||||
@@ -11,6 +11,7 @@ const keys: { [key: string]: string } = {
|
|||||||
GUI: "Graphical user interface",
|
GUI: "Graphical user interface",
|
||||||
NUC: "A small and low-power computer made by Intel",
|
NUC: "A small and low-power computer made by Intel",
|
||||||
PCBs: "Printed circuit boards",
|
PCBs: "Printed circuit boards",
|
||||||
|
SCARA: "Selective Compliance Assembly Robot Arm",
|
||||||
TDD: "Test driven development",
|
TDD: "Test driven development",
|
||||||
UPS: "Uninterruptible power supply",
|
UPS: "Uninterruptible power supply",
|
||||||
VISA: "Virtual instrument software architecture",
|
VISA: "Virtual instrument software architecture",
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
|
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
|
||||||
import Ul from "@components/Ul.astro";
|
import Ul from "@components/Ul.astro";
|
||||||
|
|
||||||
|
import H3 from "@components/H3.astro";
|
||||||
|
import H4 from "@components/H4.astro";
|
||||||
|
import PageGroup from "@components/PageGroup.astro";
|
||||||
import type {
|
import type {
|
||||||
printedCircuitBoard,
|
printedCircuitBoard,
|
||||||
printedCircuitBoardRevision,
|
printedCircuitBoardRevision,
|
||||||
@@ -19,33 +22,37 @@ const semanticPcbRevisionSort = (
|
|||||||
-((a.major - b.major) * 100 + (a.minor - b.minor) * 10 + (a.patch - b.patch));
|
-((a.major - b.major) * 100 + (a.minor - b.minor) * 10 + (a.patch - b.patch));
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
<PageGroup>
|
||||||
{
|
<Fragment slot="header"
|
||||||
pcb.revisions?.sort(semanticPcbRevisionSort).map((revision) => (
|
><H3>{pcb.name}</H3><H4>{pcb.description}</H4></Fragment
|
||||||
<div class="border-caperren-green block space-y-2 rounded-lg border bg-black py-2">
|
>
|
||||||
<div class="border-caperren-green flex flex-wrap items-center justify-between rounded-none border-b px-4 pb-2">
|
<div class="mt-1 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<div>
|
{
|
||||||
<span class="font-black">Revision:</span>
|
pcb.revisions?.sort(semanticPcbRevisionSort).map((revision) => (
|
||||||
<span>
|
<div class="border-caperren-green block space-y-2 rounded-lg border bg-black py-2">
|
||||||
{revision.major}.{revision.minor}.{revision.patch}
|
<div class="border-caperren-green flex flex-wrap items-center justify-between rounded-none border-b px-4 pb-2">
|
||||||
</span>
|
<div>
|
||||||
|
<span class="font-black">Revision:</span>
|
||||||
|
<span>
|
||||||
|
{revision.major}.{revision.minor}.{revision.patch}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm italic">{revision.date.toISODate()}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm italic">{revision.date.toISODate()}</div>
|
<div class="px-4">
|
||||||
|
<Carousel
|
||||||
|
class=""
|
||||||
|
carouselGroup={{ images: revision.images }}
|
||||||
|
showBorder={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{revision.notes && revision.notes.length > 0 && (
|
||||||
|
<div class="border-caperren-green border-t px-4 pt-4 pb-2 text-sm">
|
||||||
|
<Ul lineItems={revision.notes} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="px-4">
|
))
|
||||||
<Carousel
|
}
|
||||||
class=""
|
</div>
|
||||||
carouselGroup={{ images: revision.images }}
|
</PageGroup>
|
||||||
showBorder={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{revision.notes && revision.notes.length > 0 && (
|
|
||||||
<Ul
|
|
||||||
class="border-caperren-green border-t p-4 text-sm"
|
|
||||||
lineItems={revision.notes}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ export const siteLayout: navLink[] = [
|
|||||||
placeholderEntry: true,
|
placeholderEntry: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: false,
|
|
||||||
navText: "Zebrafish Embryo Pick and Plate",
|
navText: "Zebrafish Embryo Pick and Plate",
|
||||||
isSubItem: true,
|
isSubItem: true,
|
||||||
path: "zebrafish-embryo-pick-and-plate",
|
path: "zebrafish-embryo-pick-and-plate",
|
||||||
@@ -81,12 +80,10 @@ export const siteLayout: navLink[] = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: false,
|
|
||||||
navText: "OSU Robotics Club",
|
navText: "OSU Robotics Club",
|
||||||
path: "osu-robotics-club",
|
path: "osu-robotics-club",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
enabled: false,
|
|
||||||
navText: "Mars Rover Software Team Lead",
|
navText: "Mars Rover Software Team Lead",
|
||||||
path: "mars-rover-software-team-lead",
|
path: "mars-rover-software-team-lead",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,20 +11,34 @@ import type { videoConfig } from "@interfaces/video.ts";
|
|||||||
|
|
||||||
import { roverSubTitles } from "./osu-robotics-club.ts";
|
import { roverSubTitles } from "./osu-robotics-club.ts";
|
||||||
|
|
||||||
|
import H3 from "@components/H3.astro";
|
||||||
|
import Li from "@components/Li.astro";
|
||||||
|
|
||||||
|
import Video from "@components/Media/Video.astro";
|
||||||
|
import Paragraph from "@components/Paragraph.astro";
|
||||||
|
import Paragraphs from "@components/Paragraphs.astro";
|
||||||
|
import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro";
|
||||||
|
import Timeline from "@components/Timeline/Timeline.astro";
|
||||||
|
import Ul from "@components/Ul.astro";
|
||||||
|
import type { categorySkills } from "@interfaces/skill-matrix.ts";
|
||||||
|
import type { timelineEntry } from "@interfaces/timeline.ts";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
import circ_champions from "@assets/experience/osu-robotics-club/mars-rover-software-lead/circ-champions.jpg";
|
import circ_champions from "@assets/experience/osu-robotics-club/mars-rover-software-lead/circ-champions.jpg";
|
||||||
import corwin_at_competition from "@assets/experience/osu-robotics-club/mars-rover-software-lead/corwin-at-competition.jpg";
|
import corwin_at_competition from "@assets/experience/osu-robotics-club/mars-rover-software-lead/corwin-at-competition.jpg";
|
||||||
import drumheller_team_photo from "@assets/experience/osu-robotics-club/mars-rover-software-lead/drumheller-team-photo.jpg";
|
import drumheller_team_photo from "@assets/experience/osu-robotics-club/mars-rover-software-lead/drumheller-team-photo.jpg";
|
||||||
import final_ground_station_gui from "@assets/experience/osu-robotics-club/mars-rover-software-lead/final-ground-station-gui.png";
|
import final_ground_station_gui from "@assets/experience/osu-robotics-club/mars-rover-software-lead/final-ground-station-gui.png";
|
||||||
import ground_station_at_competition from "@assets/experience/osu-robotics-club/mars-rover-software-lead/ground-station-at-competition.jpg";
|
import ground_station_at_competition from "@assets/experience/osu-robotics-club/mars-rover-software-lead/ground-station-at-competition.jpg";
|
||||||
import iris_pcb_assembly_timelapse_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse-converted.mp4";
|
import iris_pcb_assembly_timelapse_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse.mp4";
|
||||||
import iris_pcb_working from "@assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-working.jpg";
|
import iris_pcb_working from "@assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-working.jpg";
|
||||||
import rover_at_competition_from_above from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-at-competition-from-above.jpg";
|
import rover_at_competition_from_above from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-at-competition-from-above.jpg";
|
||||||
import rover_at_competition_pickup_test from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-at-competition-pickup-test.jpg";
|
import rover_at_competition_pickup_test from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-at-competition-pickup-test.jpg";
|
||||||
import rover_gimbal_test_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test-converted.mp4";
|
import rover_gimbal_test_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test.mp4";
|
||||||
import rover_pose_with_dinosaur from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-pose-with-dinosaur.jpg";
|
import rover_pose_with_dinosaur from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-pose-with-dinosaur.jpg";
|
||||||
import rover_with_arm_pose_in_desert from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-with-arm-pose-in-desert.jpg";
|
import rover_with_arm_pose_in_desert from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-with-arm-pose-in-desert.jpg";
|
||||||
|
import senior_design_fair from "@assets/experience/osu-robotics-club/mars-rover-software-lead/senior-design-fair.jpg";
|
||||||
import silly_poke from "@assets/experience/osu-robotics-club/mars-rover-software-lead/silly-poke.gif";
|
import silly_poke from "@assets/experience/osu-robotics-club/mars-rover-software-lead/silly-poke.gif";
|
||||||
import Video from "@components/Media/Video.astro";
|
import LinkButton from "@components/LinkButton.astro";
|
||||||
|
|
||||||
const headerCarouselGroup: carouselGroup = {
|
const headerCarouselGroup: carouselGroup = {
|
||||||
animation: "slide",
|
animation: "slide",
|
||||||
@@ -36,6 +50,7 @@ const headerCarouselGroup: carouselGroup = {
|
|||||||
corwin_at_competition,
|
corwin_at_competition,
|
||||||
rover_at_competition_from_above,
|
rover_at_competition_from_above,
|
||||||
rover_at_competition_pickup_test,
|
rover_at_competition_pickup_test,
|
||||||
|
senior_design_fair,
|
||||||
final_ground_station_gui,
|
final_ground_station_gui,
|
||||||
ground_station_at_competition,
|
ground_station_at_competition,
|
||||||
iris_pcb_working,
|
iris_pcb_working,
|
||||||
@@ -43,17 +58,254 @@ const headerCarouselGroup: carouselGroup = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const timeline: timelineEntry[] = [
|
||||||
|
{
|
||||||
|
event: "Project Started",
|
||||||
|
eventDetail: "Design Work Begins",
|
||||||
|
date: DateTime.fromISO("2017-09-01"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: "Senior Design Presentation",
|
||||||
|
eventDetail: "Senior Design Fair",
|
||||||
|
date: DateTime.fromISO("2018-05-18"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: "Won 1st Place!",
|
||||||
|
eventDetail: "CIRC",
|
||||||
|
date: DateTime.fromISO("2018-08-13"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: "Project Finished",
|
||||||
|
eventDetail: "Final Documentation Complete",
|
||||||
|
date: DateTime.fromISO("2018-08-31"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const categorizedSkills: categorySkills[] = [
|
||||||
|
{
|
||||||
|
category: "Software & Environments",
|
||||||
|
skills: [
|
||||||
|
{
|
||||||
|
item: "Version Control",
|
||||||
|
subItems: [{ item: "Git" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: "Programming",
|
||||||
|
subItems: [
|
||||||
|
{
|
||||||
|
item: "Languages",
|
||||||
|
subItems: [
|
||||||
|
{ item: "Python 2" },
|
||||||
|
{ item: "C++" },
|
||||||
|
{ item: "Bash Shell Scripting" },
|
||||||
|
{ item: "High-Level Embedded C/C++ (Arduino/Teensy)" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: "Frameworks",
|
||||||
|
subItems: [{ item: "OpenCV" }, { item: "Qt" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: "Operating Systems",
|
||||||
|
subItems: [
|
||||||
|
{
|
||||||
|
item: "Linux",
|
||||||
|
subItems: [{ item: "Ubuntu" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "Electrical",
|
||||||
|
skills: [
|
||||||
|
{
|
||||||
|
item: "Schematic & PCB Design",
|
||||||
|
subItems: [
|
||||||
|
{
|
||||||
|
item: "Software",
|
||||||
|
subItems: [{ item: "Altium Designer" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: "PCB Assembly & Rework",
|
||||||
|
subItems: [
|
||||||
|
{ item: "Handheld Soldering" },
|
||||||
|
{ item: "Handheld Hot-Air Reflow" },
|
||||||
|
{ item: "Oven Reflow" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: "Electrical Diagnostics",
|
||||||
|
subItems: [
|
||||||
|
{ item: "Multimeters" },
|
||||||
|
{ item: "Electronic Loads" },
|
||||||
|
{ item: "Oscilloscopes" },
|
||||||
|
{ item: "Logic Analyzers" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
item: "Harnessing Fabrication",
|
||||||
|
subItems: [{ item: "DC Power & Signal" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const videos: videoConfig[] = [
|
const videos: videoConfig[] = [
|
||||||
{ videoPath: iris_pcb_assembly_timelapse_converted },
|
{ videoPath: iris_pcb_assembly_timelapse_converted },
|
||||||
{ videoPath: rover_gimbal_test_converted },
|
{ videoPath: rover_gimbal_test_converted },
|
||||||
{ videoPath: "https://www.youtube-nocookie.com/embed/ZjGW-HWapVA" },
|
{ videoPath: "https://www.youtube-nocookie.com/embed/ZjGW-HWapVA" },
|
||||||
{ videoPath: "https://www.youtube-nocookie.com/embed/sceA2ZbEV8Y0" },
|
{ videoPath: "https://www.youtube-nocookie.com/embed/sceA2ZbEV8Y" },
|
||||||
];
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<ExperienceLayout title="Software Team Lead" subTitles={roverSubTitles}>
|
<ExperienceLayout title="Software Team Lead" subTitles={roverSubTitles}>
|
||||||
<Carousel carouselGroup={headerCarouselGroup} />
|
<Carousel carouselGroup={headerCarouselGroup} />
|
||||||
|
<div class="grid grid-flow-row place-content-center gap-4 md:grid-flow-col">
|
||||||
|
<LinkButton
|
||||||
|
href="https://github.com/OSURoboticsClub/Rover_2017_2018"
|
||||||
|
title="Rover and Ground Station Code"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<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>Won 1st place in an international competition</Li>
|
||||||
|
<Li
|
||||||
|
>Wrote software in Python and C++ for the Rover's onboard computer</Li
|
||||||
|
>
|
||||||
|
<Li
|
||||||
|
>Wrote firmware in embedded C/C++ for the Rover's distributed
|
||||||
|
microcontroller sub-systems</Li
|
||||||
|
>
|
||||||
|
<Li
|
||||||
|
>Hand-assembled most of the custom PCBs for the Rover's distributed
|
||||||
|
microcontroller sub-systems</Li
|
||||||
|
>
|
||||||
|
<Li>Hand-fabricated much of the custom harnessing on the Rover</Li>
|
||||||
|
<Li>Piloted the Rover during some competition events</Li>
|
||||||
|
</Ul>
|
||||||
|
</PageGroup>
|
||||||
|
<SkillMatrix categorizedSkills={categorizedSkills} />
|
||||||
|
</PageGroup>
|
||||||
|
<PageGroup>
|
||||||
|
<Fragment slot="header"><H2>Details</H2></Fragment>
|
||||||
|
<PageGroup>
|
||||||
|
<Fragment slot="header"><H3>My Experience</H3></Fragment>
|
||||||
|
<Paragraphs>
|
||||||
|
<Paragraph>
|
||||||
|
I had not originally planned to be software lead for this Rover year,
|
||||||
|
as I was already working two part time jobs and going to school
|
||||||
|
full-time, but after my best friend Nick decided to become team and
|
||||||
|
electrical lead, and my other best friend Dylan would create the
|
||||||
|
rover's arm for his senior design project, I just couldn't say no.
|
||||||
|
This also came hot off the heels of me being the emergency software
|
||||||
|
lead for Rover the previous year, writing enough code in the nine days
|
||||||
|
before competition to at least give them a fighting chance, which they
|
||||||
|
had, so I was even more prepped and ready. I only had one hard
|
||||||
|
requirement, joining as the software lead, and it was that we would
|
||||||
|
have to create a serious ground station setup. When I first joined the
|
||||||
|
robotics club in 2011, I did so because I was enraptured by the rover,
|
||||||
|
but especially its ground station, which was a full-screen display
|
||||||
|
full of stats, indicators, and buttons that got the nerd in me
|
||||||
|
excited. If I was going to go all-in, I was going to do the same, and
|
||||||
|
ended up making the ground station software my university senior
|
||||||
|
design project.
|
||||||
|
</Paragraph>
|
||||||
|
<Paragraph>
|
||||||
|
The upcoming year of work turned out to be some of the most intense I
|
||||||
|
ever had at OSU, mostly self-inflicted due to not wanting to let this
|
||||||
|
opportunity get wasted. It's worth noting, that not only was I writing
|
||||||
|
the ground station software, but also the software running on the
|
||||||
|
rover's onboard Jetson TX2 computer, all the firmware for each of the
|
||||||
|
many distributed systems, on top of also hand-assembling/debugging
|
||||||
|
most of the rover's PCBs, and creating many of its electrical wiring
|
||||||
|
harnesses. In total, I put in over 2000 hours of work on this project,
|
||||||
|
while working two part-time jobs and taking classes. It was a lot,
|
||||||
|
but, it also turned out to be my proudest achievement while at OSU, so
|
||||||
|
I'd argue it was worth it!
|
||||||
|
</Paragraph>
|
||||||
|
<Paragraph>
|
||||||
|
After these countless hours, what resulted was some incredibly robust
|
||||||
|
hardware and software, which didn't crash, and which allowed us to
|
||||||
|
absolutely crush the competition at the Canadian International Rover
|
||||||
|
Challenge in Drumheller, Alberta, Canada. We won first place, with a
|
||||||
|
final score of 287 points. The second best team got 159, so it wasn't
|
||||||
|
even close! On top of doing that well, the software was also feature
|
||||||
|
complete by halfway through the competition, which was no small feat
|
||||||
|
considering the amount of scope creep a project like this tends to
|
||||||
|
encounter. I was particularly proud of the ground station by this
|
||||||
|
point as well. Not only was it a treasure trove of information about
|
||||||
|
the Rover's state, but included live GPS mapping, multiple switchable
|
||||||
|
camera views with pan/tilt capabilities and quality-switching,
|
||||||
|
artificial speed limiting, and automations to automatically complete
|
||||||
|
some of the tasks from the competition with just a few button presses.
|
||||||
|
Considering the robotics team hadn't placed over 3rd since before I'd
|
||||||
|
started in 2011, finally getting a first place win was a breath of
|
||||||
|
fresh air, and made it much more cathartic when graduating the
|
||||||
|
following year.
|
||||||
|
</Paragraph>
|
||||||
|
</Paragraphs>
|
||||||
|
</PageGroup>
|
||||||
|
<PageGroup>
|
||||||
|
<Fragment slot="header"><H3>Technical Overview</H3></Fragment>
|
||||||
|
<Paragraphs>
|
||||||
|
<Paragraph>
|
||||||
|
The ground station itself contained an Intel NUC with a Core i5, 16GB
|
||||||
|
ram, nvme ssd, and was connected to two 23″ 1080p monitors. I chose
|
||||||
|
two so we would be able to see all primary Rover systems without
|
||||||
|
having to swap between tabs or pages, which I’d had to do on some
|
||||||
|
other software I’d written and knew wouldn’t be efficient when we were
|
||||||
|
in the middle of a timed event. The desktop ran Ubuntu 16.04 with the
|
||||||
|
ROS2 stack. For the UI, PyQt was used, allowing for easy tweaking
|
||||||
|
using QtCreator, and which provided access to QtSignals, a feature
|
||||||
|
that made simple cross-thread communication much easier in Python. The
|
||||||
|
Python code itself was Python 2, which was a limitation of the ROS2
|
||||||
|
stack. Control of the rover was done via USB xbox controllers, plus a
|
||||||
|
keyboard and mouse.
|
||||||
|
</Paragraph>
|
||||||
|
<Paragraph>
|
||||||
|
The Rover itself ran on an NVidia Jetson TX2 single-board computer
|
||||||
|
powered from a 500Wh li-on battery. The electronics box also contained
|
||||||
|
a fuse box, power cutoff, network switch, battery backup, composite to
|
||||||
|
network video converter, usb hub, FrSky controller receiver, and
|
||||||
|
custom usb->RS485 adapter board. The TX2 ran Ubuntu 16.04 with the
|
||||||
|
ROS2 stack, just like the ground station. All remote control boards on
|
||||||
|
the Rover were communicated to using the modbus protocol over RS485.
|
||||||
|
Interfacing with the arm was achieved via RS485 as well, but using the
|
||||||
|
custom simplemotion control library provided by the motor controller
|
||||||
|
company. Using linux UDEV rules, usb->serial and cameras were
|
||||||
|
symlinked to custom, repeatable names at /dev/rover/name so that
|
||||||
|
devices could be accessed identically after reboots. Custom ROS nodes
|
||||||
|
were written for each system to be controlled, and the whole Rover ROS
|
||||||
|
package set to start automatically at boot. The Rover could be
|
||||||
|
controlled with an FrSky X9D controller whether the ground station was
|
||||||
|
running or not. The controller could also override all other control
|
||||||
|
inputs on-the-fly by flipping a switch on the controller. This was a
|
||||||
|
safety feature to ensure runaway ground station or autonomy code
|
||||||
|
wouldn’t allow the Rover to take off on its own. Conversely, the Rover
|
||||||
|
would also work without the controller powered on, but would
|
||||||
|
immediately allow for this override if turned on at any time.
|
||||||
|
Communication with the ground station was done using two Ubiquiti
|
||||||
|
Rocket M2 long-range wifi radios, along with their 10dB
|
||||||
|
omnidirectional antennas. This simple setup allowed for a transparent
|
||||||
|
ethernet link to be made between the two systems, allowing for useful
|
||||||
|
features such as remote debugging and code upload. The radios were
|
||||||
|
tested to work at roughly a kilometer away, when mostly line-of-sight.
|
||||||
|
</Paragraph>
|
||||||
|
</Paragraphs>
|
||||||
|
</PageGroup>
|
||||||
|
</PageGroup>
|
||||||
<PageGroup>
|
<PageGroup>
|
||||||
<Fragment slot="header"><H2>Videos</H2></Fragment>
|
<Fragment slot="header"><H2>Videos</H2></Fragment>
|
||||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import half_assembled_main_top_surround_bottom from "@assets/experience/osu-sinn
|
|||||||
export const dechorionatorPcb: printedCircuitBoard = {
|
export const dechorionatorPcb: printedCircuitBoard = {
|
||||||
name: "Dechorionator",
|
name: "Dechorionator",
|
||||||
description:
|
description:
|
||||||
"Control board which provides motion and water flow control, along with user control and monitoring.",
|
"Control board which provides motion and water flow control, along with user control and monitoring",
|
||||||
|
|
||||||
revisions: [
|
revisions: [
|
||||||
{
|
{
|
||||||
@@ -3,11 +3,13 @@ import ExperienceLayout from "@layouts/ExperienceLayout.astro";
|
|||||||
|
|
||||||
import H2 from "@components/H2.astro";
|
import H2 from "@components/H2.astro";
|
||||||
import H3 from "@components/H3.astro";
|
import H3 from "@components/H3.astro";
|
||||||
|
import InlineLink from "@components/InlineLink.astro";
|
||||||
import Li from "@components/Li.astro";
|
import Li from "@components/Li.astro";
|
||||||
import CustomCarousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
|
import CustomCarousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
|
||||||
import PageGroup from "@components/PageGroup.astro";
|
import PageGroup from "@components/PageGroup.astro";
|
||||||
import Paragraph from "@components/Paragraph.astro";
|
import Paragraph from "@components/Paragraph.astro";
|
||||||
import Paragraphs from "@components/Paragraphs.astro";
|
import Paragraphs from "@components/Paragraphs.astro";
|
||||||
|
import PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
|
||||||
import PrintedCircuitBoard from "@components/PrintedCircuitBoard.astro";
|
import PrintedCircuitBoard from "@components/PrintedCircuitBoard.astro";
|
||||||
import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro";
|
import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro";
|
||||||
import Timeline from "@components/Timeline/Timeline.astro";
|
import Timeline from "@components/Timeline/Timeline.astro";
|
||||||
@@ -18,7 +20,7 @@ import { timelineFromPrintedCircuitBoard } from "@interfaces/printed-circuit-boa
|
|||||||
import type { categorySkills } from "@interfaces/skill-matrix.ts";
|
import type { categorySkills } from "@interfaces/skill-matrix.ts";
|
||||||
import type { timelineEntry } from "@interfaces/timeline.ts";
|
import type { timelineEntry } from "@interfaces/timeline.ts";
|
||||||
|
|
||||||
import { dechorionatorPcb } from "./dechorionator.ts";
|
import { dechorionatorPcb } from "./dechorionator-pcbs.ts";
|
||||||
import {
|
import {
|
||||||
subTitles,
|
subTitles,
|
||||||
workingTimeline,
|
workingTimeline,
|
||||||
@@ -42,8 +44,7 @@ import top_holder_closeup from "@assets/experience/osu-sinnhuber-aquatic-researc
|
|||||||
import top_lid_open from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/dechorionator/top-lid-open.jpg";
|
import top_lid_open from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/dechorionator/top-lid-open.jpg";
|
||||||
import top_showerhead from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/dechorionator/top-showerhead.jpg";
|
import top_showerhead from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/dechorionator/top-showerhead.jpg";
|
||||||
import travel_setup from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/dechorionator/travel-setup.jpg";
|
import travel_setup from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/dechorionator/travel-setup.jpg";
|
||||||
import InlineLink from "@components/InlineLink.astro";
|
import { DateTime } from "luxon";
|
||||||
import PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
|
|
||||||
|
|
||||||
const headerCarouselGroup: carouselGroup = {
|
const headerCarouselGroup: carouselGroup = {
|
||||||
animation: "slide",
|
animation: "slide",
|
||||||
@@ -73,6 +74,16 @@ const headerCarouselGroup: carouselGroup = {
|
|||||||
const timeline: timelineEntry[] = [
|
const timeline: timelineEntry[] = [
|
||||||
...workingTimeline,
|
...workingTimeline,
|
||||||
...timelineFromPrintedCircuitBoard(dechorionatorPcb),
|
...timelineFromPrintedCircuitBoard(dechorionatorPcb),
|
||||||
|
{
|
||||||
|
event: "Project Started",
|
||||||
|
eventDetail: "Initial Requirements Given",
|
||||||
|
date: DateTime.fromISO("2014-05-01"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: "Project Finished",
|
||||||
|
eventDetail: "Delivered Units to Lab",
|
||||||
|
date: DateTime.fromISO("2016-09-01"),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const categorizedSkills: categorySkills[] = [
|
const categorizedSkills: categorySkills[] = [
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
|
import type { printedCircuitBoard } from "@interfaces/printed-circuit-board.ts";
|
||||||
|
|
||||||
|
import control_bottom_1_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/control/1-0-0/bottom.jpg";
|
||||||
|
import control_top_1_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/control/1-0-0/top.jpg";
|
||||||
|
import control_assembly_bottom_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/control/2-0-0/assembly-bottom.jpg";
|
||||||
|
import control_assembly_top_beaglebone_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/control/2-0-0/assembly-top-beaglebone.jpg";
|
||||||
|
import control_assembly_top_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/control/2-0-0/assembly-top.jpg";
|
||||||
|
import control_bottom_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/control/2-0-0/bottom.png";
|
||||||
|
import control_top_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/control/2-0-0/top.png";
|
||||||
|
import lights_assembly_bottom_1_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/lights/1-0-0/assembly-bottom.jpg";
|
||||||
|
import lights_assembly_top_1_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/lights/1-0-0/assembly-top.jpg";
|
||||||
|
import lights_assembly_bottom_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/lights/2-0-0/assembly-bottom.jpg";
|
||||||
|
import lights_assembly_top_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/lights/2-0-0/assembly-top.jpg";
|
||||||
|
import lights_top_panelized_2_0_0 from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pcbs/lights/2-0-0/top-panelized.png";
|
||||||
|
|
||||||
|
export const pnpLights: printedCircuitBoard = {
|
||||||
|
name: "Lighting Board",
|
||||||
|
description:
|
||||||
|
"Compact, bright, 24V lighting to provide high-contrast video for the pick and plate",
|
||||||
|
|
||||||
|
revisions: [
|
||||||
|
{
|
||||||
|
major: 2,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
date: DateTime.fromISO("2014-09-23"),
|
||||||
|
images: [
|
||||||
|
lights_top_panelized_2_0_0,
|
||||||
|
lights_assembly_top_2_0_0,
|
||||||
|
lights_assembly_bottom_2_0_0,
|
||||||
|
],
|
||||||
|
notes: [
|
||||||
|
{
|
||||||
|
item: "First panelized PCB design, with built-in test features",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
major: 1,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
date: DateTime.fromISO("2014-04-07"),
|
||||||
|
images: [lights_assembly_top_1_0_0, lights_assembly_bottom_1_0_0],
|
||||||
|
notes: [
|
||||||
|
{
|
||||||
|
item: "Worked, but couldn't remove heat efficiently long-term",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
export const pnpControl: printedCircuitBoard = {
|
||||||
|
name: "Driver Board",
|
||||||
|
description:
|
||||||
|
"Motion controller, and single-board-computer interface, for the embryo pick and plate machine",
|
||||||
|
|
||||||
|
revisions: [
|
||||||
|
{
|
||||||
|
major: 2,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
date: DateTime.fromISO("2014-07-11"),
|
||||||
|
images: [
|
||||||
|
control_top_2_0_0,
|
||||||
|
control_bottom_2_0_0,
|
||||||
|
control_assembly_top_2_0_0,
|
||||||
|
control_assembly_bottom_2_0_0,
|
||||||
|
control_assembly_top_beaglebone_2_0_0,
|
||||||
|
],
|
||||||
|
notes: [
|
||||||
|
{
|
||||||
|
item: "Functional, but ultimately scrapped due to motion control complexity",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
major: 1,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
date: DateTime.fromISO("2013-12-02"),
|
||||||
|
images: [control_top_1_0_0, control_bottom_1_0_0],
|
||||||
|
notes: [
|
||||||
|
{
|
||||||
|
item: "First printed circuit board I ever designed, which was REALLY bad",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -1,5 +1,316 @@
|
|||||||
---
|
---
|
||||||
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
|
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="SARL - Zebrafish Embryo Pick and Plate" />
|
<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>
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ const headerCarouselGroup: carouselGroup = {
|
|||||||
href="/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler"
|
href="/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler"
|
||||||
>robotic oceanographic surface sampler</InlineLink
|
>robotic oceanographic surface sampler</InlineLink
|
||||||
>
|
>
|
||||||
and an <InlineLink
|
and a <InlineLink
|
||||||
href="/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate"
|
href="/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate"
|
||||||
>embryo pick-and-plate machine</InlineLink
|
>zebrafish embryo pick-and-plate machine</InlineLink
|
||||||
>. One my my proudest moments was when our club's mars rover took first
|
>. One my my proudest moments was when our club's mars rover took first
|
||||||
place at the Candian International Rover Challenge in 2018, for which I
|
place at the Candian International Rover Challenge in 2018, for which I
|
||||||
was the <InlineLink
|
was the <InlineLink
|
||||||
|
|||||||