Add tlmConfirm to tlm_dl ota packet-structure (#2991)
[ExpressLRS.git] / src / python / test_tools / power_sweep.py
blob4efe1e61409c375cbf5255fc490ab197a0b8ea32
1 # This script runs an automated voltage sweep while collecting ADC DBGLN() output
2 # from an ExpressLRS RX using devAnalogVbat. The receiver should be compiled with:
3 # -DDEBUG_VBAT_ADC -DDEBUG_LOG -DDEBUG_CRSF_NO_OUTPUT -DRCVR_UART_BAUD=460800
4 # (lots of UART errors at the default 420000)
5 # If firmware is workign correctly `cat /dev/ttyUSB0` will show values such as
6 # $ADC,925
7 # $ADC,924
8 # $ADC,926
9 # ...
11 # Uses the KoradSerial library for power supply control, just dump this in the library directory
12 # https://github.com/starforgelabs/py-korad-serial
13 from koradserial import KoradSerial
14 import time
15 import serial
16 import argparse
18 class MedianAvg:
19 def __init__(self):
20 self.reset()
21 def reset(self):
22 self.vals = []
23 self.min = 0
24 self.max = 0
25 self.mean = 0
26 def add(self, val):
27 self.vals.append(val)
28 def calc(self):
29 if len(self.vals) < 3:
30 self.reset()
31 return
32 self.vals.sort()
33 self.min = self.vals[0]
34 self.max = self.vals[-1]
35 self.mean = 0
36 for i in range(1, len(self.vals)-1):
37 self.mean += self.vals[i]
38 self.mean = self.mean / (len(self.vals)-2)
39 def __len__(self):
40 return len(self.vals)
41 def __str__(self):
42 return f'n={len(self.vals)} mean={self.mean} min={self.min} max={self.max}'
44 def flushSerial(ser):
45 while True:
46 bVal = ser.read_until()
47 if len(bVal) == 0:
48 return
50 def doVoltageSample(ser, voltage):
51 flushSerial(ser)
52 adcMedian = MedianAvg()
53 while True:
54 sLine = ser.read_until().decode('ascii')
55 if sLine.startswith('$ADC,') and sLine.endswith('\r\n'):
56 try:
57 iADC = int(sLine[5:-2])
58 #print(iADC)
59 adcMedian.add(iADC)
60 if len(adcMedian) >= 10:
61 adcMedian.calc()
62 print(f'{voltage:0.1f},{adcMedian.mean:0.4f},{adcMedian.min},{adcMedian.max}')
63 adcMedian.reset()
64 return
65 except ValueError:
66 pass
68 def runSweep(args):
69 with serial.Serial(args.rport, baudrate=args.rbaud, timeout=0.010) as rcvr:
70 with KoradSerial(args.kport) as pwr:
71 try:
72 #print("Model: ", pwr.model)
73 pwrch = pwr.channels[0]
74 pwrch.voltage = 5.00
75 pwr.output.on()
77 print('voltage,mean,min,max')
78 for v in range(args.start, args.end+args.step, args.step):
79 voltage = v / 100.0
80 pwrch.voltage = voltage
81 time.sleep(0.2)
82 doVoltageSample(rcvr, voltage)
83 finally:
84 pwr.output.off()
86 if __name__ == '__main__':
87 parser = argparse.ArgumentParser(
88 description="Run a voltage sweep using a Korad power supply and recevie ADC data from an ELRS receiver")
89 parser.add_argument("-b", "--rbaud", type=int, default=460800,
90 help="Receiver UART baud")
91 parser.add_argument("-e", "--end", type=int, default=100,
92 help="Ending voltage (centidegrees 500 = 5.00V)")
93 parser.add_argument("-k", "--kport", type=str, default='/dev/ttyACM0',
94 help="Port used for Korad power supply UART")
95 parser.add_argument("-r", "--rport", type=str, default='/dev/ttyUSB0',
96 help="Port used for receiver UART")
97 parser.add_argument("-s", "--start", type=int, default=3100,
98 help="Starting voltage (centidegrees 500 = 5.00V)")
99 parser.add_argument("-t", "--step", type=int, default=-10,
100 help="Voltage step (centidegrees -10 = -0.10V)")
102 args = parser.parse_args()
104 runSweep(args)