Version 1.0

This commit is contained in:
Doctor Volt
2023-02-05 17:41:30 +01:00
parent 5e77193bec
commit a6d573e581
20 changed files with 11961 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
# Blu-ray Laser Microscope
In a way, CD-ROM and Blu-Ray drives already function like microscopes, using lasers to read the microscopic pits and lands on the surface of a CD or DVD. In the case of a Blu-Ray drive, an ultra precise blue (technically closer to violet in color) laser with a wavelength of 405 nanometers is focused on the surface of a disc, and how effectively that light is reflected back to the drives optical pickup unit determines whether a one or a zero has been detected.
<img src="./images/2_opu.jpg" width="560" height="315">
*Combined CD/DVD and Blu-ray optical pickup unit used in the project (BDP-10G)*
But the sensors in the optical pickup unit can actually measure a wider range of light intensities—not just on or off— which facilitates a Blu-Ray drives error correction capabilities, and allows for the hardware to be repurposed for other uses. This is about repurposing a Blu-Ray pickup to build a simple scanning laser microscope.
<img src="./images/2a_opu.jpg" width="560" height="315">
*CD/DVD/Blu-ray drive with pickup from Samsung BD-J5900*
A couple of custom-designed and manufactured plastic parts create a scanning bed for a sample that could move back in forth in one Y-direction (frame), while the laser itself shifted back and forth in x-direction (lines) by its surrounding "voice" coils.
<img src="./images/scanbed1.jpg" width="560" height="315">
*Scanning bed with electronics*
The closeup of an optical pickup unit(OPU) clearly shows the voice coils used for scanning in X-direction (lines) and Z-direction (focus)
<img src="./images/BDP10.png" width="560">
*Closeup of the BDP10G pickup unit used in the project*
Unlike an optical microscope, where the entirely of an object is imaged at once, a scanning laser microscope takes light intensity measurements in increments, moving across an object in a grid and assembling a magnified image pixel by pixel.
A browser-based user interface written in HTML an Java Script allows to operate the device over WLAN.
<img src="./images/onion480x480.png" width="560">
*Web interface of Blu-ray microscope, showing onion cells*
---
## Preparing The Microscope
- Enter WLAN SSID and passphrase into the source code file `src.ino` and upload to ESP32 module.
- Copy `index.htm` and `opencv.js` to any directory on your PC and open `index.html` in your web browser.
- Adjust the reference voltage for the op-amps with Trimmer RV1 until the LED goes off and the level indicator on the bottom of the user interface shows a minimum.
- Adjust the current through the stepper motor with the trimmer on the STSPIN 220 driver module while the Up or Down button on the website is pressed until the object sled just moves smoothly. Warning: Too much current will overheat and burn the motor out.
- Place a slide in the recess of the specimen slide and a piece of paper on it. Flip down the OPU and turn the thumbscrews until the LED lights up.
---
## Taking Images
- Set the laser power and focus controls to their full extent
- Peep through the pickup lens from above and carefully position the specimen by hand and with the Up and Down buttons on the web interface until it is correctly placed.
- Slowly turn back the coarse focus control until the indicator swings out. Then adjust it with the fine focus control and the laser power control until it deflects about halfway.
- Perform a trial scan at low resolution and high scan speed. You can also adjust the parameters during the scan.
- Now try higher resolutions and/or lower scan speed and/or samples per dot to get a higher image quality.
---
## Watch Videos to Learn More
In Part 1 you will see how I re-engineered an optical pickup unit from a broken Blu-ray player so that it can be used for a laser scanning microscope.
<a href="https://youtu.be/liGuhbFh4IQ" alt="DIY Blu-Ray Laser Scanning Microscope #1: Making a Laser Microphone">
<img width="560" height="315" src="https://i9.ytimg.com/vi_webp/liGuhbFh4IQ/mqdefault.webp?v=636dfcfd&sqp=CPSP_54G&rs=AOn4CLCRRfWlJ2_5ZDGoImf5y4xb2nhfEQ"></img>
</a>
---
Part 2 is about a working prototype that builds on the existing CD/DVD/Blu-ray drive I salvaged from the Blu-ray player.
<a href="https://youtu.be/Hkialty_8K4" alt="DIY Blu-Ray Laser Scanning Microscope #2: Shooting Images">
<img width="560" height="315" src="https://i9.ytimg.com/vi/Hkialty_8K4/mqdefault.jpg?v=6399f732&sqp=CKSZ_54G&rs=AOn4CLDJEHFbHo7iL0mKpUGCELmE1IDtrQ"></img>
</a>
---
Part 3 shows how to build an improved version of the microscope from 3D printed parts and how to use it.
<a href="https://youtu.be/xfuWbnMYOos" alt="DIY Blu-Ray Laser Scanning Microscope #3: Improvements And Tests">
<img width="560" height="315" src="https://i9.ytimg.com/vi_webp/xfuWbnMYOos/mqdefault.webp?v=63df8991&sqp=CNCb_54G&rs=AOn4CLAXFDF4tloAdsORtyXk3GeD_Mqpsw"></img>
</a>
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+365
View File
@@ -0,0 +1,365 @@
/* Copyright (C) 2022 Doctor Volt
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// #include <Arduino.h>
#include <ArduinoJson.h>
//#include "driver/ledc.h"
#define PINSTEPY_M1 18
#define PINSTEPY_M2 19
#define PINSTEPY_SLP 21
#define PINSTEPY_DIR 22
#define PINSTEPY_STP 23
#define PINPWM_SCAN_X 25
#define PINPOL_SCAN_X 26
#define PINPWN_FOCUS 27
#define PIN_SUM 32
#define PIN_FES 33
#define PINPWM_LSR 13
#define ACTIVE LOW
#define PASSIVE HIGH
#define MAX_SAMPLES 16
enum CMD
{
CMD_IDLE,
SCAN,
STOP,
FOCUS,
GO_UP,
GO_DN,
GO_STOP
};
#define DIRY_UP 1
#define DIRY_DN 0
#define PWM_SCN_MAX_BITS 9
#define PWM_FOC_BITS 10
#define PWM_LSR_BITS 8
const char *ssid = "WLAN-KEY";
const char *password = "passphrase";
// const int ledPin = LED_BUILTIN;
const int PWMScnFreq = 40000000 >> PWM_SCN_MAX_BITS; // PWM Frequency for X-Scan for max. resolution
const int PWMChanScn = 0; // PWM Channel for X-Scan
const int PWMFocFreq = 40000000 >> PWM_FOC_BITS;
const int PWMChanFoc = 2; // PWM Channel for focus
const int PWMLsrFreq = 100000;
const int PWMChanLsr = 4; // PWM Channel for laser
const int PWMChanSld = 6; // PWM Channel for manual sled positioning
int PWMRes; // = (1 << PWMResBits) - 1;
int resolution; // = 2 * (1 << PWMResBits) - 1;
// int YRes;
int scan_speed;
int nsamples; // Samples per dot for averaging
struct /*__attribute__((__packed__))*/ Point
{
uint16_t C1;
// uint16_t C2;
};
typedef uint16_t CVPoint;
CVPoint *linebuf;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
volatile SemaphoreHandle_t scanSemaphore;
TaskHandle_t taskHandle;
// Function declarations for web.cpp
void web_init(const char *ssid, const char *password);
void web_write(const char *data);
// void web_write_event(const char *event);
void web_cleanup();
// void scan_(void*);
// Macro to configure the STSPIN220 for 64 microsteps
#define STS220SET \
digitalWrite(PINSTEPY_SLP, ACTIVE); \
digitalWrite(PINSTEPY_STP, LOW); \
digitalWrite(PINSTEPY_DIR, HIGH); \
digitalWrite(PINSTEPY_SLP, PASSIVE); \
vTaskDelay(10);
void setXscan(int x) // Position of lens
{
int d;
if (x >= 0)
{
d = PWMRes - x - resolution / 30; // The "resolution/xx fixes the glitch arond the zero position"
digitalWrite(PINPOL_SCAN_X, HIGH);
}
else
{
d = -x;
digitalWrite(PINPOL_SCAN_X, LOW);
}
// int d = (x >= 0) ? PWMRes - x : -x;
//Serial.printf("x: %d, d: %d\n", x, d);
// digitalWrite(PINPOL_SCAN_X, (x >= 0));
ledcWrite(PWMChanScn, d);
}
void scanX(int speed, CVPoint *linebuf)
{
for (int i = 1; i <= 16; i++) // Move back lens smoothly before scanning to prevent bouncing
{
setXscan(-i * resolution / 32);
// Serial.printf("%d", -i*PWMRes/8);
vTaskDelay(10);
}
for (int scanX = -resolution / 2; scanX <= resolution / 2 - 1; scanX++)
{
setXscan(scanX);
delayMicroseconds(1550 - 100 * speed);
int c1 = 0;
for (int i = 0; i < nsamples; i++)
{
c1 += analogRead(PIN_SUM);
// c2 += analogRead(PIN_FES);
}
linebuf[resolution / 2 + scanX] = 16 * (c1 / nsamples); // Sum
}
setXscan(0); //Neutral position
}
/* This must be started as task to prevent triggering the async_tcp watchdog*/
void scan(void *task_break)
{
const int nSteps = 1280; // Will do one revolution (20*64 microsteps)
static int microsteps = 0; // Number of microsteps passed
const int pre_steps = 200; // Number of steps the motor takes before scanning for the leadscrew to gain grip.
Serial.println("Start scanning");
STS220SET
int yskip = 1 + floor(nSteps / (PWMRes + 1));
digitalWrite(PINSTEPY_DIR, DIRY_UP);
for (int i = 0; i < yskip * resolution / 2; i++)
{
digitalWrite(PINSTEPY_STP, HIGH);
vTaskDelay(1);
digitalWrite(PINSTEPY_STP, LOW);
vTaskDelay(1);
microsteps--;
}
// Advance the sled a bit, so that the leadscrew gets grip.
digitalWrite(PINSTEPY_DIR, DIRY_DN);
for (int i = 0; i < pre_steps / yskip; i++)
{
digitalWrite(PINSTEPY_STP, HIGH);
vTaskDelay(1);
digitalWrite(PINSTEPY_STP, LOW);
vTaskDelay(1);
microsteps++;
}
for (int i = 0; (i < resolution) && (!*((bool *)task_break)); i++)
{
scanX(scan_speed, linebuf); // Scan line Forwards
for (int i = 0; i < yskip; i++) // Forward by ySkip microsteps
{
digitalWrite(PINSTEPY_STP, HIGH);
vTaskDelay(1);
digitalWrite(PINSTEPY_STP, LOW);
vTaskDelay(1);
microsteps++;
}
xSemaphoreGive(scanSemaphore); // This triggers sending of the line in the loop() function
vTaskSuspend(NULL); // Suspend task during data transfer
//if(*(bool*)task_break) break;
}
Serial.printf("Scan completed: %d\n", *((bool *)task_break));
// Move sled back to intitial y position
digitalWrite(PINSTEPY_DIR, DIRY_UP);
for (int i = 0; i < microsteps; i++)
{
digitalWrite(PINSTEPY_STP, HIGH);
delayMicroseconds(200);
digitalWrite(PINSTEPY_STP, LOW);
delayMicroseconds(200);
}
microsteps = 0;
digitalWrite(PINSTEPY_SLP, ACTIVE);
digitalWrite(PINPWM_SCAN_X, LOW);
ledcWrite(PWMChanScn, 0);
digitalWrite(PINPOL_SCAN_X, LOW);
web_write("stop");
vTaskDelete(NULL);
}
void handleWebMessage(const char *data, size_t len)
{
DynamicJsonDocument jdoc(1024);
deserializeJson(jdoc, data);
static bool taskBreak;
if (nsamples != (int)jdoc["nsamples"])
{
nsamples = jdoc["nsamples"];
// Serial.printf("Number of samples per dot: %d\n", nsamples);
}
if (scan_speed != (int)jdoc["speed"])
{
scan_speed = jdoc["speed"];
// Serial.printf("speed: %d\n", scan_speed);
}
static int pwmbits;
if (pwmbits != (int)jdoc["pwmbits"])
{
pwmbits = jdoc["pwmbits"];
Serial.printf("pwmbits: %d\n", pwmbits);
ledcSetup(PWMChanScn, PWMScnFreq, pwmbits);
PWMRes = (1 << pwmbits) - 1;
resolution = 2 * (1 << pwmbits) - (1 << pwmbits - 3);
Serial.printf("Resolution: %d\n", resolution);
}
static int focus;
if (focus != (int)jdoc["focus"])
{
focus = jdoc["focus"];
// Serial.printf("focus: %d\n", focus);
ledcWrite(PWMChanFoc, focus);
}
static int laser;
if (laser != (int)jdoc["laser"])
{
laser = jdoc["laser"];
// Serial.printf("laser: %d\n", laser);
ledcWrite(PWMChanLsr, laser);
}
static int xcoil;
if (xcoil != (int)jdoc["xcoil"])
{
xcoil = jdoc["xcoil"];
Serial.printf("xcoil: %d\n", xcoil);
setXscan(xcoil);
}
switch ((int)jdoc["cmd"])
{
case CMD::SCAN:
taskBreak = 0;
xTaskCreate(scan, "scan", 16000, &taskBreak, 1, &taskHandle);
break;
case CMD::STOP:
taskBreak = 1;
break;
case CMD::GO_UP:
case CMD::GO_DN:
// Serial.print("Move Sled ");
STS220SET;
(int)jdoc["cmd"] == GO_UP
? digitalWrite(PINSTEPY_DIR, DIRY_UP)
: digitalWrite(PINSTEPY_DIR, DIRY_DN);
ledcAttachPin(PINSTEPY_STP, PWMChanSld);
ledcWriteTone(PWMChanSld, 100 * (scan_speed + 1));
break;
case CMD::GO_STOP:
// Serial.println("Stop sled");
ledcDetachPin(PINSTEPY_STP);
digitalWrite(PINSTEPY_SLP, ACTIVE);
break;
}
}
/*void ARDUINO_ISR_ATTR onTimer()
{
portENTER_CRITICAL_ISR(&timerMux);
portEXIT_CRITICAL_ISR(&timerMux);
xSemaphoreGiveFromISR(timerSemaphore, NULL);
}*/
void setup()
{
Serial.begin(115200);
// digitalWrite(ledPin, LOW);
scanSemaphore = xSemaphoreCreateBinary();
// hw_timer_t *timer = timerBegin(0, 80, true);
// timerAttachInterrupt(timer, &onTimer, true);
// timerAlarmWrite(timer, 100000, true);
// timerAlarmEnable(timer);
linebuf = (CVPoint*)calloc(sizeof(CVPoint), 2 << PWM_SCN_MAX_BITS);
pinMode(PINSTEPY_SLP, OUTPUT);
digitalWrite(PINSTEPY_SLP, ACTIVE);
pinMode(PINSTEPY_M1, OUTPUT);
pinMode(PINSTEPY_M2, OUTPUT);
pinMode(PINSTEPY_STP, OUTPUT);
pinMode(PINSTEPY_DIR, OUTPUT);
// Set M1 and M2 for motor driver
digitalWrite(PINSTEPY_M1, HIGH);
digitalWrite(PINSTEPY_M2, HIGH);
pinMode(PINPOL_SCAN_X, OUTPUT);
adcAttachPin(PIN_SUM);
adcAttachPin(PIN_FES);
ledcSetup(PWMChanFoc, PWMFocFreq, PWM_FOC_BITS);
ledcSetup(PWMChanLsr, PWMLsrFreq, PWM_LSR_BITS);
ledcSetup(PWMChanSld, 0, 1);
ledcAttachPin(PINPWN_FOCUS, PWMChanFoc);
ledcAttachPin(PINPWM_LSR, PWMChanLsr);
ledcAttachPin(PINPWM_SCAN_X, PWMChanScn);
// handleWebMessage("{\"speed\":2,\"pwmbits\":6,\"yres\":128,\"cmd\":1}", 35);
web_init(ssid, password);
}
void loop()
{
char buf[16];
if (xSemaphoreTake(scanSemaphore, 100) == pdTRUE)
{
String line;
for (int i = 0; i < resolution; i++)
{
// sprintf(buf, "%d,%d,", linebuf[i].C1, linebuf[i].C2);
sprintf(buf, "%d,", linebuf[i]);
line += String(buf);
}
line[line.length() - 1] = 0; // Remove comma */
// Serial.println(line);
web_write(line.c_str());
vTaskResume(taskHandle);
}
else
{
sprintf(buf, "{\"SUM\": %d}", analogRead(PIN_SUM));
web_write(buf);
}
// Serial.println("loop");
web_cleanup();
}
// Create test pattern
void scan_(void *task_break)
{
Serial.printf("xres: %d, yres: %d, PWMRes: %d\n", resolution, resolution, PWMRes);
for (int i = 0; (i < resolution) && (!*((bool *)task_break)); i++)
{
for (int scanX = -resolution / 2; scanX <= resolution / 2; scanX++)
{
if (scanX % 16)
linebuf[resolution / 2 + scanX] = 256 * (resolution / 2 + scanX); // Sum
}
xSemaphoreGive(scanSemaphore); // This triggers sending of the line in the loop() function
vTaskSuspend(NULL);
}
web_write("stop");
vTaskDelete(NULL);
}
+159
View File
@@ -0,0 +1,159 @@
/* Copyright (C) 2020 Doctor Volt
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses></https:>.
*/
#define LOCAL_WEB //Website located on PC
//#define USE_OTA
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#ifndef LOCAL_WEB
#include <SPIFFS.h>
#endif
#include <mdns.h>
#ifdef USE_OTA
//#include <AsyncElegantOTA.h>
#endif
// mdns hostname
const char *hostname = "lasermic.local";
void handleWebMessage(const char *data, size_t len);
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
//AsyncEventSource es("/es");
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
void *arg, uint8_t *data, size_t len)
{
switch (type)
{
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
// handleWebSocketMessage(arg, data, len);
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT)
{
handleWebMessage((const char *)data, len);
}
}
break;
case WS_EVT_PONG:
Serial.println("WebSocket Pong:");
case WS_EVT_ERROR:
Serial.println("WebSocket Error");
}
}
String processor(const String &var)
{
Serial.print("processor");
Serial.println(var);
if (var == "STATE")
{
}
return "Hello";
}
void web_init(const char *ssid, const char *password)
{
// Serial port for debugging purposes
// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
// Print ESP Local IP Address
Serial.println();
Serial.println("WiFi Connected");
// Assign DNS name
mdns_init();
mdns_hostname_set(hostname);
ws.onEvent(onEvent);
server.addHandler(&ws);
// Initialize SPIFFS
#ifndef LOCAL_WEB
Serial.printf("Open http://%s in browser\r\n", hostname);
if (!SPIFFS.begin(true))
{
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
server.serveStatic("/", SPIFFS, "/");
#endif
/*Event source initialization*/
/*es.onConnect([](AsyncEventSourceClient *client)
{
//Serial.println("es.onConnect");
if(client->lastId()){
Serial.printf("Event Client reconnected! Last message ID: %u\n", client->lastId());
}
if(client->connected()){
Serial.println("Event source connected");
} });*/
// Magic to allow access to event server from anywhere
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Origin"), F("*"));
//DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Credentials"), F("true"));
#ifdef USE_OTA
AsyncElegantOTA.begin(&server);
#endif
// Start server
server.begin();
//server.addHandler(&es);
}
/*void web_write_event(const char *data)
{
// ws.textAll((const char*)buffer, len);
while(es.avgPacketsWaiting())
{
Serial.printf("waiting: %d\n",es.avgPacketsWaiting());
vTaskDelay(1000);
}
es.send(data);
}*/
void web_write(const char *data)
{
ws.textAll(data);
while(!ws.availableForWriteAll())
{
//Serial.println("Waiting for websocket");
vTaskDelay(10);
}
// es.send(data, NULL);
}
void web_cleanup()
{
ws.cleanupClients();
}
+449
View File
@@ -0,0 +1,449 @@
<!--
Download the required opencv.js from https://docs.opencv.org/4.6.0/opencv.js
Note: This will not fit on the ESP32 SPIFFS file system, so open from PC.
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Blu-Ray Laser Microscope</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<style>
html {
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
h2 {
font-size: 1.5rem;
font-weight: bold;
}
.espcontrol {
display: inline-grid;
grid-template-columns: 200px auto 200px;
background-color: mediumblue;
justify-content: center;
}
.header {
display: grid;
grid-column: -1/1;
background-color: darkviolet;
}
.left {
background-color: #777;
}
.middle {
background-color: black;
}
.right {
background-color: #777;
}
.footer {
display: grid;
grid-template-columns: auto auto auto;
grid-column: -1/1;
gap: 0px;
background-color: darkslateblue;
color: white;
align-items: center;
}
.slider_box {
padding: 5px;
display: grid;
justify-content: left;
border: darkslateblue;
border-style: dotted;
border-width: 1px;
}
.slider {
width: 180px;
}
.image {
background-color: #143642;
width: 64px;
height: 64px;
}
.meters {
grid-column: 3/4;
}
meter {
width: 400px
}
.radiogroup {
display: grid;
grid-template-columns: auto auto;
border: darkslateblue;
border-style: dotted;
border-width: 1px;
/*justify-content: space-around;*/
}
.udbutton {
background-color: #3e8e41;
border-color: white;
}
.udbutton:disabled {
opacity: 0.65;
cursor: not-allowed;
}
.arrowline {
stroke-linecap: round;
stroke: yellow;
stroke-width: 4;
fill: none
}
</style>
<script script type="text/javascript">
var gateway = "ws://lasermic.local/ws";
var alfa = 1; //Contrast
var beta = 0; //Brightness
var act_channel = 0;
var settings = { "nsamples": 0, "pwmbits": 0, "speed": 0, "focus": 0, "laser": 0, "xcoil": 0, "cmd": 0 };
var resolution;
const IDLE = 0;
const SCAN = 1;
const STOP = 2;
const FOCUS = 3;
const GO_UP = 4;
const GO_DN = 5;
const GO_STOP = 6;
const btn_txt_scan = "Scan";
const btn_txt_stop = "Stop";
const btn_txt_cancelled = "Cancelled";
var scanvals;
//var scanmat_vector;
var cvimage;
var linenum = 0; //Number of lines being scanned
//var gateway = "ws://${window.location.hostname}/ws";
var websocket;
//var src; //OpenCv Mat
window.addEventListener('load', onLoad);
function show_canvas() {
if (resolution < 960)
cv.resize(cvimage, cvimage, new cv.Size(480, 480));
else
cv.resize(cvimage, cvimage, new cv.Size(960, 960));
cv.imshow("cvcanvas", cvimage);
}
function onOpenCVReady() {
console.log("Open CV ready");
resolution = 2 * (1 << settings.pwmbits) - (1 << settings.pwmbits - 3);
cvimage = cv.Mat.zeros(resolution, resolution, cv.CV_16UC1);
show_canvas();
scanvals = cv.Mat.zeros(resolution, resolution, cv.CV_16UC1);
alfa = Number(document.getElementById("sld_cont").value);
document.getElementById("sld_cont").oninput = function () {
alfa = Number(this.value);
//cv.convertScaleAbs(cvimage, alpha=alpha, beta=beta)
scanvals.convertTo(cvimage, cv.CV_16UC1, alfa, beta);
show_canvas();
}
beta = Number(document.getElementById("sld_bright").value);
document.getElementById("sld_bright").oninput = function () {
beta = Number(this.value);
scanvals.convertTo(cvimage, cv.CV_16UC1, alfa, beta);
show_canvas();
}
//console.log(act_channel);
}
function on_updn(value) { //Button that moves the sled up or down
settings.cmd = value;
websocket.send(JSON.stringify(settings));
//console.log(JSON.stringify(settings));
}
function onWsOpen(event) {
//console.log('Websocket open');
websocket.send(JSON.stringify(settings)); //Send settings to init ESP32
//Outgoing messages from user interaction
document.getElementsByName("rad_samp").forEach(function (radio) {
radio.onchange = function () {
settings.nsamples = this.value;
websocket.send(JSON.stringify(settings));
//console.log(JSON.stringify(settings));
}
});
document.getElementsByName("rad_res").forEach(function (radio) {
radio.onchange = function () {
settings.pwmbits = this.value;
resolution = 2 * (1 << settings.pwmbits) - (1 << settings.pwmbits - 3);
cv.resize(scanvals, scanvals, new cv.Size(resolution, resolution));
show_canvas();
websocket.send(JSON.stringify(settings));
//console.log(JSON.stringify(settings));
}
});
document.getElementById("sld_speed").oninput = function () {
settings.speed = this.value;
websocket.send(JSON.stringify(settings));
//console.log(JSON.stringify(settings));
}
document.getElementById("sld_focus").oninput = function () {
settings.focus = this.value;
websocket.send(JSON.stringify(settings));
document.getElementById("sld_focus_fine").value = 0;
}
document.getElementById("sld_focus_fine").oninput = function () {
settings.focus = Number(this.value) + Number(document.getElementById("sld_focus").value);
websocket.send(JSON.stringify(settings));
}
document.getElementById("sld_laser").oninput = function () {
settings.laser = this.max - Number(this.value)
websocket.send(JSON.stringify(settings));
}
document.getElementById("sld_xcoil").oninput = function () {
settings.xcoil = Number(this.value)
websocket.send(JSON.stringify(settings));
console.log(JSON.stringify(settings));
}
document.getElementById("btn_scan").onclick = function () { //Scan button clicked
if (this.innerHTML == btn_txt_scan) {
this.innerHTML = btn_txt_stop;
settings.cmd = SCAN;
linenum = 0;
} else {
this.innerHTML = btn_txt_cancelled;
settings.cmd = STOP;
}
websocket.send(JSON.stringify(settings));
settings.cmd = IDLE;
}
document.getElementById("h2_connected").innerHTML = "Connected";
document.getElementById("btn_scan").removeAttribute("disabled");
document.getElementById("btn_up").removeAttribute("disabled");
document.getElementById("btn_dn").removeAttribute("disabled");
}
function onWsClose(event) {
console.log('Websocket closed');
document.getElementById("h2_connected").innerHTML = "Not Connected";
document.getElementById("btn_scan").setAttribute("disabled", "");
document.getElementById("btn_up").setAttribute("disabled", "");
document.getElementById("btn_dn").setAttribute("disabled", "");
setTimeout(initWebSocket, 2000);
}
function onMessage(event) { //Event handler for messages from ESP32
//console.log(event.data);
if (event.data == "stop") {
document.getElementById("btn_scan").innerHTML = btn_txt_scan;
return;
}
var arr = event.data.split(",");
if (arr.length == 1) {
document.getElementById("met_ch1").value = JSON.parse(event.data).SUM;
return;
}
if (arr.length != resolution) {
console.error("Resolution mismatch. Received array: " + arr.length + " resolution: " + resolution);
return;
}
//console.log(arr.length);
var scanline = cv.matFromArray(1, resolution, cv.CV_16UC1, arr);
var dstrow = scanvals.row(linenum++);
scanline.copyTo(dstrow);
scanvals.convertTo(cvimage, cv.CV_16UC1, alfa, beta);
show_canvas();
}
function initWebSocket() {
//console.log('Trying to open a WebSocket connection...');
websocket = new WebSocket(gateway);
websocket.onopen = onWsOpen;
websocket.onclose = onWsClose;
websocket.onmessage = onMessage; // <-- add this line
}
//Receiving bulk date
function initEventSources() {
var evtsource = new EventSource("http://lasermic.local/es");
evtsource.onmessage = onMessage;
}
function onLoad(event) { //Initialize html elements when page is loading
console.log("onLoad()");
document.getElementsByName("rad_samp").forEach(function (radio) {
if (radio.checked) {
settings.nsamples = Number(radio.value);
}
});
document.getElementsByName("rad_res").forEach(function (radio) {
if (radio.checked) {
settings.pwmbits = Number(radio.value);
resolution = 2 * (1 << settings.pwmbits) - (1 << settings.pwmbits - 3);
}
});
settings.speed = Number(document.getElementById("sld_speed").value);
settings.focus = Number(document.getElementById("sld_focus").value);
settings.focus += Number(document.getElementById("sld_focus_fine").value);
settings.laser = Number(document.getElementById("sld_laser").max);
settings.laser -= Number(document.getElementById("sld_laser").value);
document.getElementById("btn_scan").setAttribute("disabled", "");
document.getElementById("btn_scan").innerHTML = btn_txt_scan;
document.getElementById("btn_up").setAttribute("disabled", "");
document.getElementById("btn_dn").setAttribute("disabled", "");
//console.log(settings);
initWebSocket();
//initEventSources();
}
var Module = {
// https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
onRuntimeInitialized() {
onOpenCVReady();
}
}
</script>
<script async src="opencv.js" type="text/javascript"></script>
<!--<script async src="opencv_new.js" onload="onOpenCVReady()" type="text/javascript"></script>-->
</head>
<body>
<div class="espcontrol">
<div class="header">
<h1>Blu-Ray Laser Scanning Microscope</h1>
</div>
<div class="left">
<div class="slider_box">
<label for="sld_cont">Contrast</label>
<input class="slider" type="range" id="sld_cont" min="1" max="4" value="1" step="0.1">
</div>
<div class="slider_box">
<label for="sld_bright">Brightness</label>
<input class="slider" type="range" id="sld_bright" min="-65536" max="32768" value="0">
</div>
</div>
<div class="middle">
<!--<div class="image">-->
<canvas id="cvcanvas" width=480 height=480></canvas>
<!--</div>-->
</div>
<div class="right">
<div class="radiogroup">
<div style="grid-column: -1/1">Samples Per Dot</div>
<p><label for="samp1">1</label>
<input type="radio" id="samp1" name="rad_samp" value="1" checked>
<label for="samp4">&nbsp 4</label>
<input type="radio" id="samp4" name="rad_samp" value="4">
<label for="samp8">&nbsp8</label>
<input type="radio" id="samp8" name="rad_samp" value="8">
<label for="samp12">&nbsp12</label>
<input type="radio" id="samp12" name="rad_samp" value="12">
</p>
</div>
<div class="radiogroup">
<div style="grid-column: -1/1">Resolution</div>
<p><label for="res127">120x120</label>
<input type="radio" id="res127" name="rad_res" value="6" checked>
<!--The values eqal the PWM resolution in bits-->
</p>
<p>
<label for="res255">240x240</label>
<input type="radio" id="res255" name="rad_res" value="7">
</p>
<p>
<label for="res511">480x480</label>
<input type="radio" id="res511" name="rad_res" value="8">
</p>
<p>
<label for="res1023">960x960</label>
<input type="radio" id="res1023" name="rad_res" value="9">
</p>
</div>
<div class="slider_box">
<label for="sld_speed">Scan Speed</label>
<input class="slider" type="range" id="sld_speed" min="0" max="15">
</div>
<div class="slider_box">
<label for="sld_focus">Focus (coarse)</label>
<input class="slider" type="range" id="sld_focus" min="100" max="924">
</div>
<div class="slider_box">
<label for="sld_focus_fine">Focus (fine)</label>
<input class="slider" type="range" id="sld_focus_fine" min="-100" max="100">
</div>
<div class="slider_box">
<label for="sld_laser">Laser power</label>
<input class="slider" type="range" id="sld_laser" min="128" max="255">
</div>
<div style="visibility:collapse" class="slider_box">
<label hidden for="sld_xcoil">X-Coil</label>
<input hidden class="slider" type="range" id="sld_xcoil" min="-240" max="239">
</div>
<hr>
<button type="button" id="btn_scan" style="width: 90%;"></button>
</div>
<div class="footer">
<div>
<h2 id="h2_connected">Not Connected</h2>
</div>
<div>
<p>
<label for="met_ch1">Level</label>
<meter id="met_ch1" min="0" max="4096" low="1000"></meter>
</p>
</div>
<div>
<button class="udbutton" id="btn_up" onmousedown="on_updn(GO_UP)" onmouseup="on_updn(GO_STOP)" disabled="true">
<svg width="40px" height="40px">
<line x1="20" y1="5" x2="20" y2="38" class="arrowline"></line>
<polyline points="5,20, 20,5, 35,20" class="arrowline"></polyline>
</svg>
</button>
<button class="udbutton" id="btn_dn" onmousedown="on_updn(GO_DN)" onmouseup="on_updn(GO_STOP)">
<svg width="40px" height="40px">
<line x1="20" y1="5" x2="20" y2="38" class="arrowline"></line>
<polyline points="5,20, 20,38, 35,20" class="arrowline"></polyline>
<polyline>
</svg>
</button>
</div>
</div>
</body>
</html>
<!--
function dbgMat(mat) {
console.log('image width: ' + mat.cols + '\n' +
'image height: ' + mat.rows + '\n' +
'image size: ' + mat.size().width + '*' + mat.size().height + '\n' +
'image depth: ' + mat.depth() + '\n' +
'image channels ' + mat.channels() + '\n' +
'image type: ' + mat.type() + '\n');
console.log(mat.data);
}
-->
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 503 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

+431
View File
@@ -0,0 +1,431 @@
{
"board": {
"design_settings": {
"defaults": {
"board_outline_line_width": 0.049999999999999996,
"copper_line_width": 0.19999999999999998,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.09999999999999999,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.762,
"height": 1.524,
"width": 1.524
},
"silk_line_width": 0.12,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.15,
"silk_text_upright": false,
"zones": {
"45_degree_only": false,
"min_clearance": 0.508
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"copper_edge_clearance": "error",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rules": {
"allow_blind_buried_vias": false,
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.0,
"min_copper_edge_clearance": 0.01,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_silk_clearance": 0.0,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.19999999999999998,
"min_via_annular_width": 0.049999999999999996,
"min_via_diameter": 0.39999999999999997,
"use_height_for_length_calcs": true
},
"track_widths": [
0.0
],
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
}
],
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "lasermic.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
}
],
"meta": {
"version": 2
},
"net_colors": null
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"e63e39d7-6ac0-4ffd-8aa3-1841a4541b55",
""
]
],
"text_variables": {}
}
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

