Skip to content

Instantly share code, notes, and snippets.

@davydmaker
Created April 22, 2026 02:39
Show Gist options
  • Select an option

  • Save davydmaker/4a624fe45ed983c4b096752be5fa4749 to your computer and use it in GitHub Desktop.

Select an option

Save davydmaker/4a624fe45ed983c4b096752be5fa4749 to your computer and use it in GitHub Desktop.
servo-motor-sizing: Python script to rank RC servo motors against control surface requirements

servo-motor-sizing

Python script that helps rank RC servo motors against control surface requirements (aileron, rudder, elevator, flaps, tailwheel). Reads a config file and writes a ranked comparison to result.txt.

How it works

The script reads conf.txt, which defines:

  • Surfaces (control surfaces with their minimum torque and weighting criteria).
  • Servos (candidate motors with their specifications).

For each surface × servo combination, it computes a score per criterion (Reliability, GearType, Weight, TorqueNeed), applies the weighting, and writes the totals to result.txt for comparison.

Configuration format

Adding a surface

{SurfaceName}={MinTorque}|Reliability={w}|GearType={w}|Weight={w}|TorqueNeed={w}

Where {w} is the weight of that criterion (0-100) and {MinTorque} is the minimum required torque in kg·cm.

Example:

Aileron=4,62|Reliability=70|GearType=80|Weight=90|TorqueNeed=100

Adding a servo

{ServoName}={torque}|{weight}|{gearType}|{reliability}

Where:

  • torque = torque at 4.8V (N·cm)
  • weight = servo weight (g)
  • gearType = gear type rating (0-10)
  • reliability = reliability rating (0-10)

Example:

CORONA DS-843MG=4,8|8,5|10|8

Usage

python3 servo-motor-sizing.py

The script reads conf.txt from the current directory and writes to result.txt.

Notes

  • Decimal separator in config values uses commas (,), following the original BR/EU convention used when the script was built. The script handles the conversion internally.
  • Written in Python 3.
  • Originally a one-off tool built to automate servo selection in an RC airplane project.

License

MIT.

Aileron=4,62|Reliability=70|GearType=80|Weight=90|TorqueNeed=100
Rudder=1|Reliability=70|GearType=80|Weight=90|TorqueNeed=100
Elevator=7,32|Reliability=70|GearType=80|Weight=90|TorqueNeed=100
Flaps=2,21|Reliability=70|GearType=80|Weight=90|TorqueNeed=100
Tailwheel=5,0|Reliability=70|GearType=80|Weight=90|TorqueNeed=100
CORONA DS-843MG=4,8|8,5|10|8
EFLITE EFLR7140=2,3|13|10|7
FEETECH FS5115M=5,2|58|10|7
HITEC HD-645MG=7,7|52,2|6,5|8
Goteck GS-D9025MG=2,35|13,3|10|5
EMAX es3302=2,4|12,4|10|6
#!/usr/bin/python3
# encoding: utf-8
"""servo-motor-sizing.py: Script to rank RC servo motors against control surface requirements."""
__author__ = "Davyd Maker"
__version__ = "1.5"
def truncate(s, n):
i, p, d = "{}".format(s).partition('.')
return '.'.join([i, d[:n]]).rstrip("0").rstrip(".")
def changePoint(s, decimal, thousand): return thousand.join(str(s).replace(thousand, "").split(decimal))
def splitStrVal(arr): return list(map(lambda rlv: [rlv.split("=")[0], float(changePoint(rlv.split("=")[1], ",", "."))], arr.split("|")))
listSv, listSprf, listRlv = [], [], []
confValores = open("./conf.txt", "r")
for idxL, l in enumerate(confValores):
l = l.strip()
if l == "": continue
if l.count("=") > 1:
l = l.split("|")
listSprf.append(splitStrVal(l[0])[0])
listRlv.append(splitStrVal("|".join(l[1:])))
else:
listSv.append(list([l.split("=")[0], [float(changePoint(tL, ",", ".")) for tL in l.split("=")[1].split("|")]]))
arq = open("./result.txt", "w+")
for n, rList in zip(listSprf, listRlv):
for idxS, s in enumerate(listSv):
for idxR, r in enumerate(rList):
if r[0] == "Reliability": tNota = s[1][3]
elif r[0] == "GearType": tNota = s[1][2]
elif r[0] == "Weight": tNota = -0.05 * s[1][1] + 10
elif r[0] == "TorqueNeed": tNota = float(truncate(n[1]/s[1][0], 2)) * 10
arq.write("[Servo " + s[0] + " with torque (4.8V) " + changePoint(s[1][0], ".", ",") + " N*cm for " + n[0] + " with Tm " + changePoint(n[1], ".", ",") + " kg*cm]\n")
arq.write("[" + r[0] + " - Relevance: " + changePoint(r[1], ".", ",") + "]\n")
arq.write("Score: " + changePoint(truncate(tNota, 2), ".", ",") + "\n")
arq.write("Total: " + str(changePoint(truncate(float(tNota) * float(r[1]), 2), ".", ",")) + "\n")
arq.write("\n")
arq.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment