-
Notifications
You must be signed in to change notification settings - Fork 54
Nema Stepper Element #136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nema Stepper Element #136
Changes from 3 commits
f5ba7de
efe1a23
cfef27b
a58002e
a021545
af0e3f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,177 +1,126 @@ | ||
| import { html, LitElement } from 'lit'; | ||
| import { customElement, property } from 'lit/decorators.js'; | ||
| import { ElementPin } from '.'; | ||
| import { mmToPix } from './utils/units'; | ||
|
|
||
|
|
||
| /** | ||
| * NemaSpec describes a NEMA Stepper specification (for the purpose of visualisation) | ||
| * | ||
| */ | ||
| export interface NemaSpec { | ||
| id: number; // Nema common number representing the size shorthand (Nema11 Nema 17 etc) | ||
| frameSize: number; // the frame size in mm. Since Nema Steppers are square, only one side needed | ||
| holeRadius: number; // Fastening hole size | ||
| shaftRadius: number; // Motor shaft radius | ||
| cornerRadius: number; // Frame corner radius | ||
| cornerOffset: number; // Offset from corner to center of hole | ||
| bodyRadius: number; // the round motor body size | ||
| textSize: number; // Text size showing units etc | ||
| }; | ||
|
|
||
| @customElement('wokwi-stepper-motor') | ||
| export class StepperMotorElement extends LitElement { | ||
| @property() angle = 0; | ||
| @property() arrow = ''; | ||
| @property() value = ''; | ||
| @property() units = ''; | ||
| @property() size : 8 | 11 | 14 | 17 | 23 | 34=17; // valid sizes are 8, 11, 14, 17, 21, 24. 8 is the default at 0.8" | ||
|
|
||
| get pinInfo(): ElementPin[] { | ||
| const spec = this.nemaSpecMap[this.size]; | ||
|
|
||
| // these offsets match the transform in renderFace | ||
| const xOff = (spec.frameSize / 2 - 3.75) * mmToPix; | ||
| const yOff = (spec.frameSize + 5) * mmToPix; | ||
|
|
||
| const pi = [ | ||
| { name: 'A+', y: yOff, x: xOff, number: 1, signals: [] }, | ||
| { name: 'A-', y: yOff, x: xOff + 2.54 * mmToPix, number: 2, signals: [] }, | ||
| { name: 'B+', y: yOff, x: xOff + 5.08 * mmToPix, number: 3, signals: [] }, | ||
| { name: 'B-', y: yOff, x: xOff + 7.62 * mmToPix, number: 4, signals: [] }, | ||
| ]; | ||
|
|
||
| return pi; | ||
| } | ||
|
|
||
| readonly nemaSpecMap : {[key:string] : NemaSpec } = { | ||
| "8": { "id": 8, "frameSize": 20.4, "holeRadius": 0.5, "shaftRadius": 3.5, "cornerRadius": 2.5, "cornerOffset": 2.5, "bodyRadius": 7.7, "textSize":8 }, | ||
| "11": { "id": 11, "frameSize": 28.2, "holeRadius": 1.25, "shaftRadius": 5, "cornerRadius": 2.5, "cornerOffset": 2.5, "bodyRadius": 11, "textSize":8 }, | ||
| "14": { "id": 14, "frameSize": 35.2, "holeRadius": 1.5, "shaftRadius": 5, "cornerRadius": 4.5, "cornerOffset": 4.5, "bodyRadius": 11, "textSize":10 }, | ||
| "17": { "id": 17, "frameSize": 42.3, "holeRadius": 1.5, "shaftRadius": 5, "cornerRadius": 5, "cornerOffset": 5.5, "bodyRadius": 14, "textSize":10 }, | ||
| "23": { "id": 23, "frameSize": 57.3, "holeRadius": 2.5, "shaftRadius": 6.35, "cornerRadius": 5, "cornerOffset": 5.5, "bodyRadius": 19.5, "textSize":16 }, | ||
| "34": { "id": 34, "frameSize": 86, "holeRadius": 3.25, "shaftRadius": 14, "cornerRadius": 3.25, "cornerOffset": 8.4, "bodyRadius": 36.5, "textSize":16 }, | ||
| } | ||
|
|
||
| readonly pinInfo: ElementPin[] = [ | ||
| { name: 'A+', y: 237, x: 108, number: 1, signals: [] }, | ||
| { name: 'A-', y: 237, x: 98, number: 2, signals: [] }, | ||
| { name: 'B+', y: 237, x: 117, number: 3, signals: [] }, | ||
| { name: 'B-', y: 237, x: 127, number: 4, signals: [] }, | ||
| ]; | ||
| render() { | ||
| const spec = this.nemaSpecMap[this.size]; | ||
|
|
||
| render() { | ||
| const { arrow } = this; | ||
| // local vars const ratio = 1; //100 / spec.frameSize; | ||
|
||
| const cornerRadius = spec.cornerRadius; | ||
| const holeRadius = spec.holeRadius; | ||
| const shaftRadius = spec.shaftRadius; | ||
| const frameSize = spec.frameSize; | ||
| const cornerOffset = spec.cornerOffset; | ||
| const bodyRadius = spec.bodyRadius; | ||
|
|
||
| return html` | ||
| <svg | ||
| width="57mm" | ||
| height="63.349mm" | ||
| version="1.1" | ||
| viewBox="0 0 57 63.349" | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| xmlns:xlink="http://www.w3.org/1999/xlink" | ||
| return html`<svg | ||
| width="100mm" | ||
|
||
| height="100mm" | ||
| version="1.1" | ||
| viewBox="0 0 ${100 * mmToPix} ${100 * mmToPix}" | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| xmlns:xlink="http://www.w3.org/1999/xlink" | ||
| > | ||
| <defs> | ||
| <linearGradient | ||
| id="motor-body" | ||
| x1="17.567" | ||
| x2="197.27" | ||
| y1="171.8" | ||
| y2="171.8" | ||
| gradientTransform="matrix(.31539 0 0 .31539 9.0021 56.33)" | ||
| gradientUnits="userSpaceOnUse" | ||
| > | ||
| <linearGradient id="motor-body" x1="0%" x2="120%" y1="0" y2="0" gradientUnits="userSpaceOnUse" > | ||
| <stop stop-color="#666" offset="0" /> | ||
| <stop stop-color="#fff" offset="1" /> | ||
| </linearGradient> | ||
| <linearGradient | ||
| id="linearGradient5454" | ||
| x1="339.07" | ||
| x2="478.3" | ||
| y1="660.79" | ||
| y2="660.79" | ||
| gradientTransform="matrix(.083446 0 0 .083446 9.845 56.471)" | ||
| gradientUnits="userSpaceOnUse" | ||
| > | ||
| <linearGradient id="shaft" x1="0%" x2="100%" y1="0" y2="0" gradientUnits="userSpaceOnUse" > | ||
| <stop stop-color="#9d9d9d" offset="0" /> | ||
| <stop stop-color="#9d9d9d" stop-opacity="0" offset="1" /> | ||
| <stop stop-color="#fdfafa" stop-opacity="0" offset="1" /> | ||
| </linearGradient> | ||
| <linearGradient | ||
| id="linearGradient29501" | ||
| x1="33.418" | ||
| x2="53.905" | ||
| y1="114.39" | ||
| y2="113.37" | ||
| gradientUnits="userSpaceOnUse" | ||
| > | ||
| <linearGradient id="linearGradient29501" x1="0%" x2="200%" y1="0%" y2="150%" gradientUnits="userSpaceOnUse" > | ||
| <stop stop-color="#9d9d9d" offset="0" /> | ||
| <stop stop-color="#fdfafa" offset=".29501" /> | ||
| <stop offset="1" /> | ||
| </linearGradient> | ||
| </defs> | ||
| <!-- Body --> | ||
| <g transform="translate(-14.38 -82.486)"> | ||
| <g stroke-linecap="round" stroke-linejoin="round"> | ||
| <rect | ||
| x="14.543" | ||
| y="82.648" | ||
| width="56.675" | ||
| height="55.731" | ||
| rx="4.7308" | ||
| ry="4.6584" | ||
| fill="url(#motor-body)" | ||
| stroke="#000" | ||
| stroke-width=".3245" | ||
| /> | ||
| <circle cx="20.407" cy="88.675" r="1.7314" fill="#666" stroke-width=".47984" /> | ||
| <circle | ||
| cx="65.732" | ||
| cy="88.585" | ||
| r="1.7314" | ||
| fill="#666" | ||
| stroke-linecap="round" | ||
| stroke-linejoin="round" | ||
| stroke-width=".47984" | ||
| /> | ||
| <ellipse cx="65.704" cy="88.613" rx="1.0232" ry=".99314" fill="#e6e6e6" /> | ||
| <circle | ||
| cx="66.278" | ||
| cy="133.65" | ||
| r="1.7314" | ||
| fill="#666" | ||
| stroke-linecap="round" | ||
| stroke-linejoin="round" | ||
| stroke-width=".47984" | ||
| /> | ||
| <ellipse cx="66.25" cy="133.54" rx="1.0232" ry=".99314" fill="#e6e6e6" /> | ||
| <circle | ||
| cx="19.6" | ||
| cy="133.13" | ||
| r="1.7314" | ||
| fill="#666" | ||
| stroke-linecap="round" | ||
| stroke-linejoin="round" | ||
| stroke-width=".47984" | ||
| /> | ||
| <ellipse cx="19.572" cy="133.16" rx="1.0232" ry=".99314" fill="#ccc" /> | ||
| <ellipse cx="20.378" cy="88.702" rx="1.0232" ry=".99314" fill="#ccc" /> | ||
| </defs> | ||
| <!-- Body --> | ||
| <g transform="scale(${mmToPix})"> | ||
| <g stroke-linecap="round" stroke-linejoin="round"> | ||
| <rect width="${frameSize}" height="${frameSize}" rx="${cornerRadius}" ry="${cornerRadius}" fill="url(#motor-body)" stroke="#000" stroke-width=".3245" /> | ||
| <circle cx="${cornerOffset}" cy="${cornerOffset}" r="${holeRadius}" fill="darkgrey" /> | ||
| <circle cx="${cornerOffset}" cy="${cornerOffset}" r="${holeRadius*0.9}" fill="lightgrey" /> | ||
| <circle cx="${frameSize - cornerOffset}" cy="${cornerOffset}" r="${holeRadius}" fill="darkgrey" /> | ||
| <circle cx="${frameSize - cornerOffset}" cy="${cornerOffset}" r="${holeRadius*0.9}" fill="lightgrey" /> | ||
| <circle cx="${cornerOffset}" cy="${frameSize - cornerOffset}" r="${holeRadius}" fill="darkgrey" /> | ||
| <circle cx="${cornerOffset}" cy="${frameSize - cornerOffset}" r="${holeRadius*0.9}" fill="lightgrey" /> | ||
| <circle cx="${frameSize - cornerOffset}" cy="${frameSize - cornerOffset}" r="${holeRadius}" fill="darkgrey" /> | ||
| <circle cx="${frameSize - cornerOffset}" cy="${frameSize - cornerOffset}" r="${holeRadius*0.9}" fill="lightgrey" /> | ||
| </g> | ||
| <!-- Rotator --> | ||
| <circle | ||
| cx="43.816" | ||
| cy="111.05" | ||
| r="10.25" | ||
| fill="#868686" | ||
| fill-opacity=".89602" | ||
| opacity=".73" | ||
| stroke="url(#linearGradient29501)" | ||
| stroke-width=".41429" | ||
| /> | ||
| <path | ||
| transform="rotate(${this.angle}, 43.82, 111.2)" | ||
| fill="${arrow || 'transparent'}" | ||
| d="M48.706051,111.66821H38.189949L43.448,83.34119Z" | ||
| /> | ||
| <path | ||
| transform="rotate(${this.angle}, 43.82, 111.2)" | ||
| d="m40.056 106.86a5.3616 5.3616 0 0 0-1.9696 4.1497 5.3616 5.3616 0 0 0 5.3616 5.3616 5.3616 5.3616 0 0 0 5.3616-5.3616 5.3616 5.3616 0 0 0-1.9672-4.1497z" | ||
| fill="#4d4d4d" | ||
| stroke="url(#linearGradient5454)" | ||
| stroke-width=".57968" | ||
| /> | ||
| <!-- motor body --> | ||
| <circle cx="${frameSize / 2}" cy="${frameSize / 2}" r="${bodyRadius}" fill="#868686" fill-opacity=".89602" opacity=".73" stroke="url(#shaft)" stroke-width=".41429" /> | ||
| <!-- Rotator --> | ||
| <g > | ||
| <path transform="rotate(${this.angle}, ${frameSize/2},${frameSize/2}) translate(${frameSize/2} ${frameSize/2})" fill="${this.arrow || 'transparent'}" d="m 0 0 l -${shaftRadius} 0 l ${shaftRadius} -${frameSize/2 - 3} l ${shaftRadius} ${frameSize/2 - 3} z" /> | ||
| <path transform="rotate(${this.angle}, ${frameSize/2} ${frameSize/2}) translate(${(frameSize-shaftRadius)/2} ${(frameSize-2*shaftRadius)/2})" d="m 0 0 a ${shaftRadius} ${shaftRadius} 0 1 0 ${shaftRadius} 0 z" fill="#4d4d4d" stroke="url(#shaft)" stroke-width=".57968" /> | ||
| </g> | ||
| <g | ||
| transform="matrix(-.0031398 -.26456 .26456 -.0031398 32.829 149.58)" | ||
| clip-rule="evenodd" | ||
| fill-rule="evenodd" | ||
| stroke-linecap="round" | ||
| stroke-linejoin="round" | ||
| stroke-miterlimit="1.5" | ||
| > | ||
| <!-- Pins --> | ||
| <path | ||
| id="pin" | ||
| fill="#9f9f9f" | ||
| d="m15.259 56.3c-0.382-2.2e-5 -0.74801 0.15196-1.019 0.42194-0.27002 0.26998-0.42104 0.63698-0.42106 1.019-2.2e-5 0.382 0.15096 0.74801 0.42094 1.019 0.27098 0.27002 0.63698 0.42204 1.019 0.42206 5.242 2.96e-4 23.147 0.0013 26.132 0.0015 0.233 1.4e-5 0.42301-0.18998 0.42302-0.42398 3.1e-5 -0.545 8.4e-5 -1.489 1.15e-4 -2.035 1.3e-5 -0.233-0.18998-0.42301-0.42298-0.42302-2.985-1.68e-4 -20.89-0.0012-26.132-0.0015z" | ||
| /> | ||
| <!-- Pins --> | ||
| <path id="pin" transform="translate(${frameSize/2 - 3.75} ${frameSize})" fill="#9f9f9f" d="m 0 0 c .5 0 .5 0 .5 .5 v 5 c -.5 .5 -.5 .5 -1 0 v -5 c 0 -.5 0 -.5 .5 -.5" /> | ||
| <use xlink:href="#pin" x="2.54" /> | ||
| <use xlink:href="#pin" x="5.08" /> | ||
| <use xlink:href="#pin" x="7.62" /> | ||
| <use xlink:href="#pin" y="-9.6" /> | ||
| <use xlink:href="#pin" y="-19.2" /> | ||
| <use xlink:href="#pin" y="-28.8" /> | ||
| <!-- Text --> | ||
| <text font-family="arial" font-size="14.667px" text-align="center" text-anchor="middle" > | ||
| <tspan x="${frameSize/ 2}" y="${frameSize - spec.textSize/2}" font-size="${spec.textSize/mmToPix}px">${this.value} ${this.units}</tspan> | ||
| </text> | ||
| <!-- Text --> | ||
| <text | ||
| transform="rotate(90)" | ||
| font-family="arial" | ||
| font-size="14.667px" | ||
| text-align="center" | ||
| text-anchor="middle" | ||
| > | ||
| <tspan x="45" y="-58.62619" font-size="14px">${this.units}</tspan> | ||
| <tspan x="45" y="-75.066772" font-size="24px">${this.value}</tspan> | ||
| </text> | ||
| </g> | ||
| </g> | ||
| </svg> | ||
| `; | ||
| </svg>`; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add fallback behavior when
sizeis not valid (e.g. use the values of size 17, or the closest size)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this what happens when specifying the property as one of a set of values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Storybook does validate the
size, but in Wokwi users can change the size on the diagram to an invalid value and then they get an error.