+240
View File
@@ -0,0 +1,240 @@
(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor)
(symbol "ESP32_NODEMCU" (pin_names (offset 1.016)) (in_bom yes) (on_board yes)
(property "Reference" "U?" (id 0) (at 0 35.56 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "ESP32_NODEMCU" (id 1) (at 0 33.02 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) (justify left bottom) hide)
)
(property "ki_locked" "" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)))
)
(symbol "ESP32_NODEMCU_0_0"
(rectangle (start -10.16 30.48) (end 8.89 -24.13)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type background))
)
(pin power_in line (at -15.24 27.94 0) (length 5.08)
(name "3V3" (effects (font (size 1.016 1.016))))
(number "1" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 -2.54 0) (length 5.08)
(name "D19" (effects (font (size 1.016 1.016))))
(number "10" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 -5.08 0) (length 5.08)
(name "D21" (effects (font (size 1.016 1.016))))
(number "11" (effects (font (size 1.016 1.016))))
)
(pin input line (at -15.24 -10.16 0) (length 5.08)
(name "RX0" (effects (font (size 1.016 1.016))))
(number "12" (effects (font (size 1.016 1.016))))
)
(pin output line (at -15.24 -12.7 0) (length 5.08)
(name "TX0" (effects (font (size 1.016 1.016))))
(number "13" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 -17.78 0) (length 5.08)
(name "D22" (effects (font (size 1.016 1.016))))
(number "14" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 -20.32 0) (length 5.08)
(name "D23" (effects (font (size 1.016 1.016))))
(number "15" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 -12.7 180) (length 5.08)
(name "EN" (effects (font (size 1.016 1.016))))
(number "16" (effects (font (size 1.016 1.016))))
)
(pin input line (at 13.97 -10.16 180) (length 5.08)
(name "VP_D36" (effects (font (size 1.016 1.016))))
(number "17" (effects (font (size 1.016 1.016))))
)
(pin input line (at 13.97 -7.62 180) (length 5.08)
(name "VN_D39" (effects (font (size 1.016 1.016))))
(number "18" (effects (font (size 1.016 1.016))))
)
(pin input line (at 13.97 -2.54 180) (length 5.08)
(name "D34" (effects (font (size 1.016 1.016))))
(number "19" (effects (font (size 1.016 1.016))))
)
(pin power_in line (at -15.24 25.4 0) (length 5.08)
(name "GND" (effects (font (size 1.016 1.016))))
(number "2" (effects (font (size 1.016 1.016))))
)
(pin input line (at 13.97 0 180) (length 5.08)
(name "D35" (effects (font (size 1.016 1.016))))
(number "20" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 2.54 180) (length 5.08)
(name "D32" (effects (font (size 1.016 1.016))))
(number "21" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 5.08 180) (length 5.08)
(name "D33" (effects (font (size 1.016 1.016))))
(number "22" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 7.62 180) (length 5.08)
(name "D25" (effects (font (size 1.016 1.016))))
(number "23" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 10.16 180) (length 5.08)
(name "D26" (effects (font (size 1.016 1.016))))
(number "24" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 12.7 180) (length 5.08)
(name "D27" (effects (font (size 1.016 1.016))))
(number "25" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 15.24 180) (length 5.08)
(name "D14" (effects (font (size 1.016 1.016))))
(number "26" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 17.78 180) (length 5.08)
(name "D12" (effects (font (size 1.016 1.016))))
(number "27" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at 13.97 20.32 180) (length 5.08)
(name "D13" (effects (font (size 1.016 1.016))))
(number "28" (effects (font (size 1.016 1.016))))
)
(pin power_in line (at 13.97 25.4 180) (length 5.08)
(name "GND" (effects (font (size 1.016 1.016))))
(number "29" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 20.32 0) (length 5.08)
(name "D15" (effects (font (size 1.016 1.016))))
(number "3" (effects (font (size 1.016 1.016))))
)
(pin power_in line (at 13.97 27.94 180) (length 5.08)
(name "5V" (effects (font (size 1.016 1.016))))
(number "30" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 17.78 0) (length 5.08)
(name "D2" (effects (font (size 1.016 1.016))))
(number "4" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 15.24 0) (length 5.08)
(name "D4" (effects (font (size 1.016 1.016))))
(number "5" (effects (font (size 1.016 1.016))))
)
(pin input line (at -15.24 10.16 0) (length 5.08)
(name "RX2" (effects (font (size 1.016 1.016))))
(number "6" (effects (font (size 1.016 1.016))))
)
(pin output line (at -15.24 7.62 0) (length 5.08)
(name "TX2" (effects (font (size 1.016 1.016))))
(number "7" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 2.54 0) (length 5.08)
(name "D5" (effects (font (size 1.016 1.016))))
(number "8" (effects (font (size 1.016 1.016))))
)
(pin bidirectional line (at -15.24 0 0) (length 5.08)
(name "D18" (effects (font (size 1.016 1.016))))
(number "9" (effects (font (size 1.016 1.016))))
)
)
)
(symbol "Pololu_STSPIN220" (in_bom yes) (on_board yes)
(property "Reference" "A?" (id 0) (at 7.0994 20.955 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "Pololu_STSPIN220" (id 1) (at 7.0994 18.415 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "Module:Pololu_Breakout-16_15.2x20.3mm" (id 2) (at 6.985 -19.05 0)
(effects (font (size 1.27 1.27)) (justify left) hide)
)
(property "Datasheet" "https://www.pololu.com/product/2980/pictures" (id 3) (at 12.7 -24.13 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "Pololu Breakout Board Stepper Driver A4988" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Pololu Breakout Board, Stepper Driver A4988" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "Pololu*Breakout*15.2x20.3mm*" (id 6) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "Pololu_STSPIN220_0_1"
(rectangle (start 10.16 -17.78) (end -7.62 15.24)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type background))
)
)
(symbol "Pololu_STSPIN220_1_1"
(pin power_in line (at 0 -20.32 90) (length 2.54)
(name "GND" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 -5.08 0) (length 2.54)
(name "MS1" (effects (font (size 1.27 1.27))))
(number "10" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 -7.62 0) (length 2.54)
(name "MS2" (effects (font (size 1.27 1.27))))
(number "11" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 -10.16 0) (length 2.54)
(name "1" (effects (font (size 1.27 1.27))))
(number "12" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 -12.7 0) (length 2.54)
(name "2" (effects (font (size 1.27 1.27))))
(number "13" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 7.62 0) (length 2.54)
(name "~{STBY}" (effects (font (size 1.27 1.27))))
(number "14" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 5.08 0) (length 2.54)
(name "STEP" (effects (font (size 1.27 1.27))))
(number "15" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 2.54 0) (length 2.54)
(name "DIR" (effects (font (size 1.27 1.27))))
(number "16" (effects (font (size 1.27 1.27))))
)
(pin power_in line (at 0 17.78 270) (length 2.54)
(name "VDD" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
(pin output line (at 12.7 2.54 180) (length 2.54)
(name "1B" (effects (font (size 1.27 1.27))))
(number "3" (effects (font (size 1.27 1.27))))
)
(pin output line (at 12.7 0 180) (length 2.54)
(name "1A" (effects (font (size 1.27 1.27))))
(number "4" (effects (font (size 1.27 1.27))))
)
(pin output line (at 12.7 -2.54 180) (length 2.54)
(name "2A" (effects (font (size 1.27 1.27))))
(number "5" (effects (font (size 1.27 1.27))))
)
(pin output line (at 12.7 -5.08 180) (length 2.54)
(name "2B" (effects (font (size 1.27 1.27))))
(number "6" (effects (font (size 1.27 1.27))))
)
(pin power_in line (at 5.08 -20.32 90) (length 2.54)
(name "GND" (effects (font (size 1.27 1.27))))
(number "7" (effects (font (size 1.27 1.27))))
)
(pin power_in line (at 5.08 17.78 270) (length 2.54)
(name "VMOT" (effects (font (size 1.27 1.27))))
(number "8" (effects (font (size 1.27 1.27))))
)
(pin input line (at -10.16 11.43 0) (length 2.54)
(name "~{EN}" (effects (font (size 1.27 1.27))))
(number "9" (effects (font (size 1.27 1.27))))
)
)
)
)
+3
View File
@@ -0,0 +1,3 @@
(sym_lib_table
(lib (name "parts")(type "KiCad")(uri "${KIPRJMOD}/parts.kicad_sym")(options "")(descr ""))
)