Skip to content
Back to skills

Gear

ASecurity

Create an involute spur gear using FreeCAD's Part module.

  • 539 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 26, 2026
developmentpython

Security analysis

A100/100

Scanned October 4, 2026

npx -y skills add ghbalf/freecad-ai --skill gear --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gear?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gear
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ghbalf-gear/badge)](https://www.skillsdirectory.com/skills/ghbalf-gear)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gear
description: "Create an involute spur gear using FreeCAD's Part module."
---

# Spur Gear Generator

Create an involute spur gear using FreeCAD's Part module.

## Parameters to extract from user request
- **Module** (m): tooth size parameter, default 2.0mm
- **Number of teeth** (z): default 20
- **Pressure angle**: default 20 degrees
- **Face width** (thickness): default 10mm
- **Bore diameter**: center hole, default 5mm (0 = no bore)

## Derived dimensions
- Pitch diameter: d = m * z
- Tip diameter: da = m * (z + 2)
- Root diameter: df = m * (z - 2.5)

## Construction

Use `execute_code` with the complete gear generation code below.
Replace the parameter values at the top with the user's requested values.

```python
import math
import Part
import FreeCAD as App

# === PARAMETERS (replace with user values) ===
module = 2.0
teeth = 20
pressure_angle_deg = 20
face_width = 10.0
bore_dia = 5.0

# === DERIVED ===
pitch_r = module * teeth / 2.0
base_r = pitch_r * math.cos(math.radians(pressure_angle_deg))
tip_r = pitch_r + module
root_r = pitch_r - 1.25 * module

def involute_pts(base_r, tip_r, n=20):
    max_angle = math.sqrt((tip_r / base_r) ** 2 - 1)
    pts = []
    for i in range(n):
        t = i * max_angle / (n - 1)
        x = base_r * (math.cos(t) + t * math.sin(t))
        y = base_r * (math.sin(t) - t * math.cos(t))
        pts.append(App.Vector(x, y, 0))
    return pts

def rotate_pt(pt, angle_rad):
    c, s = math.cos(angle_rad), math.sin(angle_rad)
    return App.Vector(c * pt.x - s * pt.y, s * pt.x + c * pt.y, 0)

def pt_angle(pt):
    return math.atan2(pt.y, pt.x)

# Involute half-tooth thickness angle
inv_alpha = math.tan(math.radians(pressure_angle_deg)) - math.radians(pressure_angle_deg)
half_thick_angle = math.pi / (2 * teeth) + inv_alpha

# Generate involute profile for one tooth, centered on +Y axis
right_involute = involute_pts(base_r, tip_r, 20)
right_side = [rotate_pt(p, -half_thick_angle + math.pi / 2) for p in right_involute]
left_side = [App.Vector(-p.x, p.y, 0) for p in right_side]

# Key points
left_base, left_tip = left_side[0], left_side[-1]
right_base, right_tip = right_side[0], right_side[-1]
lb_a, rb_a = pt_angle(left_base), pt_angle(right_base)

# Points on root circle at flank angles
lb_on_root = App.Vector(root_r * math.cos(lb_a), root_r * math.sin(lb_a), 0)
rb_on_root = App.Vector(root_r * math.cos(rb_a), root_r * math.sin(rb_a), 0)

# Build closed tooth profile: root → left involute → tip arc → right involute → root arc
tooth_edges = []

# Radial: left root → left base
if lb_on_root.distanceToPoint(left_base) > 0.01:
    tooth_edges.append(Part.LineSegment(lb_on_root, left_base).toShape())

# Left involute BSpline (base → tip)
bs_left = Part.BSplineCurve()
bs_left.interpolate(left_side)
tooth_edges.append(bs_left.toShape())

# Tip arc (left tip → right tip)
tip_mid_a = (pt_angle(left_tip) + pt_angle(right_tip)) / 2
tip_mid = App.Vector(tip_r * math.cos(tip_mid_a), tip_r * math.sin(tip_mid_a), 0)
tooth_edges.append(Part.Arc(left_tip, tip_mid, right_tip).toShape())

# Right involute BSpline (tip → base)
bs_right = Part.BSplineCurve()
bs_right.interpolate(list(reversed(right_side)))
tooth_edges.append(bs_right.toShape())

# Radial: right base → right root
if right_base.distanceToPoint(rb_on_root) > 0.01:
    tooth_edges.append(Part.LineSegment(right_base, rb_on_root).toShape())

# Root arc (right root → left root, closing the profile)
root_mid_a = (lb_a + rb_a) / 2
root_mid = App.Vector(root_r * math.cos(root_mid_a), root_r * math.sin(root_mid_a), 0)
tooth_edges.append(Part.Arc(rb_on_root, root_mid, lb_on_root).toShape())

# Create one tooth solid
tooth_wire = Part.Wire(tooth_edges)
tooth_face = Part.Face(tooth_wire)
tooth_solid = tooth_face.extrude(App.Vector(0, 0, face_width))

# Build gear: base cylinder + all teeth fused together
gear = Part.makeCylinder(root_r, face_width)
for t in range(teeth):
    rotated = tooth_solid.copy()
    if t > 0:
        rotated.rotate(App.Vector(0, 0, 0), App.Vector(0, 0, 1), t * 360.0 / teeth)
    gear = gear.fuse(rotated)
gear = gear.removeSplitter()

# Cut bore hole
if bore_dia > 0:
    bore = Part.makeCylinder(bore_dia / 2, face_width + 2, App.Vector(0, 0, -1))
    gear = gear.cut(bore)

# Add to document
gear_obj = App.ActiveDocument.addObject("Part::Feature", "Gear_M{}_Z{}".format(module, teeth))
gear_obj.Label = "Gear M{} Z{}".format(module, teeth)
gear_obj.Shape = gear
App.ActiveDocument.recompute()

print("Gear created: pitch dia={:.1f}mm, tip dia={:.1f}mm, root dia={:.1f}mm".format(
    pitch_r * 2, tip_r * 2, root_r * 2))
```

## Important
- Copy the COMPLETE code block above into `execute_code`, only changing the parameter values at the top
- Do NOT try to use PartDesign Body/Sketch for the gear — use Part::Feature directly
- Do NOT use `App.Gui` — it may not be available in the sandbox
- Label the gear clearly with its parameters: "Gear M2 Z24"
- The gear is centered at the origin

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.