import operator from math import cos, sin, atan2, radians, degrees, sqrt import koko.lib.shapes2d as s2d from koko.lib.text import text from numpy import * class PCB(object): def __init__(self, x0, y0, width, height, chamfer_distance=0): self.x0 = x0 self.y0 = y0 self.width = width self.height = height self.components = [] self.connections = [] self._cutout = None self.custom_cutout = None self.custom_layers = {} self.chamfer_distance = chamfer_distance @property def traces(self): L = [c.pads for c in self.components] + [c.traces[0] for c in self.connections] if L: t = reduce(operator.add, L) #L = [c.holes for c in self.components if c.holes is not None] #L.extend([c.holes for c in self.connections if c.holes is not None]) #if L: # t = t - reduce(operator.add,L) return t else: return None @property def traces_other_side(self): L = [c.traces[1] for c in self.connections if c.traces[1] is not None] if L: t = reduce(operator.add, L) #L = [c.holes for c in self.components if c.holes is not None] #L.extend([c.holes for c in self.connections if c.holes is not None]) #if L: # t = t - reduce(operator.add,L) return t else: return None @property def holes(self): L = [c.holes for c in self.components if c.holes is not None] L.extend([c.holes for c in self.connections if c.holes is not None]) if L: t = reduce(operator.add,L) return t else: return None @property def part_labels(self): L = [c.label for c in self.components if c.label is not None] return reduce(operator.add, L) if L else None @property def part_shadows(self): L = [c.shadow_shape for c in self.components if c.shadow_shape is not None] return reduce(operator.add, L) if L else None @property def pin_labels(self): L = [c.pin_labels for c in self.components if c.pin_labels is not None] return reduce(operator.add, L) if L else None @property def cutout(self): if self.custom_cutout is not None: if self.holes: return self.custom_cutout - self.holes else: return self.custom_cutout outer = s2d.rectangle(self.x0, self.x0 + self.width, self.y0, self.y0 + self.height) if self.chamfer_distance: c = self.chamfer_distance c1 = s2d.triangle(self.x0,self.y0,self.x0,self.y0+c,self.x0+c,self.y0) c2 = s2d.triangle(self.x0+self.width,self.y0+self.height, self.x0+self.width, self.y0+self.height-c, self.x0+self.width-c, self.y0+self.height) c3 = s2d.triangle(self.x0,self.y0+self.height, self.x0+c, self.y0+self.height, self.x0, self.y0+self.height-c) c4 = s2d.triangle(self.x0+self.width,self.y0, self.x0+self.width-c, self.y0, self.x0+self.width, self.y0+c) outer -= c1+c2+c3+c4 #L = [c.holes for c in self.components if c.holes is not None] #L.extend([c.holes for c in self.connections if c.holes is not None]) return outer - self.holes if self.holes else outer @property def layout(self): T = [] if self.part_labels: T.append(s2d.color(self.part_labels, (125, 200, 60))) if self.pin_labels: T.append(s2d.color(self.pin_labels, (255, 90, 60))) if self.traces: T.append(s2d.color(self.traces-self.holes, (125, 90, 60))) if self.traces_other_side: T.append(s2d.color(self.traces_other_side-self.holes, (90, 60, 125))) if self.part_shadows: T.append(s2d.color(self.part_shadows-self.holes,((55,55,60)))) for v in sorted(self.custom_layers.values(),key=lambda v: -v['position']): if v['visible']: T.append(s2d.color(v['layer'],v['color'])) T.append(s2d.color(self.cutout, (35,35,40))) return T def __iadd__(self, rhs): if isinstance(rhs, Component): self.components.append(rhs) elif isinstance(rhs, Connection): self.connections.append(rhs) else: raise TypeError("Invalid type for PCB addition (%s)" % type(rhs)) return self def add_custom_layer(self,name,layer,color): self.custom_layers[name] = {'layer':layer,'color':color,'position':len(self.custom_layers),'visible':1} def hide_layer(self,name): self.custom_layers[name]['visible'] = 0 def connectH(self, *args, **kwargs): ''' Connects a set of pins or points, traveling first horizontally then vertically ''' width = kwargs['width'] if 'width' in kwargs else 0.016 mode = kwargs['mode'] if 'mode' in kwargs else 'explicit' sides = kwargs['sides'] if 'sides' in kwargs else [0 for a in args[:-1]] new_sides = [] points = [] args = list(args) for i,p in enumerate(args): if not isinstance(p,BoundPin): if mode=='diff': args[i] = Point(args[i-1].x+p[0],args[i-1].y+p[1]) elif mode=='explicit': args[i] = Point(*p) else: raise NotImplementedError("Unknown mode type %s"%mode) for A, B, s in zip(args[:-1], args[1:], sides): points.append(A); new_sides.append(s) if (A.x != B.x): points.append(Point(B.x, A.y)); new_sides.append(s) if A.y != B.y: points.append(B) c = Connection(width, *points, sides=new_sides) self.connections.append(c) return c def connectV(self, *args, **kwargs): ''' Connects a set of pins or points, travelling first vertically then horizontally. ''' width = kwargs['width'] if 'width' in kwargs else 0.016 mode = kwargs['mode'] if 'mode' in kwargs else 'explicit' sides = kwargs['sides'] if 'sides' in kwargs else [0 for a in args[:-1]] new_sides = [] points = [] args = list(args) for i,p in enumerate(args): if not isinstance(p,BoundPin): if mode=='diff': args[i] = Point(args[i-1].x+p[0],args[i-1].y+p[1]) elif mode=='explicit': args[i] = Point(*p) else: raise NotImplementedError("Unknown mode type %s"%mode) for A, B, s in zip(args[:-1], args[1:], sides): points.append(A); new_sides.append(s) if (A.y != B.y): points.append(Point(A.x, B.y)); new_sides.append(s) if A.x != B.x: points.append(B) c = Connection(width, *points, sides=new_sides) self.connections.append(c) return c ################################################################################ class Component(object): ''' Generic PCB component. ''' def __init__(self, x, y, rot=0, name='',label_size=0.05): ''' Constructs a Component object x X position y Y position rotation angle (degrees) name String ''' self.x = x self.y = y self.rot = rot self.name = name self.label_size = label_size def __getitem__(self, i): if isinstance(i, str): try: pin = [p for p in self.pins if p.name == i][0] except IndexError: raise IndexError("No pin with name %s" % i) elif isinstance(i, int): try: pin = self.pins[i-1] except IndexError: raise IndexError("Pin %i is not in array" %i) return BoundPin(pin, self) @property def pads(self): pads = reduce(operator.add, [p.pad for p in self.pins]) return s2d.move(s2d.rotate(pads, self.rot), self.x, self.y) @property def holes(self): if self.vias: holes = reduce(operator.add,[v.hole for v in self.vias]) return s2d.move(s2d.rotate(holes,self.rot), self.x, self.y) else: return None @property def pin_labels(self): L = [] for p in self.pins: p = BoundPin(p, self) if p.pin.name: t = s2d.rotate(text(p.pin.name, 0, 0, p.pin.label_size),self.rot+p.pin.label_rot) L.append(s2d.move(t, p.x, p.y)) return reduce(operator.add, L) if L else None @property def label(self): return text(self.name, self.x, self.y, self.label_size) @property def shadow_shape(self): try: return s2d.move(s2d.rotate(self.shadow, self.rot),self.x, self.y) except AttributeError: return None ################################################################################ class Pin(object): ''' PCB pin, with name, shape, and position ''' def __init__(self, x, y, shape, name='', label_size=.03, label_rot=0): self.x = x self.y = y self.shape = shape self.name = name self.label_size = label_size self.label_rot = label_rot @property def pad(self): return s2d.move(self.shape, self.x, self.y) ################################################################################ class Via(object): ''' PCB via, with shape, and position ''' def __init__(self, x, y, shape): self.x = x self.y = y self.shape = shape @property def hole(self): return s2d.move(self.shape, self.x, self.y) ################################################################################ class BoundPin(object): ''' PCB pin localized to a specific component (so that it has correct x and y positions) ''' def __init__(self, pin, component): self.pin = pin self.component = component @property def x(self): return (cos(radians(self.component.rot)) * self.pin.x - sin(radians(self.component.rot)) * self.pin.y + self.component.x) @property def y(self): return (sin(radians(self.component.rot)) * self.pin.x + cos(radians(self.component.rot)) * self.pin.y + self.component.y) @property def point(self): return Point(self.x,self.y) ################################################################################ class Point(object): ''' Object with x and y member variables ''' def __init__(self, x, y): self.x = x self.y = y def __iter__(self): return iter([self.x, self.y]) def __add__(self, p): return Point(self.x+p.x,self.y+p.y) def __sub__(self, p): return Point(self.x-p.x,self.y-p.y) def __rmul__(self,a): return Point(a*self.x,a*self.y) def magnitude(self): return sqrt(self.x*self.x + self.y+self.y) def normalized(self): return Point(self.x/self.magnitude(), self.y/self.magnitude()) @property def point(self): return self ################################################################################ class Connection(object): ''' Connects two pins via a series of intermediate points ''' def __init__(self, width, *args, **kwargs): self.width = width self.points = [ a if isinstance(a, BoundPin) else Point(*a) for a in args ] self.sides = kwargs['sides'] if 'sides' in kwargs else [0 for a in args[:-1]] #0 is base side, 1 is other side self.holes = None self.jumpers = [] def add_jumper(self,p,rot=0): self.jumpers.append((p,rot)) return self def cut_corners(self,idx): for i in idx: i,v = i #unpack index and distance assert(i>0) #start corner numbering at 1 assert(i dp: self.points = self.points[:i] + \ [Point(self.points[i].x-v/dm*(self.points[i].x-self.points[i-1].x ), self.points[i].y-v/dm*(self.points[i].y-self.points[i-1].y )), Point(self.points[i].x+v/dp*(self.points[i+1].x-self.points[i].x ), self.points[i].y+v/dp*(self.points[i+1].y-self.points[i].y )) ] + \ self.points[i+1:] self.sides.insert(i,self.sides[i]) #else: # self.points[i] = self.points[i] - dm/dp*(self.points[i]-self.points[i+1]) return self @property def traces(self): _pad_1206 = s2d.rectangle(-0.025, 0.025, -0.034, 0.034) _pad_via = s2d.circle(0,0,.023) #s2d.rectangle(-0.025, 0.025, -0.025, 0.025) _hole_via = s2d.circle(0,0,.016) _jumper_pad = s2d.move(_pad_1206,-.05,0) + s2d.move(_pad_1206,.05,0) _cut_1206 = s2d.rectangle(-.06,.06,-.034,.034) jumper_cuts = [] jumper_pads = [] for p,r in self.jumpers: jumper_cuts.append(s2d.move(s2d.rotate(_cut_1206,r),p[0],p[1])) jumper_pads.append(s2d.move(s2d.rotate(_jumper_pad,r),p[0],p[1])) t = [[],[]] for p1, p2, side in zip(self.points[:-1], self.points[1:], self.sides): d = sqrt((p1.x - p2.x)**2 + (p1.y - p2.y)**2) if p2 != self.points[-1]: d += self.width/2 a = atan2(p2.y - p1.y, p2.x - p1.x) r = s2d.rounded_rectangle(0, d, -self.width/2, self.width/2,1.) t[side].append(s2d.move(s2d.rotate(r, degrees(a)), p1.x, p1.y)) result0 = reduce(operator.add, t[0]) try: result1 = reduce(operator.add, t[1]) except TypeError: result1 = None #calculate locations for via holes and pads for s1,s2,p in zip(self.sides[:-1],self.sides[1:],self.points[1:-1]): if s1!=s2: result0 += s2d.move(_pad_via,p.x,p.y) result1 += s2d.move(_pad_via,p.x,p.y) self.holes += s2d.move(_hole_via,p.x,p.y) if len(self.jumpers)!=0: result0 -= reduce(operator.add,jumper_cuts) result0 += reduce(operator.add,jumper_pads) return result0, result1 ################################################################################ # Discrete passive components ################################################################################ _pad_1206 = s2d.rectangle(-0.032, 0.032, -0.034, 0.034) class R_1206(Component): ''' 1206 Resistor ''' pins = [Pin(-0.06, 0, _pad_1206), Pin(0.06, 0, _pad_1206)] prefix = 'R' vias = [] class C_1206(Component): ''' 1206 Capacitor ''' pins = [Pin(-0.06, 0, _pad_1206), Pin(0.06, 0, _pad_1206)] prefix = 'C' vias = [] _pad_0805 = s2d.rectangle(-.023,.023, -.027, .027) class R_0805(Component): ''' 0805 Resistor ''' pins = [Pin(-0.04, 0, _pad_0805), Pin(0.04, 0, _pad_0805)] prefix = 'R' vias = [] class C_0805(Component): ''' 0805 Capacitor ''' pins = [Pin(-0.04, 0, _pad_0805), Pin(0.04, 0, _pad_0805)] prefix = 'C' vias = [] _pad_SJ = s2d.rectangle(-0.02, 0.02, -0.03, 0.03) class SJ(Component): ''' Solder jumper ''' pins = [Pin(-0.029, 0, _pad_SJ), Pin(0.029, 0, _pad_SJ)] prefix = 'SJ' vias = [] _pad_SOD_123 = s2d.rectangle(-0.02, 0.02, -0.024, 0.024) class D_SOD_123(Component): ''' Diode ''' pins = [Pin(-0.07, 0, _pad_SOD_123, 'A'), Pin(0.07, 0, _pad_SOD_123, 'C')] prefix = 'D' vias = [] ################################################################################ # Connectors ################################################################################ _pad_USB_trace = s2d.rectangle(-0.0075, 0.0075, -0.04, 0.04) _pad_USB_foot = s2d.rectangle(-0.049, 0.049, -0.043, 0.043) class USB_mini_B(Component): ''' USB mini B connector Hirose UX60-MB-5ST ''' pins = [ Pin(0.063, 0.24, _pad_USB_trace, 'G'), Pin(0.0315, 0.24, _pad_USB_trace), Pin(0, 0.24, _pad_USB_trace, '+'), Pin(-0.0315, 0.24, _pad_USB_trace, '-'), Pin(-0.063, 0.24, _pad_USB_trace, 'V'), Pin( 0.165, 0.21, _pad_USB_foot), Pin(-0.165, 0.21, _pad_USB_foot), Pin( 0.165, 0.0, _pad_USB_foot), Pin(-0.165, 0.0, _pad_USB_foot) ] prefix = 'J' vias = [] _pad_header = s2d.rectangle(-0.06, 0.06, -0.025, 0.025) _pad_header_skinny = s2d.rectangle(-0.06, 0.06, -0.020, 0.020) class Header_4(Component): ''' 4-pin header fci 95278-101a04lf bergstik 2x2x0.1 ''' pins = [ Pin(-0.107, 0.05, _pad_header), Pin(-0.107, -0.05, _pad_header), Pin( 0.107, -0.05, _pad_header), Pin( 0.107, 0.05, _pad_header) ] prefix = 'J' vias = [] class Header_4_skinny(Component): ''' 4-pin header fci 95278-101a04lf bergstik 2x2x0.1 ''' pins = [ Pin(-0.107, 0.05, _pad_header_skinny), Pin(-0.107, -0.05, _pad_header_skinny), Pin( 0.107, -0.05, _pad_header_skinny), Pin( 0.107, 0.05, _pad_header_skinny) ] prefix = 'J' vias = [] class Header_Power(Component): ''' 4-pin header fci 95278-101a04lf bergstik 2x2x0.1 ''' pins = [ Pin(-0.107, 0.05, _pad_header,"V"), Pin(-0.107, -0.05, _pad_header,"GND"), Pin( 0.107, -0.05, _pad_header), Pin( 0.107, 0.05, _pad_header) ] prefix = 'J' vias = [] class Header_ISP(Component): ''' ISP programming header FCI 95278-101A06LF Bergstik 2x3x0.1 ''' pins = [ Pin(-0.107, 0.1, _pad_header, 'GND'), Pin(-0.107, 0, _pad_header, 'MOSI'), Pin(-0.107, -0.1, _pad_header, 'V'), Pin( 0.107, -0.1, _pad_header, 'MISO'), Pin( 0.107, 0, _pad_header, 'SCK'), Pin( 0.107, 0.1, _pad_header, 'RST') ] prefix = 'J' vias = [] class Header_ISP_skinny(Component): ''' ISP programming header FCI 95278-101A06LF Bergstik 2x3x0.1 ''' pins = [ Pin(-0.107, 0.1, _pad_header_skinny, 'GND'), Pin(-0.107, 0, _pad_header_skinny, 'MOSI'), Pin(-0.107, -0.1, _pad_header_skinny, 'V'), Pin( 0.107, -0.1, _pad_header_skinny, 'MISO'), Pin( 0.107, 0, _pad_header_skinny, 'SCK'), Pin( 0.107, 0.1, _pad_header_skinny, 'RST') ] prefix = 'J' vias = [] #shadow = s2d.rectangle(-.06,8/25.4,-.325,.325) class Header_FTDI(Component): ''' FTDI cable header ''' pins = [ Pin(0, 0.25, _pad_header, 'GND'), Pin(0, 0.15, _pad_header, 'CTS'), Pin(0, 0.05, _pad_header, 'VCC'), Pin(0, -0.05, _pad_header, 'TX'), Pin(0, -0.15, _pad_header, 'RX'), Pin(0, -0.25, _pad_header, 'RTS') ] prefix = 'J' vias = [] shadow = s2d.rectangle(-.06,8/25.4,-.325,.325) class Header_FTDI_skinny(Component): ''' FTDI cable header ''' pins = [ Pin(0, 0.25, _pad_header_skinny, 'GND'), Pin(0, 0.15, _pad_header_skinny, 'CTS'), Pin(0, 0.05, _pad_header_skinny, 'VCC'), Pin(0, -0.05, _pad_header_skinny, 'TX'), Pin(0, -0.15, _pad_header_skinny, 'RX'), Pin(0, -0.25, _pad_header_skinny, 'RTS') ] prefix = 'J' vias = [] shadow = s2d.rectangle(-.06,8/25.4,-.325,.325) class ScrewTerminal(Component): pitch = .131 _pad = s2d.rectangle(-0.04, 0.04, -0.04, 0.04) _via = s2d.circle(0,0,.025) pins = [Pin(-.5*pitch,0,_pad),Pin(.5*pitch,0,_pad)] vias = [Via(-.5*pitch,0,_via),Via(.5*pitch,0,_via)] shadow = s2d.rectangle(-3.5/25.4,3.5/25.4,-3/25.4,3/25.4) class ScrewTerminal3(Component): pitch = .131 _pad = s2d.rectangle(-0.04, 0.04, -0.04, 0.04) _via = s2d.circle(0,0,.025) pins = [Pin(-pitch,0,_pad),Pin(0,0,_pad),Pin(pitch,0,_pad)] vias = [Via(-pitch,0,_via),Via(0,0,_via),Via(pitch,0,_via)] shadow = s2d.rectangle(-5.35/25.4,5.35/25.4,-3/25.4,3/25.4) class JST_2(Component): pitch = 2./25.4 _pad = s2d.rectangle(-0.5/25.4,0.5/25.4, -1.75/25.4, 1.75/25.4) _pad2 = s2d.rectangle(-.75/25.4,.75/25.4,-1.7/25.4,1.7/25.4) y2 = -4.55/25.4 pins = [Pin(-.5*pitch,0,_pad,'VCC'),Pin(.5*pitch,0,_pad,'GND'),Pin(-.5*pitch-2.35/25.4,y2,_pad2),Pin(.5*pitch+2.35/25.4,y2,_pad2)] vias = [] shadow = s2d.rectangle(-3.95/25.4,3.95/25.4,y2-1.7/25.4,1.75/25.4) ################################################################################ # SOT-23 components ################################################################################ _pad_SOT23 = s2d.rectangle(-.02,.02,-.012,.012) class NMOS_SOT23(Component): ''' NMOS transistor in SOT23 package Fairchild NDS355AN ''' pins = [ Pin(0.045, -0.0375, _pad_SOT23,'G'), Pin(0.045, 0.0375, _pad_SOT23,'S'), Pin(-0.045, 0, _pad_SOT23,'D') ] prefix = 'Q' vias = [] class PMOS_SOT23(Component): ''' PMOS transistor in SOT23 package Fairchild NDS356AP ''' pins = [ Pin(-0.045, -0.0375, _pad_SOT23,'G'), Pin(-0.045, 0.0375, _pad_SOT23,'S'), Pin(0.045, 0, _pad_SOT23,'D') ] prefix = 'Q' vias = [] class Regulator_SOT23(Component): ''' SOT23 voltage regulator ''' pins = [ Pin(-0.045, -0.0375, _pad_SOT23,'Out'), Pin(-0.045, 0.0375, _pad_SOT23,'In'), Pin(0.045, 0, _pad_SOT23,'GND') ] prefix = 'U' vias = [] class Regulator_LM3480(Component): ''' SOT23 voltage regulator, LM3480 ''' pins = [ Pin(-0.045, -0.0375, _pad_SOT23,'In'), Pin(-0.045, 0.0375, _pad_SOT23,'Out'), Pin(0.045, 0, _pad_SOT23,'GND') ] prefix = 'U' vias = [] ########### # H Bridge ############ _pad_SOIC = s2d.rectangle(-.041,.041,-.015,.015) class A4953_SOICN(Component): pins = [ Pin(-.11, .075,_pad_SOIC+s2d.circle(-.041,0,.015),"GND"), Pin(-.11, .025,_pad_SOIC,"IN2"), Pin(-.11,-.025,_pad_SOIC,"IN1"), Pin(-.11,-.075,_pad_SOIC,"VREF"), Pin( .11,-.075,_pad_SOIC,"VBB"), Pin( .11,-.025,_pad_SOIC,"OUT1"), Pin( .11, .025,_pad_SOIC,"LSS"), Pin( .11, .075,_pad_SOIC,"OUT2"), Pin( 0,0,s2d.rectangle(-.04,.04,-.075,.075),"") ] prefix = 'U' vias = [] ################################################################################ # Clock crystals ################################################################################ _pad_XTAL_NX5032GA = s2d.rectangle(-.039,.039,-.047,.047) class XTAL_NX5032GA(Component): pins = [Pin(-0.079, 0, _pad_XTAL_NX5032GA), Pin(0.079, 0, _pad_XTAL_NX5032GA)] prefix = 'X' vias = [] ################################################################################ # Atmel microcontrollers ################################################################################ _pad_SOIC = s2d.rectangle(-0.041, 0.041, -0.015, 0.015) class ATtiny45_SOIC(Component): pins = [] y = 0.075 for t in ['RST', 'PB3', 'PB4', 'GND']: pins.append(Pin(-0.14, y, _pad_SOIC, t)) y -= 0.05 for p in ['PB0', 'PB1', 'PB2', 'VCC']: y += 0.05 pins.append(Pin(0.14, y, _pad_SOIC, p)) del y prefix = 'U' vias = [] class ATtiny44_SOIC(Component): pins = [] y = 0.15 for t in ['VCC', 'PB0', 'PB1', 'PB3', 'PB2', 'PA7', 'PA6']: pad = _pad_SOIC + s2d.circle(-0.041, 0, 0.015) if t == 'VCC' else _pad_SOIC pins.append(Pin(-0.12, y, pad, t)) y -= 0.05 for t in ['PA5', 'PA4', 'PA3', 'PA2', 'PA1', 'PA0', 'GND']: y += 0.05 pins.append(Pin(0.12, y, _pad_SOIC, t)) prefix = 'U' vias = [] _pad_TQFP_h = s2d.rectangle(-0.025, 0.025, -0.008, 0.008) _pad_TQFP_v = s2d.rectangle(-0.008, 0.008, -0.025, 0.025) class ATmega88_TQFP(Component): pins = [] y = 0.1085 for t in ['PD3', 'PD4', 'GND', 'VCC', 'GND', 'VCC', 'PB6', 'PB7']: pins.append(Pin(-0.18, y, _pad_TQFP_h, t)) y -= 0.031 x = -0.1085 for t in ['PD5', 'PD6', 'PD7', 'PB0', 'PB1', 'PB2', 'PB3', 'PB4']: pins.append(Pin(x, -0.18, _pad_TQFP_v, t)) x += 0.031 y = -0.1085 for t in ['PB5', 'AVCC', 'ADC6', 'AREF', 'GND', 'ADC7', 'PC0', 'PC1']: pins.append(Pin(0.18, y, _pad_TQFP_h, t)) y += 0.031 x = 0.1085 for t in ['PC2', 'PC3', 'PC4', 'PC5', 'PC6', 'PD0', 'PD1', 'PD2']: pins.append(Pin(x, 0.18, _pad_TQFP_v, t)) x -= 0.031 del x, y prefix = 'U' vias = [] ################################################################################ # CBA logo ################################################################################ _pin_circle_CBA = s2d.circle(0, 0, 0.02) _pin_square_CBA = s2d.rectangle(-0.02, 0.02, -0.02, 0.02) class CBA(Component): pins = [] for i in range(3): for j in range(3): pin = _pin_circle_CBA if i == 2-j and j >= 1 else _pin_square_CBA pins.append(Pin(0.06*(i-1), 0.06*(j-1), pin)) vias = [] class ESP8266_03(Component): _pad = s2d.rectangle(-0.04, 0.04, -0.03, 0.03) _via = s2d.circle(0,0,.019) names = ['VCC','GPIO14','GPIO12','GPIO13','GPIO15','GPIO2','GPIO0', 'WIFI_ANT','CH-PD','GPIO18','URXD','UTXD','NC','GND'] w = 12.2/25.4 l = 17.4/25.4 wp = 12.2/25.4 lp = .5 dp = 2/25.4 ys = arange(.5*lp-dp ,-.5*lp-.001-dp,-dp) pts = vstack(( dstack((-.5*wp*ones_like(ys),ys))[0], dstack((.5*wp*ones_like(ys),ys))[0] )) pins = [Pin(p[0],p[1],_pad,n) for n,p in zip(names,pts)] vias = []#[Via(p[0],p[1],_via) for n,p in zip(names,pts)] shadow = s2d.rectangle(-.5*w,.5*w,-.5*l,.5*l) prefix = 'IC' class ZLDO1117(Component): '''3.3 V 1 A regulator, SOT223''' _pad1 = s2d.rectangle(-.6/25.4,.6/25.4,-.8/25.4,.8/25.4) _pad2 = s2d.rectangle(-1.65/25.4,1.65/25.4,-.6/25.4,.6/25.4) pins = [ Pin(-2.3/25.4, -3.2/25.4, _pad1,'GND'), Pin(0, -3.2/25.4, _pad1,'Vout'), Pin(2.3/25.4, -3.2/25.4, _pad1,'Vin'), Pin(0, 3.2/25.4, _pad2,'Vout2'), ] prefix = 'U' vias = [] class AstarMicro(Component): ''' Polulo Astar micro ''' _pad = s2d.rectangle(-0.04, 0.04, -0.025, 0.025) _via = s2d.circle(0,0,.019) #flip names since through hole names = [ 'VIN','GND','5V','3v3','RST','12/A11/PWM','11','10/A10/PWM','A1','A0', '9/A9/PWM','8/A8','7','6/A7/PWM','5/PWM','4/A6','3/PWM','2','1','0'] w = .6 l = 1. wp = .5 lp = .9 ys = arange(.5*lp,-.5*lp-.001,-.1) os = 0*.13*(arange(shape(ys)[0])%2-.5) pts = vstack(( dstack((-.5*wp*ones_like(ys)+os,ys[::-1]))[0], dstack((.5*wp*ones_like(ys)-os,ys))[0] )) pins = [Pin(p[0],p[1],_pad,n) for n,p in zip(names,pts)] vias = [Via(p[0],p[1],_via) for n,p in zip(names,pts)] shadow = s2d.rectangle(-.5*w,.5*w,-.5*l,.5*l) prefix = 'IC' class Header_bldc_skinny(Component): ''' brushless motor logic ''' _pad_header_skinny = s2d.rectangle(-0.06, 0.06, -0.020, 0.020) pins = [ Pin(0, 0.1, _pad_header_skinny, 'GND'), Pin(0, -0.0, _pad_header_skinny, 'VCC'), Pin(0, -0.1, _pad_header_skinny, 'RC') ] prefix = 'J' shadow = s2d.rectangle(-.06,8/25.4,-.325,.325) vias = [] class A4988_Carrier(Component): ''' Stepper driver carrier black from pololu ''' _pad = s2d.rectangle(-0.04, 0.04, -0.028, 0.028) _via = s2d.circle(0,0,.019) names = ['VMOT','GMOT','2B','2A','1A','1B','VDD','GND','DIR','STEP','SLP','RST','MS3','MS2','MS1','EN'] ys = arange(.4,-.4+.001,-.1)-.05 pts = vstack(( dstack((-.25*ones_like(ys),ys))[0], dstack((.25*ones_like(ys),ys[::-1]))[0] )) pins = [Pin(p[0],p[1],_pad,n) for n,p in zip(names,pts)] vias = [Via(p[0],p[1],_via) for n,p in zip(names,pts)] prefix = 'IC' shadow = s2d.rectangle(-.3,.3,-.45,.45) class CDRH2D18(Component): '''Power Inductor''' def chamfered_rectangle(x0,x1,y0,y1,c): r = s2d.rectangle(x0,x1,y0,y1) c1 = s2d.triangle(x0,y0,x0,y0+c,x0+c,y0) c2 = s2d.triangle(x1,y1, x1, y1-c, x1-c, y1) c3 = s2d.triangle(x0,y1, x0+c, y1, x0, y1-c) c4 = s2d.triangle(x1,y0, x1-c, y0, x1, y0+c) return r-c1-c2-c3-c4 _pad = s2d.rectangle(-.65/25.4,.65/25.4,-.65/25.4,.65/25.4) pins = [Pin(-1.5/25.5,0,_pad), Pin(1.5/25.5,0,_pad)] vias = [] shadow = s2d.rotate(chamfered_rectangle(-1.5/25.4,1.5/25.4,-1.5/25.4, 1.5/25.4,1/25.5),45) prefix='I' class LTC35881(Component): ''' Energy Scavenger ''' _pad = s2d.rectangle(-.889/2/25.4, .889/2/25.4,-.25/2/25.4, .25/2/25.4) p = .5/25.4 pins = [ Pin(0, 0, s2d.rectangle(-1.68/2/25.4,1.68/2/25.4,-1.88/2/25.4,1.88/2/25.4), 'GND'), Pin(-2.1/25.4, 2*p,_pad,'PZ1',label_size=.015,label_rot=0), Pin(-2.1/25.4, 1*p,_pad,'PZ2',label_size=.015,label_rot=0), Pin(-2.1/25.4, 0,_pad,'CAP',label_size=.015,label_rot=0), Pin(-2.1/25.4,-1*p,_pad,'VIN',label_size=.015,label_rot=0), Pin(-2.1/25.4,-2*p,_pad,'SW',label_size=.015,label_rot=0), Pin(2.1/25.4, -2*p,_pad,'VOUT',label_size=.015,label_rot=0), Pin(2.1/25.4, -1*p,_pad,'VIN2',label_size=.015,label_rot=0), Pin(2.1/25.4, 0,_pad,'D1',label_size=.015,label_rot=0), Pin(2.1/25.4, 1*p,_pad,'D0',label_size=.015,label_rot=0), Pin(2.1/25.4, 2*p,_pad,'PGOOD',label_size=.015,label_rot=0) ] prefix = 'J' h = 2.9/25.4; w = 2.8/25.4; shadow = s2d.rectangle(-.5*w,.5*w,-.5*h,.5*h) vias = [] class DSK414(Component): '''Dynacap, ELNA, 220mF''' pins = [ Pin(0,5.15/25.4, s2d.rectangle(-2.4/25.4,2.4/25.4,-1./25.4,1/25.4),'+'), Pin(0,-5/25.4, s2d.rectangle(-2/25.4,2/25.4,-.85/25.4,.81/25.4),'-') ] vias = [] shadow = s2d.rectangle(-2.5/25.4,2.5/25.4,-5.85/25.4, 6.15/25.4) shadow += s2d.circle(0,0,3.4/25.4) prefix='C' class EECRG(Component): '''Panasonic 1F, 3.6 V''' _pad = s2d.rectangle(-.02,.02,-.035,.035) pins = [ Pin(-10/25.4, 0, _pad), Pin(10/25.4, 0, _pad) ] _via = s2d.rectangle(-.1/25.4,.1/25.4,-.5/25.4,.5/25.4) vias = [Via(p.x,p.y,_via) for p in pins] shadow = s2d.rectangle(0,0,0,0) prefix='C' class EEE1EA101XP(Component): '''Panasonic 100uF, 25V''' _pad = s2d.rectangle(-.6/25.4,.6/25.4,-1.35/25.4,1.35/25.4) pins = [ Pin(0, 2.2/25.4, _pad), Pin(0, -2.2/25.4, _pad) ] #_via = s2d.rectangle(-.1/25.4,.1/25.4,-.5/25.4,.5/25.4) vias = [] def half_chamfered_rectangle(x0,x1,y0,y1,c): r = s2d.rectangle(x0,x1,y0,y1) c1 = s2d.triangle(x0,y0,x0,y0+c,x0+c,y0) c2 = s2d.triangle(x1,y1, x1, y1-c, x1-c, y1) c3 = s2d.triangle(x0,y1, x0+c, y1, x0, y1-c) c4 = s2d.triangle(x1,y0, x1-c, y0, x1, y0+c) return r-c1-c4 shadow = half_chamfered_rectangle(-3.3/25.4,3.3/25.4,-3.3/25.4,3.3/25.4,1/25.4) prefix='C'