diff --git a/CHANGELOG.md b/CHANGELOG.md index c2186843..3a9551b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Support for Eurocircuits drill adjust to fix small OARs. + Option `eurocircuits_reduce_holes`. (#227) ## [1.3.0] - 2022-09-08 diff --git a/kibot/out_report.py b/kibot/out_report.py index e79ab453..f09de780 100644 --- a/kibot/out_report.py +++ b/kibot/out_report.py @@ -32,6 +32,10 @@ from . import log logger = log.get_logger() INF = float('inf') +# This OAR is the minimum Eurocircuits does without extra charge +EC_SMALL_OAR = 0.125*pcbnew.IU_PER_MM +# The minimum drill tool +EC_MIN_DRILL = 0.1*pcbnew.IU_PER_MM def do_round(v, dig): @@ -194,6 +198,10 @@ class ReportOptions(BaseOptions): Note that the extension should match the `convert_to` value """ self.eurocircuits_class_target = '10F' """ Which Eurocircuits class are we aiming at """ + self.eurocircuits_reduce_holes = 0.45 + """ When computing the Eurocircuits category: Final holes sizes smaller or equal to this given + diameter can be reduced to accommodate the correct annular ring values. + Use 0 to disable it """ super().__init__() self._expand_id = 'report' self._expand_ext = 'txt' @@ -463,6 +471,20 @@ class ReportOptions(BaseOptions): self.bb_w = x2-x1 self.bb_h = y2-y1 + def compute_oar(self, pad, hole): + """ Compute the OAR and the corrected OAR for Eurocircuits """ + oar_ec = oar = (pad-hole)/2 + if oar < EC_SMALL_OAR and oar > 0 and hole < self.eurocircuits_reduce_holes*pcbnew.IU_PER_MM: + # This hole is classified as "via hole" and has a problematic OAR + hole_ec = max(adjust_drill(pad-2*EC_SMALL_OAR, is_pth=False), EC_MIN_DRILL) + oar_ec = (pad-hole_ec)/2 + if GS.debug_level > 2: + logger.debug('Adjusting drill from {} to {} to get an OAR of {}'. + format(to_mm(hole), to_mm(hole_ec), to_mm(oar_ec))) + else: + hole_ec = hole + return oar, oar_ec, hole_ec + def collect_data(self, board): ds = board.GetDesignSettings() self.extra_pth_drill = GS.global_extra_pth_drill*pcbnew.IU_PER_MM @@ -505,10 +527,12 @@ class ReportOptions(BaseOptions): ########################################################### self.track_d = ds.m_TrackMinWidth tracks = board.GetTracks() - self.oar_vias = self.track = INF + self.oar_vias = self.oar_vias_ec = self.track = INF self._vias = {} + self._vias_ec = {} self._tracks_m = {} self._drills_real = {} + self._drills_ec = {} track_type = 'TRACK' if GS.ki5 else 'PCB_TRACK' via_type = 'VIA' if GS.ki5 else 'PCB_VIA' for t in tracks: @@ -522,8 +546,13 @@ class ReportOptions(BaseOptions): via_id = (via.GetDrill(), via.GetWidth()) self._vias[via_id] = self._vias.get(via_id, 0) + 1 d = adjust_drill(via_id[0]) - self.oar_vias = min(self.oar_vias, (via_id[1] - d) / 2) + oar, oar_ec, d_ec = self.compute_oar(via_id[1], d) + via_id_ec = (d_ec, via_id[1]) + self._vias_ec[via_id_ec] = self._vias.get(via_id_ec, 0) + 1 + self.oar_vias = min(self.oar_vias, oar) + self.oar_vias_ec = min(self.oar_vias_ec, oar_ec) self._drills_real[d] = self._drills_real.get(d, 0) + 1 + self._drills_ec[d_ec] = self._drills_ec.get(d_ec, 0) + 1 self.track_min = min(self.track_d, self.track) ########################################################### # Drill (min) @@ -531,7 +560,7 @@ class ReportOptions(BaseOptions): modules = board.GetModules() if GS.ki5 else board.GetFootprints() self._drills = {} self._drills_oval = {} - self.oar_pads = self.pad_drill = self.pad_drill_real = INF + self.oar_pads = self.oar_pads_ec = self.pad_drill = self.pad_drill_real = self.pad_drill_real_ec = INF self.slot = INF self.top_smd = self.top_tht = self.bot_smd = self.bot_tht = 0 top_layer = board.GetLayerID('F.Cu') @@ -581,11 +610,16 @@ class ReportOptions(BaseOptions): # print('{} @ {}'.format(dr, pad.GetPosition())) self._drills_real[d_r] = self._drills_real.get(d_r, 0) + 1 pad_sz = pad.GetSize() - oar_x = (pad_sz.x - dr_x_real) / 2 - oar_y = (pad_sz.y - dr_y_real) / 2 + oar_x, oar_ec_x, dr_x_ec = self.compute_oar(pad_sz.x, dr_x_real) + oar_y, oar_ec_y, dr_y_ec = self.compute_oar(pad_sz.y, dr_y_real) + dr_ec = min(dr_x_ec, dr_y_ec) + self._drills_ec[dr_ec] = self._drills_ec.get(dr_ec, 0) + 1 + self.pad_drill_real_ec = min(dr_ec, self.pad_drill_real_ec) oar_t = min(oar_x, oar_y) + oar_ec_t = min(oar_ec_x, oar_ec_y) if oar_t > 0: self.oar_pads = min(self.oar_pads, oar_t) + self.oar_pads_ec = min(self.oar_pads_ec, oar_ec_t) if oar_t < min_oar: logger.warning(W_WRONGOAR+"Really small OAR detected ({} mm) for pad {}". format(to_mm(oar_t, 4), get_pad_info(pad))) @@ -594,6 +628,7 @@ class ReportOptions(BaseOptions): elif oar_t == 0 and is_pth: logger.warning(W_WRONGOAR+"Plated pad without copper "+get_pad_info(pad)) self._vias_m = sorted(self._vias.keys()) + self._vias_ec_m = sorted(self._vias_ec.keys()) # Via Pad size self.via_pad_d = ds.m_ViasMinSize self.via_pad = self._vias_m[0][1] if self._vias_m else INF @@ -603,14 +638,18 @@ class ReportOptions(BaseOptions): self.via_drill_d = ds.m_ViasMinDrill if GS.ki5 else ds.m_MinThroughDrill self.via_drill = self._vias_m[0][0] if self._vias_m else INF self.via_drill_min = min(self.via_drill_d, self.via_drill) + self.via_drill_real_ec = self.via_drill_ec = self._vias_ec_m[0][0] if self._vias_ec_m else INF + self.via_drill_ec_min = min(self.via_drill_d, self.via_drill_ec) # Via Drill size before platting self.via_drill_real_d = adjust_drill(self.via_drill_d) self.via_drill_real = adjust_drill(self.via_drill) self.via_drill_real_min = adjust_drill(self.via_drill_min) + self.via_drill_real_ec_min = adjust_drill(self.via_drill_ec_min) # Pad Drill # No minimum defined (so no _d) self.pad_drill_min = self.pad_drill if GS.ki5 else ds.m_MinThroughDrill self.pad_drill_real_min = self.pad_drill_real if GS.ki5 else adjust_drill(ds.m_MinThroughDrill, False) + self.pad_drill_real_ec_min = self.pad_drill_real_ec if GS.ki5 else adjust_drill(ds.m_MinThroughDrill, False) # Drill overall self.drill_d = min(self.via_drill_d, self.pad_drill) self.drill = min(self.via_drill, self.pad_drill) @@ -619,6 +658,9 @@ class ReportOptions(BaseOptions): self.drill_real_d = min(self.via_drill_real_d, self.pad_drill_real) self.drill_real = min(self.via_drill_real, self.pad_drill_real) self.drill_real_min = min(self.via_drill_real_min, self.pad_drill_real_min) + self.drill_real_ec_d = min(self.via_drill_real_d, self.pad_drill_real_ec) + self.drill_real_ec = min(self.via_drill_real_ec, self.pad_drill_real_ec) + self.drill_real_ec_min = min(self.via_drill_real_ec_min, self.pad_drill_real_ec_min) self.top_comp_type = to_smd_tht(self.top_smd, self.top_tht) self.bot_comp_type = to_smd_tht(self.bot_smd, self.bot_tht) ########################################################### @@ -631,13 +673,15 @@ class ReportOptions(BaseOptions): via_sizes = board.GetViasDimensionsList() self._vias_defined = set() self._via_sizes_sorted = [] - self.oar_vias_d = INF + self.oar_vias_d = self.oar_vias_ec_d = INF for v in sorted(via_sizes, key=lambda x: (x.m_Diameter, x.m_Drill)): d = v.m_Diameter h = v.m_Drill if not d and not h: continue # KiCad 6 - self.oar_vias_d = min(self.oar_vias_d, (d - adjust_drill(h)) / 2) + oar, oar_ec, _ = self.compute_oar(d, adjust_drill(h)) + self.oar_vias_d = min(self.oar_vias_d, oar) + self.oar_vias_ec_d = min(self.oar_vias_ec_d, oar_ec) self._vias_defined.add((h, d)) self._via_sizes_sorted.append((h, d)) ########################################################### @@ -648,18 +692,24 @@ class ReportOptions(BaseOptions): self.oar = min(self.oar_vias, self.oar_pads) self.oar_min = min(self.oar_d, self.oar) self.oar_vias_min = min(self.oar_vias_d, self.oar_vias) + # Eurocircuits OAR + self.oar_pads_ec_min = self.oar_pads_ec + self.oar_ec_d = min(self.oar_vias_ec_d, self.oar_pads_ec) + self.oar_ec = min(self.oar_vias_ec, self.oar_pads_ec) + self.oar_ec_min = min(self.oar_ec_d, self.oar_ec) + self.oar_vias_ec_min = min(self.oar_vias_ec_d, self.oar_vias_ec) ########################################################### # Eurocircuits class # https://www.eurocircuits.com/pcb-design-guidelines-classification/ ########################################################### # Pattern class - self.pattern_class_min = get_pattern_class(self.track_min, self.clearance, self.oar_min, 'minimum') - self.pattern_class = get_pattern_class(self.track, self.clearance, self.oar, 'measured', self._ec_pat) - self.pattern_class_d = get_pattern_class(self.track_d, self.clearance, self.oar_d, 'defined') + self.pattern_class_min = get_pattern_class(self.track_min, self.clearance, self.oar_ec_min, 'minimum') + self.pattern_class = get_pattern_class(self.track, self.clearance, self.oar_ec, 'measured', self._ec_pat) + self.pattern_class_d = get_pattern_class(self.track_d, self.clearance, self.oar_ec_d, 'defined') # Drill class - self.drill_class_min = get_drill_class(self.drill_real_min, 'minimum') - self.drill_class = get_drill_class(self.drill_real, 'measured', self._ec_drl) - self.drill_class_d = get_drill_class(self.drill_real_d, 'defined') + self.drill_class_min = get_drill_class(self.drill_real_ec_min, 'minimum') + self.drill_class = get_drill_class(self.drill_real_ec, 'measured', self._ec_drl) + self.drill_class_d = get_drill_class(self.drill_real_ec_d, 'defined') ########################################################### # General stats ########################################################### diff --git a/kibot/report_templates/report_full.txt b/kibot/report_templates/report_full.txt index fe01dc4f..70bddebf 100644 --- a/kibot/report_templates/report_full.txt +++ b/kibot/report_templates/report_full.txt @@ -69,6 +69,7 @@ Outer Annular Ring: ${oar_mm} mm (${oar_mils} mils) - By design rules: ${oar_d_mm} mm (${oar_d_mils} mils) Eurocircuits class: ${pattern_class}${drill_class} +- Using min drill ${drill_real_ec_mm} mm for an OAR of ${oar_ec_mm} mm # General stats diff --git a/tests/reference/5_1_6/light_control-report.txt b/tests/reference/5_1_6/light_control-report.txt index 85f9a55e..16713252 100644 --- a/tests/reference/5_1_6/light_control-report.txt +++ b/tests/reference/5_1_6/light_control-report.txt @@ -42,7 +42,8 @@ Outer Annular Ring: 0.08 mm (3 mils) - By design rules: 0.08 mm (3 mils) -Eurocircuits class: 10C +Eurocircuits class: 6D +- Using min drill 0.25 mm for an OAR of 0.13 mm # General stats diff --git a/tests/reference/5_1_6/light_control-report.txt_2 b/tests/reference/5_1_6/light_control-report.txt_2 index d1a4f774..4188eec6 100644 --- a/tests/reference/5_1_6/light_control-report.txt_2 +++ b/tests/reference/5_1_6/light_control-report.txt_2 @@ -42,7 +42,8 @@ Outer Annular Ring: 0.08 mm (3 mils) - By design rules: 0.08 mm (3 mils) -Eurocircuits class: 10C +Eurocircuits class: 6D +- Using min drill 0.25 mm for an OAR of 0.13 mm # General stats diff --git a/tests/reference/5_1_6/light_control-report_simple.txt b/tests/reference/5_1_6/light_control-report_simple.txt index 8ae8acda..9dc4697c 100644 --- a/tests/reference/5_1_6/light_control-report_simple.txt +++ b/tests/reference/5_1_6/light_control-report_simple.txt @@ -3,7 +3,7 @@ Size: - 59.69x48.26 mm -Class: 10C +Class: 6D Track width: ≥ 0.15 mm diff --git a/tests/reference/6_0_4/light_control-report.txt b/tests/reference/6_0_4/light_control-report.txt index b0dff466..d91aeccf 100644 --- a/tests/reference/6_0_4/light_control-report.txt +++ b/tests/reference/6_0_4/light_control-report.txt @@ -67,7 +67,8 @@ Outer Annular Ring: 0.08 mm (3 mils) - By design rules: 0.08 mm (3 mils) -Eurocircuits class: 10C +Eurocircuits class: 6D +- Using min drill 0.25 mm for an OAR of 0.13 mm # General stats diff --git a/tests/reference/6_0_4/light_control-report.txt_2 b/tests/reference/6_0_4/light_control-report.txt_2 index 4791a406..b3e62ef2 100644 --- a/tests/reference/6_0_4/light_control-report.txt_2 +++ b/tests/reference/6_0_4/light_control-report.txt_2 @@ -67,7 +67,8 @@ Outer Annular Ring: 0.08 mm (3 mils) - By design rules: 0.08 mm (3 mils) -Eurocircuits class: 10C +Eurocircuits class: 6D +- Using min drill 0.25 mm for an OAR of 0.13 mm # General stats diff --git a/tests/reference/6_0_4/light_control-report_simple.txt b/tests/reference/6_0_4/light_control-report_simple.txt index 9c88fd56..367a8332 100644 --- a/tests/reference/6_0_4/light_control-report_simple.txt +++ b/tests/reference/6_0_4/light_control-report_simple.txt @@ -3,7 +3,7 @@ Size: - 59.69x48.26 mm -Class: 10C +Class: 6D Track width: ≥ 0.15 mm