├── README.md ├── WebUpdater.ino ├── data ├── BMS 2306.5 2000KV │ └── btfl_001.bbl ├── EMAX RS2306 2400KV │ ├── 11_turn - 6s - 2.csv │ ├── 11_turn - 6s - 2.csv.plot.png │ ├── 11_turn - 6s - 3.csv │ ├── 11_turn - 6s - 3.csv.plot.png │ ├── 11_turn - 6s - 4.csv │ ├── 11_turn - 6s - 4.csv.plot.png │ ├── 11_turn - 6s multistrand.csv │ ├── 11_turn - 6s multistrand.csv.plot.png │ ├── 11_turn - 6s.csv │ ├── 11_turn - 6s.csv.plot.png │ ├── 11_turn.csv │ ├── 11_turn.csv.plot.png │ ├── 11_turn_cyclone_5046 - 6s - 2.csv │ ├── 11_turn_cyclone_5046 - 6s - 2.csv.plot.png │ ├── 11_turn_cyclone_5046 - 6s - 3.csv │ ├── 11_turn_cyclone_5046 - 6s - 3.csv.plot.png │ ├── 11_turn_cyclone_5046 - 6s - noisy.csv │ ├── 11_turn_cyclone_5046 - 6s - noisy.csv.plot.png │ ├── 11_turn_cyclone_5046 - 6s multistrand.csv │ ├── 11_turn_cyclone_5046 - 6s multistrand.csv.plot.png │ ├── 11_turn_cyclone_5046 - 6s.csv │ ├── 11_turn_cyclone_5046 - 6s.csv.plot.png │ ├── 11_turn_cyclone_5046.csv │ ├── 11_turn_cyclone_5046.csv.plot.png │ ├── 11_turn_cyclone_5050 - 6s multistrand.csv │ ├── 11_turn_cyclone_5050 - 6s multistrand.csv.plot.png │ ├── 11_turn_cyclone_5050 - 6s.csv │ ├── 11_turn_cyclone_5050 - 6s.csv.plot.png │ ├── 11_turn_cyclone_5050.csv │ ├── 11_turn_cyclone_5050.csv.plot.png │ ├── 8_turn.csv │ ├── 8_turn.csv.plot.png │ ├── 8_turn_cyclone_5046.csv │ ├── 8_turn_cyclone_5046.csv.plot.png │ ├── 8_turn_cyclone_5050.csv │ ├── 8_turn_cyclone_5050.csv.plot.png │ ├── 9_turn.csv │ ├── 9_turn.csv.plot.png │ ├── 9_turn_cyclone_5046.csv │ ├── 9_turn_cyclone_5046.csv.plot.png │ ├── 9_turn_cyclone_5050.csv │ ├── 9_turn_cyclone_5050.csv.plot.png │ ├── comparison plots 4s zoomed.png │ ├── comparison plots 4s.png │ ├── comparison plots 6s three motors zoomed.png │ ├── comparison plots 6s three motors.png │ ├── comparison plots 6s zoomed.png │ ├── comparison plots 6s.png │ ├── emax_rs2306_plots - 6s - M1,2,3.py │ ├── emax_rs2306_plots - 6s.py │ ├── emax_rs2306_plots - rpm thrust.py │ ├── emax_rs2306_plots.py │ ├── old excel │ │ ├── EMAX RS2306 2400KV.xlsx │ │ └── plots.png │ ├── original.csv │ ├── original.csv.plot.png │ ├── original_cyclone_5046.csv │ ├── original_cyclone_5046.csv.plot.png │ ├── original_cyclone_5050.csv │ └── original_cyclone_5050.csv.plot.png ├── drop csv on here to plot.bat └── thrustPlot.py ├── dshot-esc-tester.ino ├── dshot-esc-tester.ino.esp32.bin ├── images ├── 8turn.jpg ├── 9turn.jpg ├── bottom.jpg ├── builds │ ├── AlexM1.jpg │ ├── AlexM2.jpg │ ├── AlexM3.jpg │ └── neohito.jpg ├── thruststand.jpg ├── top loadcell.jpg └── top.jpg └── pcb ├── Gerber-dshot-esc-tester.zip └── pcb.png /README.md: -------------------------------------------------------------------------------- 1 | Uses the dshot600 protocol to communicate with the a blheli32 ESC and receive telemetry. Telemetry data is used to calculate KV and all info is displayed on the OLED. 2 | 3 | Great for testing hand wound motors KV or new/troublesome motors. 4 | 5 | Optional loadcell can be added to the pin header highlighted with the orange circle below. Data is printed via serial every 2-3ms. 6 | 7 | 20 second demo video https://www.youtube.com/watch?v=VLMNEdSz4wI 8 | 9 | Schematics and PCB https://easyeda.com/jyesmith/kv-meter 10 | 11 | 12 | 13 | Results form a rewound emax 2306 stator. Left is with 8 turns and the right images is with 9 turns. 14 | 15 | 16 | 17 | **WARNING - If `#define MINIQUADTESTBENCH` is uncommented the test sequence used by https://www.miniquadtestbench.com/ will automatically start!!!** Below shows the results of testing an original EMAX RS2306 2400KV motor against the same motor wound with 0.5mm wire 8 & 9 turns per tooth. 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 6s data below also shows a comparison between single and multistrand windings. 26 | 27 | 28 | 29 | 30 | 31 | ## BOM 32 | 33 | - Upload the gerber zip in the pcb folder to jlcpcb.com, select 1.6mm PCB thickness, and your favourite colour. 34 | - ESP32 development board. Get the same one as in the images above to be sure it mounts correctly. I removed the black plastic standoff on the pins so that it sits flat on the PCB and gives enough headroom for the upper PCB and regulator. 35 | - You favourite blheli32 esc. Make sure it has telemetry out and ideally a current sensor. 36 | - OLED 128*64. There are 2 common version but the Vcc and GND pins are swapped. This PCB has been designed to take both and you select which pin receives Vcc/GND by soldering the jumpers. 37 | - A 3V3 or 5V regulator. Either can be used and solder the jumper to which ever voltage you have used. This makes sure the ESP32 is powered correctly. 38 | - Optional loadcell for measuring thrust. 39 | 40 | 41 | 42 | ## If you make one I would love to see it. Please post your pics as an issue or add them to this readme :) 43 | 44 | ## neohito 45 | 46 | 47 | 48 | ## Alex 49 | 50 | 51 | -------------------------------------------------------------------------------- /WebUpdater.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define STASSID "DSHOT ESC TESTER" 8 | #define STAPSK "password123" 9 | 10 | const char *host = "dshot-tester-webupdate"; 11 | const char *ssid = STASSID; 12 | const char *password = STAPSK; 13 | 14 | WebServer server(80); 15 | const char* serverIndex = "
"; 16 | 17 | void BeginWebUpdate(void) { 18 | 19 | // Serial.println("Begin Webupdater"); 20 | WiFi.mode(WIFI_AP); 21 | WiFi.softAP(ssid, password); 22 | 23 | MDNS.begin(host); 24 | server.on("/", HTTP_GET, []() { 25 | server.sendHeader("Connection", "close"); 26 | server.send(200, "text/html", serverIndex); 27 | }); 28 | server.on("/update", HTTP_POST, []() { 29 | server.sendHeader("Connection", "close"); 30 | server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); 31 | ESP.restart(); 32 | }, []() { 33 | HTTPUpload& upload = server.upload(); 34 | if (upload.status == UPLOAD_FILE_START) { 35 | Serial.setDebugOutput(true); 36 | Serial.printf("Update: %s\n", upload.filename.c_str()); 37 | if (!Update.begin()) { //start with max available size 38 | Update.printError(Serial); 39 | } 40 | } else if (upload.status == UPLOAD_FILE_WRITE) { 41 | if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { 42 | Update.printError(Serial); 43 | } 44 | } else if (upload.status == UPLOAD_FILE_END) { 45 | if (Update.end(true)) { //true to set the size to the current progress 46 | Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); 47 | } else { 48 | Update.printError(Serial); 49 | } 50 | Serial.setDebugOutput(false); 51 | } else { 52 | Serial.printf("Update Failed Unexpectedly (likely broken connection): status=%d\n", upload.status); 53 | } 54 | }); 55 | server.begin(); 56 | MDNS.addService("http", "tcp", 80); 57 | 58 | // Serial.printf("Ready! Open http://%s.local in your browser\n", host); 59 | } 60 | 61 | void HandleWebUpdate(void) { 62 | server.handleClient(); 63 | yield(); 64 | } 65 | -------------------------------------------------------------------------------- /data/BMS 2306.5 2000KV/btfl_001.bbl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/BMS 2306.5 2000KV/btfl_001.bbl -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn - 6s - 2.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn - 6s - 2.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn - 6s - 3.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn - 6s - 3.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn - 6s - 4.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn - 6s - 4.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn - 6s multistrand.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn - 6s multistrand.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn - 6s.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn - 6s.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s - 2.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s - 2.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s - 3.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s - 3.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s - noisy.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s - noisy.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s multistrand.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s multistrand.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5046 - 6s.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5046.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5046.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5050 - 6s multistrand.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5050 - 6s multistrand.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5050 - 6s.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5050 - 6s.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/11_turn_cyclone_5050.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/11_turn_cyclone_5050.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/8_turn.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/8_turn.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/8_turn_cyclone_5046.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/8_turn_cyclone_5046.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/8_turn_cyclone_5050.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/8_turn_cyclone_5050.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/9_turn.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/9_turn.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/9_turn_cyclone_5046.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/9_turn_cyclone_5046.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/9_turn_cyclone_5050.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/9_turn_cyclone_5050.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/comparison plots 4s zoomed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/comparison plots 4s zoomed.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/comparison plots 4s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/comparison plots 4s.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/comparison plots 6s three motors zoomed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/comparison plots 6s three motors zoomed.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/comparison plots 6s three motors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/comparison plots 6s three motors.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/comparison plots 6s zoomed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/comparison plots 6s zoomed.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/comparison plots 6s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/comparison plots 6s.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/emax_rs2306_plots - 6s - M1,2,3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Aug 26 19:53:08 2019 4 | 5 | @author: Jye 6 | """ 7 | 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | eleven_turn_1 = np.genfromtxt('11_turn - 6s.csv', delimiter=',', skip_header=1, 13 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 14 | eleven_turn_2 = np.genfromtxt('11_turn - 6s - 2.csv', delimiter=',', skip_header=1, 15 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 16 | eleven_turn_3 = np.genfromtxt('11_turn - 6s - 3.csv', delimiter=',', skip_header=1, 17 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 18 | 19 | eleven_turn_5046_1 = np.genfromtxt('11_turn_cyclone_5046 - 6s.csv', delimiter=',', skip_header=1, 20 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 21 | eleven_turn_5046_2 = np.genfromtxt('11_turn_cyclone_5046 - 6s - 2.csv', delimiter=',', skip_header=1, 22 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 23 | eleven_turn_5046_3 = np.genfromtxt('11_turn_cyclone_5046 - 6s - 3.csv', delimiter=',', skip_header=1, 24 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 25 | 26 | 27 | ## KV plot 28 | fig = plt.figure() 29 | ax1 = fig.add_subplot(221) 30 | ax1.title.set_text('KV') 31 | #ax2 = ax1.twinx() 32 | ax3 = ax1.twinx() 33 | ax3.spines["right"].set_position(("axes", 1.2)) 34 | fig.subplots_adjust(right=0.75) 35 | 36 | ax3.plot(eleven_turn_1['Time_ms'], eleven_turn_1['dshot'], color='y', label='dshot') 37 | ax3.set_ylabel('dshot') 38 | ax3.set_ylim([0, 2100]) 39 | 40 | #ax1.plot(original['Time_ms'], original['RPM'] / original['Voltage_V'], color='b', label='original') 41 | #ax1.plot(eight_turn['Time_ms'], eight_turn['RPM'] / eight_turn['Voltage_V'], color='r', label='8 turn') 42 | #ax1.plot(nine_turn['Time_ms'], nine_turn['RPM'] / nine_turn['Voltage_V'], color='g', label='9 turn') 43 | ax1.plot(eleven_turn_1['Time_ms'], eleven_turn_1['RPM'] / eleven_turn_1['Voltage_V'], color='b', label='11 turn - 1') 44 | ax1.plot(eleven_turn_2['Time_ms'], eleven_turn_2['RPM'] / eleven_turn_2['Voltage_V'], color='r', label='11 turn - 2') 45 | ax1.plot(eleven_turn_3['Time_ms'], eleven_turn_3['RPM'] / eleven_turn_3['Voltage_V'], color='g', label='11 turn - 3') 46 | ax1.set_xlabel('Time_ms') 47 | ax1.set_xlim([3500, 25000]) 48 | ax1.set_ylabel('KV') 49 | ax1.set_ylim([1500, 2500]) 50 | ax1.legend() 51 | 52 | 53 | ## Response plot 54 | ax1 = fig.add_subplot(223) 55 | ax1.title.set_text('Response - Cyclone 5046 Vs 5050') 56 | #ax2 = ax1.twinx() 57 | ax3 = ax1.twinx() 58 | ax3.spines["right"].set_position(("axes", 1.2)) 59 | fig.subplots_adjust(right=0.75) 60 | 61 | ax3.plot(eleven_turn_5046_1['Time_ms'], eleven_turn_5046_1['dshot'], color='y', label='dshot') 62 | ax3.set_xlabel('Time_ms') 63 | ax3.set_ylabel('dshot') 64 | ax3.set_ylim([0, 2100]) 65 | 66 | #ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 67 | #ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 68 | ax1.plot(eleven_turn_5046_1['Time_ms'], eleven_turn_5046_1['Thrust_g'], color='b', label='11 turn - 5046 - 1') 69 | ax1.plot(eleven_turn_5046_2['Time_ms'], eleven_turn_5046_2['Thrust_g'], color='r', label='11 turn - 5046 - 2') 70 | ax1.plot(eleven_turn_5046_3['Time_ms'], eleven_turn_5046_3['Thrust_g'], color='g', label='11 turn - 5046 - 3') 71 | ax1.set_xlabel('Time_ms') 72 | ax1.set_xlim([3500, 25000]) 73 | ax1.set_ylabel('Thrust (g)') 74 | ax1.set_xlim([11900, 12300]) 75 | ax1.set_ylim([0, 1500]) 76 | ax1.legend() 77 | 78 | 79 | ## Thrust efficiency plot Cyclone 5046 80 | ax1 = fig.add_subplot(222) 81 | ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5046') 82 | ax2 = ax1.twinx() 83 | ax3 = ax1.twinx() 84 | ax3.spines["right"].set_position(("axes", 1.2)) 85 | 86 | ax3.plot(eleven_turn_5046_1['Time_ms'], eleven_turn_5046_1['dshot'], color='y', label='dshot') 87 | ax3.set_xlabel('Time_ms') 88 | ax3.set_ylabel('dshot') 89 | ax3.set_ylim([0, 2100]) 90 | 91 | #ax2.plot(original_5046['Time_ms'], original_5046['Thrust_g'] / (original_5046['Voltage_V'] * original_5046['Current_A']/10), color='b', label='original') 92 | #ax2.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'] / (eight_turn_5046['Voltage_V'] * eight_turn_5046['Current_A']/10), color='r', label='8 turn') 93 | #ax2.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'] / (nine_turn_5046['Voltage_V'] * nine_turn_5046['Current_A']/10), color='g', label='9 turn') 94 | ax2.plot(eleven_turn_5046_1['Time_ms'], eleven_turn_5046_1['Thrust_g'] / (eleven_turn_5046_1['Voltage_V'] * eleven_turn_5046_1['Current_A']/10), color='b', label='11 turn - 1') 95 | ax2.plot(eleven_turn_5046_2['Time_ms'], eleven_turn_5046_2['Thrust_g'] / (eleven_turn_5046_2['Voltage_V'] * eleven_turn_5046_2['Current_A']/10), color='r', label='11 turn - 2') 96 | ax2.plot(eleven_turn_5046_3['Time_ms'], eleven_turn_5046_3['Thrust_g'] / (eleven_turn_5046_3['Voltage_V'] * eleven_turn_5046_3['Current_A']/10), color='g', label='11 turn - 3') 97 | ax2.set_ylabel('Efficiency (g/W)') 98 | ax2.set_ylim([0, 5]) 99 | 100 | #ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 101 | #ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 102 | #ax1.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'], color='g', label='9 turn') 103 | ax1.plot(eleven_turn_5046_1['Time_ms'], eleven_turn_5046_1['Thrust_g'], color='b', label='11 turn - 1') 104 | ax1.plot(eleven_turn_5046_2['Time_ms'], eleven_turn_5046_2['Thrust_g'], color='r', label='11 turn - 2') 105 | ax1.plot(eleven_turn_5046_3['Time_ms'], eleven_turn_5046_3['Thrust_g'], color='g', label='11 turn - 3') 106 | ax1.set_xlabel('Time_ms') 107 | ax1.set_xlim([3500, 25000]) 108 | ax1.set_ylabel('Thrust (g)') 109 | ax1.set_ylim([0, 1500]) 110 | ax1.legend() 111 | 112 | 113 | ### Thrust efficiency plot Cyclone 5050 114 | #ax1 = fig.add_subplot(224) 115 | #ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5050') 116 | #ax2 = ax1.twinx() 117 | #ax3 = ax1.twinx() 118 | #ax3.spines["right"].set_position(("axes", 1.2)) 119 | # 120 | #ax3.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['dshot'], color='y', label='dshot') 121 | #ax3.set_xlabel('Time_ms') 122 | #ax3.set_ylabel('dshot') 123 | #ax3.set_ylim([0, 2100]) 124 | # 125 | ##ax2.plot(original_5050['Time_ms'], original_5050['Thrust_g'] / (original_5050['Voltage_V'] * original_5050['Current_A']/10), color='b', label='original') 126 | ##ax2.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'] / (eight_turn_5050['Voltage_V'] * eight_turn_5050['Current_A']/10), color='r', label='8 turn') 127 | ##ax2.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'] / (nine_turn_5050['Voltage_V'] * nine_turn_5050['Current_A']/10), color='g', label='9 turn') 128 | #ax2.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'] / (eleven_turn_5050['Voltage_V'] * eleven_turn_5050['Current_A']/10), color='orange', label='11 turn') 129 | #ax2.plot(eleven_turn_5050_ms['Time_ms'], eleven_turn_5050_ms['Thrust_g'] / (eleven_turn_5050_ms['Voltage_V'] * eleven_turn_5050_ms['Current_A']/10), color='r', label='11 turn multistrand') 130 | #ax2.set_ylabel('Efficiency (g/W)') 131 | #ax2.set_ylim([0, 5]) 132 | # 133 | ##ax1.plot(original_5050['Time_ms'], original_5050['Thrust_g'], color='b', label='original') 134 | ##ax1.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'], color='r', label='8 turn') 135 | ##ax1.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'], color='g', label='9 turn') 136 | #ax1.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'], color='orange', label='11 turn') 137 | #ax1.plot(eleven_turn_5050_ms['Time_ms'], eleven_turn_5050_ms['Thrust_g'], color='r', label='11 turn multistrand') 138 | #ax1.set_xlabel('Time_ms') 139 | #ax1.set_xlim([3500, 25000]) 140 | #ax1.set_ylabel('Thrust (g)') 141 | #ax1.set_ylim([0, 1500]) 142 | #ax1.legend() -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/emax_rs2306_plots - 6s.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Aug 26 19:53:08 2019 4 | 5 | @author: Jye 6 | """ 7 | 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | 11 | #original = np.genfromtxt('original.csv', delimiter=',', skip_header=1, 12 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 13 | #eight_turn = np.genfromtxt('8_turn.csv', delimiter=',', skip_header=1, 14 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 15 | #nine_turn = np.genfromtxt('9_turn.csv', delimiter=',', skip_header=1, 16 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 17 | eleven_turn = np.genfromtxt('11_turn - 6s.csv', delimiter=',', skip_header=1, 18 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 19 | eleven_turn_ms = np.genfromtxt('11_turn - 6s multistrand.csv', delimiter=',', skip_header=1, 20 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 21 | 22 | #original_5046 = np.genfromtxt('original_cyclone_5046.csv', delimiter=',', skip_header=1, 23 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 24 | #eight_turn_5046 = np.genfromtxt('8_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 25 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 26 | #nine_turn_5046 = np.genfromtxt('9_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 27 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 28 | eleven_turn_5046 = np.genfromtxt('11_turn_cyclone_5046 - 6s.csv', delimiter=',', skip_header=1, 29 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 30 | eleven_turn_5046_ms = np.genfromtxt('11_turn_cyclone_5046 - 6s multistrand.csv', delimiter=',', skip_header=1, 31 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 32 | 33 | #original_5050 = np.genfromtxt('original_cyclone_5050.csv', delimiter=',', skip_header=1, 34 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 35 | #eight_turn_5050 = np.genfromtxt('8_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 36 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 37 | #nine_turn_5050 = np.genfromtxt('9_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 38 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 39 | eleven_turn_5050 = np.genfromtxt('11_turn_cyclone_5050 - 6s.csv', delimiter=',', skip_header=1, 40 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 41 | eleven_turn_5050_ms = np.genfromtxt('11_turn_cyclone_5050 - 6s multistrand.csv', delimiter=',', skip_header=1, 42 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 43 | 44 | ## KV plot 45 | fig = plt.figure() 46 | ax1 = fig.add_subplot(221) 47 | ax1.title.set_text('KV') 48 | #ax2 = ax1.twinx() 49 | ax3 = ax1.twinx() 50 | ax3.spines["right"].set_position(("axes", 1.2)) 51 | fig.subplots_adjust(right=0.75) 52 | 53 | ax3.plot(eleven_turn['Time_ms'], eleven_turn['dshot'], color='y', label='dshot') 54 | ax3.set_ylabel('dshot') 55 | ax3.set_ylim([0, 2100]) 56 | 57 | #ax1.plot(original['Time_ms'], original['RPM'] / original['Voltage_V'], color='b', label='original') 58 | #ax1.plot(eight_turn['Time_ms'], eight_turn['RPM'] / eight_turn['Voltage_V'], color='r', label='8 turn') 59 | #ax1.plot(nine_turn['Time_ms'], nine_turn['RPM'] / nine_turn['Voltage_V'], color='g', label='9 turn') 60 | ax1.plot(eleven_turn['Time_ms'], eleven_turn['RPM'] / eleven_turn['Voltage_V'], color='b', label='11 turn') 61 | ax1.plot(eleven_turn_ms['Time_ms'], eleven_turn_ms['RPM'] / eleven_turn_ms['Voltage_V'], color='r', label='11 turn multistrand') 62 | ax1.set_xlabel('Time_ms') 63 | ax1.set_xlim([3500, 25000]) 64 | ax1.set_ylabel('KV') 65 | ax1.set_ylim([1500, 2500]) 66 | ax1.legend() 67 | 68 | 69 | ## Response plot 70 | ax1 = fig.add_subplot(223) 71 | ax1.title.set_text('Response - Cyclone 5046 Vs 5050') 72 | #ax2 = ax1.twinx() 73 | ax3 = ax1.twinx() 74 | ax3.spines["right"].set_position(("axes", 1.2)) 75 | fig.subplots_adjust(right=0.75) 76 | 77 | ax3.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['dshot'], color='y', label='dshot') 78 | ax3.set_xlabel('Time_ms') 79 | ax3.set_ylabel('dshot') 80 | ax3.set_ylim([0, 2100]) 81 | 82 | #ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 83 | #ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 84 | ax1.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'], color='g', label='11 turn - 5046') 85 | ax1.plot(eleven_turn_5046_ms['Time_ms'], eleven_turn_5046_ms['Thrust_g'], color='r', label='11 turn - 5046 multistrand') 86 | ax1.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'], color='orange', label='11 turn - 5050') 87 | ax1.plot(eleven_turn_5050_ms['Time_ms'], eleven_turn_5050_ms['Thrust_g'], color='b', label='11 turn - 5050 multistrand') 88 | ax1.set_xlabel('Time_ms') 89 | ax1.set_xlim([3500, 25000]) 90 | ax1.set_ylabel('Thrust (g)') 91 | ax1.set_xlim([11900, 12300]) 92 | ax1.set_ylim([0, 1500]) 93 | ax1.legend() 94 | 95 | 96 | ## Thrust efficiency plot Cyclone 5046 97 | ax1 = fig.add_subplot(222) 98 | ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5046') 99 | ax2 = ax1.twinx() 100 | ax3 = ax1.twinx() 101 | ax3.spines["right"].set_position(("axes", 1.2)) 102 | 103 | ax3.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['dshot'], color='y', label='dshot') 104 | ax3.set_xlabel('Time_ms') 105 | ax3.set_ylabel('dshot') 106 | ax3.set_ylim([0, 2100]) 107 | 108 | #ax2.plot(original_5046['Time_ms'], original_5046['Thrust_g'] / (original_5046['Voltage_V'] * original_5046['Current_A']/10), color='b', label='original') 109 | #ax2.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'] / (eight_turn_5046['Voltage_V'] * eight_turn_5046['Current_A']/10), color='r', label='8 turn') 110 | #ax2.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'] / (nine_turn_5046['Voltage_V'] * nine_turn_5046['Current_A']/10), color='g', label='9 turn') 111 | ax2.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'] / (eleven_turn_5046['Voltage_V'] * eleven_turn_5046['Current_A']/10), color='g', label='11 turn') 112 | ax2.plot(eleven_turn_5046_ms['Time_ms'], eleven_turn_5046_ms['Thrust_g'] / (eleven_turn_5046_ms['Voltage_V'] * eleven_turn_5046_ms['Current_A']/10), color='r', label='11 turn multistrand') 113 | ax2.set_ylabel('Efficiency (g/W)') 114 | ax2.set_ylim([0, 5]) 115 | 116 | #ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 117 | #ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 118 | #ax1.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'], color='g', label='9 turn') 119 | ax1.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'], color='g', label='11 turn') 120 | ax1.plot(eleven_turn_5046_ms['Time_ms'], eleven_turn_5046_ms['Thrust_g'], color='r', label='11 turn multistrand') 121 | ax1.set_xlabel('Time_ms') 122 | ax1.set_xlim([3500, 25000]) 123 | ax1.set_ylabel('Thrust (g)') 124 | ax1.set_ylim([0, 1500]) 125 | ax1.legend() 126 | 127 | 128 | ## Thrust efficiency plot Cyclone 5050 129 | ax1 = fig.add_subplot(224) 130 | ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5050') 131 | ax2 = ax1.twinx() 132 | ax3 = ax1.twinx() 133 | ax3.spines["right"].set_position(("axes", 1.2)) 134 | 135 | ax3.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['dshot'], color='y', label='dshot') 136 | ax3.set_xlabel('Time_ms') 137 | ax3.set_ylabel('dshot') 138 | ax3.set_ylim([0, 2100]) 139 | 140 | #ax2.plot(original_5050['Time_ms'], original_5050['Thrust_g'] / (original_5050['Voltage_V'] * original_5050['Current_A']/10), color='b', label='original') 141 | #ax2.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'] / (eight_turn_5050['Voltage_V'] * eight_turn_5050['Current_A']/10), color='r', label='8 turn') 142 | #ax2.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'] / (nine_turn_5050['Voltage_V'] * nine_turn_5050['Current_A']/10), color='g', label='9 turn') 143 | ax2.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'] / (eleven_turn_5050['Voltage_V'] * eleven_turn_5050['Current_A']/10), color='orange', label='11 turn') 144 | ax2.plot(eleven_turn_5050_ms['Time_ms'], eleven_turn_5050_ms['Thrust_g'] / (eleven_turn_5050_ms['Voltage_V'] * eleven_turn_5050_ms['Current_A']/10), color='r', label='11 turn multistrand') 145 | ax2.set_ylabel('Efficiency (g/W)') 146 | ax2.set_ylim([0, 5]) 147 | 148 | #ax1.plot(original_5050['Time_ms'], original_5050['Thrust_g'], color='b', label='original') 149 | #ax1.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'], color='r', label='8 turn') 150 | #ax1.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'], color='g', label='9 turn') 151 | ax1.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'], color='orange', label='11 turn') 152 | ax1.plot(eleven_turn_5050_ms['Time_ms'], eleven_turn_5050_ms['Thrust_g'], color='r', label='11 turn multistrand') 153 | ax1.set_xlabel('Time_ms') 154 | ax1.set_xlim([3500, 25000]) 155 | ax1.set_ylabel('Thrust (g)') 156 | ax1.set_ylim([0, 1500]) 157 | ax1.legend() -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/emax_rs2306_plots - rpm thrust.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Aug 26 19:53:08 2019 4 | 5 | @author: Jye 6 | """ 7 | 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | 11 | #original = np.genfromtxt('original.csv', delimiter=',', skip_header=1, 12 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 13 | #eight_turn = np.genfromtxt('8_turn.csv', delimiter=',', skip_header=1, 14 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 15 | #nine_turn = np.genfromtxt('9_turn.csv', delimiter=',', skip_header=1, 16 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 17 | eleven_turn = np.genfromtxt('11_turn - 6s.csv', delimiter=',', skip_header=1, 18 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 19 | 20 | #original_5046 = np.genfromtxt('original_cyclone_5046.csv', delimiter=',', skip_header=1, 21 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 22 | #eight_turn_5046 = np.genfromtxt('8_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 23 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 24 | #nine_turn_5046 = np.genfromtxt('9_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 25 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 26 | eleven_turn_5046 = np.genfromtxt('11_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 27 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 28 | eleven_turn_5046_6s = np.genfromtxt('11_turn_cyclone_5046 - 6s.csv', delimiter=',', skip_header=1, 29 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 30 | 31 | #original_5050 = np.genfromtxt('original_cyclone_5050.csv', delimiter=',', skip_header=1, 32 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 33 | #eight_turn_5050 = np.genfromtxt('8_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 34 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 35 | #nine_turn_5050 = np.genfromtxt('9_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 36 | # names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 37 | eleven_turn_5050 = np.genfromtxt('11_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 38 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 39 | eleven_turn_5050_6s = np.genfromtxt('11_turn_cyclone_5050 - 6s.csv', delimiter=',', skip_header=1, 40 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 41 | 42 | ## KV plot 43 | fig = plt.figure() 44 | ax1 = fig.add_subplot(111) 45 | ax1.title.set_text('6s') 46 | #ax2 = ax1.twinx() 47 | #ax3 = ax1.twinx() 48 | #ax3.spines["right"].set_position(("axes", 1.2)) 49 | #fig.subplots_adjust(right=0.75) 50 | 51 | #ax3.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['dshot'], color='y', label='dshot') 52 | #ax3.set_ylabel('dshot') 53 | #ax3.set_ylim([0, 2100]) 54 | 55 | #ax1.plot(original['Time_ms'], original['RPM'] / original['Voltage_V'], color='b', label='original') 56 | #ax1.plot(eight_turn['Time_ms'], eight_turn['RPM'] / eight_turn['Voltage_V'], color='r', label='8 turn') 57 | #ax1.plot(nine_turn['Time_ms'], nine_turn['RPM'] / nine_turn['Voltage_V'], color='g', label='9 turn') 58 | ax1.plot(eleven_turn_5046['RPM'], eleven_turn_5046['Thrust_g'] , color='b', label='11 turn 5046 4s') 59 | ax1.plot(eleven_turn_5046_6s['RPM'], eleven_turn_5046_6s['Thrust_g'] , color='g', label='11 turn 5046 6s') 60 | ax1.plot(eleven_turn_5050['RPM'], eleven_turn_5050['Thrust_g'] , color='r', label='11 turn 5050 4s') 61 | ax1.plot(eleven_turn_5050_6s['RPM'], eleven_turn_5050_6s['Thrust_g'] , color='orange', label='11 turn 5050 6s') 62 | ax1.set_xlabel('RPM') 63 | ax1.set_xlim([0, 30000]) 64 | ax1.set_ylabel('Thrust_g') 65 | ax1.set_ylim([0, 1500]) 66 | ax1.legend() 67 | 68 | # 69 | ### Response plot 70 | #ax1 = fig.add_subplot(223) 71 | #ax1.title.set_text('Response - Cyclone 5046 Vs 5050') 72 | ##ax2 = ax1.twinx() 73 | #ax3 = ax1.twinx() 74 | #ax3.spines["right"].set_position(("axes", 1.2)) 75 | #fig.subplots_adjust(right=0.75) 76 | # 77 | #ax3.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['dshot'], color='y', label='dshot') 78 | #ax3.set_xlabel('Time_ms') 79 | #ax3.set_ylabel('dshot') 80 | #ax3.set_ylim([0, 2100]) 81 | # 82 | ##ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 83 | ##ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 84 | #ax1.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'], color='g', label='11 turn - 5046') 85 | #ax1.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'], color='orange', label='11 turn - 5050') 86 | #ax1.set_xlabel('Time_ms') 87 | #ax1.set_xlim([3500, 25000]) 88 | #ax1.set_ylabel('Thrust (g)') 89 | #ax1.set_xlim([11900, 12300]) 90 | #ax1.set_ylim([0, 1500]) 91 | #ax1.legend() 92 | # 93 | # 94 | ### Thrust efficiency plot Cyclone 5046 95 | #ax1 = fig.add_subplot(222) 96 | #ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5046') 97 | #ax2 = ax1.twinx() 98 | #ax3 = ax1.twinx() 99 | #ax3.spines["right"].set_position(("axes", 1.2)) 100 | # 101 | #ax3.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['dshot'], color='y', label='dshot') 102 | #ax3.set_xlabel('Time_ms') 103 | #ax3.set_ylabel('dshot') 104 | #ax3.set_ylim([0, 2100]) 105 | # 106 | ##ax2.plot(original_5046['Time_ms'], original_5046['Thrust_g'] / (original_5046['Voltage_V'] * original_5046['Current_A']/10), color='b', label='original') 107 | ##ax2.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'] / (eight_turn_5046['Voltage_V'] * eight_turn_5046['Current_A']/10), color='r', label='8 turn') 108 | ##ax2.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'] / (nine_turn_5046['Voltage_V'] * nine_turn_5046['Current_A']/10), color='g', label='9 turn') 109 | #ax2.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'] / (eleven_turn_5046['Voltage_V'] * eleven_turn_5046['Current_A']/10), color='g', label='11 turn') 110 | #ax2.set_ylabel('Efficiency (g/W)') 111 | #ax2.set_ylim([0, 5]) 112 | # 113 | ##ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 114 | ##ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 115 | ##ax1.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'], color='g', label='9 turn') 116 | #ax1.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'], color='g', label='11 turn') 117 | #ax1.set_xlabel('Time_ms') 118 | #ax1.set_xlim([3500, 25000]) 119 | #ax1.set_ylabel('Thrust (g)') 120 | #ax1.set_ylim([0, 1500]) 121 | #ax1.legend() 122 | # 123 | # 124 | ### Thrust efficiency plot Cyclone 5050 125 | #ax1 = fig.add_subplot(224) 126 | #ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5050') 127 | #ax2 = ax1.twinx() 128 | #ax3 = ax1.twinx() 129 | #ax3.spines["right"].set_position(("axes", 1.2)) 130 | # 131 | #ax3.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['dshot'], color='y', label='dshot') 132 | #ax3.set_xlabel('Time_ms') 133 | #ax3.set_ylabel('dshot') 134 | #ax3.set_ylim([0, 2100]) 135 | # 136 | ##ax2.plot(original_5050['Time_ms'], original_5050['Thrust_g'] / (original_5050['Voltage_V'] * original_5050['Current_A']/10), color='b', label='original') 137 | ##ax2.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'] / (eight_turn_5050['Voltage_V'] * eight_turn_5050['Current_A']/10), color='r', label='8 turn') 138 | ##ax2.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'] / (nine_turn_5050['Voltage_V'] * nine_turn_5050['Current_A']/10), color='g', label='9 turn') 139 | #ax2.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'] / (eleven_turn_5050['Voltage_V'] * eleven_turn_5050['Current_A']/10), color='orange', label='11 turn') 140 | #ax2.set_ylabel('Efficiency (g/W)') 141 | #ax2.set_ylim([0, 5]) 142 | # 143 | ##ax1.plot(original_5050['Time_ms'], original_5050['Thrust_g'], color='b', label='original') 144 | ##ax1.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'], color='r', label='8 turn') 145 | ##ax1.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'], color='g', label='9 turn') 146 | #ax1.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'], color='orange', label='11 turn') 147 | #ax1.set_xlabel('Time_ms') 148 | #ax1.set_xlim([3500, 25000]) 149 | #ax1.set_ylabel('Thrust (g)') 150 | #ax1.set_ylim([0, 1500]) 151 | #ax1.legend() -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/emax_rs2306_plots.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Aug 26 19:53:08 2019 4 | 5 | @author: Jye 6 | """ 7 | 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | 11 | original = np.genfromtxt('original.csv', delimiter=',', skip_header=1, 12 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 13 | eight_turn = np.genfromtxt('8_turn.csv', delimiter=',', skip_header=1, 14 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 15 | nine_turn = np.genfromtxt('9_turn.csv', delimiter=',', skip_header=1, 16 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 17 | eleven_turn = np.genfromtxt('11_turn.csv', delimiter=',', skip_header=1, 18 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 19 | 20 | original_5046 = np.genfromtxt('original_cyclone_5046.csv', delimiter=',', skip_header=1, 21 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 22 | eight_turn_5046 = np.genfromtxt('8_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 23 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 24 | nine_turn_5046 = np.genfromtxt('9_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 25 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 26 | eleven_turn_5046 = np.genfromtxt('11_turn_cyclone_5046.csv', delimiter=',', skip_header=1, 27 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 28 | 29 | original_5050 = np.genfromtxt('original_cyclone_5050.csv', delimiter=',', skip_header=1, 30 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 31 | eight_turn_5050 = np.genfromtxt('8_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 32 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 33 | nine_turn_5050 = np.genfromtxt('9_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 34 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 35 | eleven_turn_5050 = np.genfromtxt('11_turn_cyclone_5050.csv', delimiter=',', skip_header=1, 36 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 37 | 38 | ## KV plot 39 | fig = plt.figure() 40 | ax1 = fig.add_subplot(221) 41 | ax1.title.set_text('KV') 42 | #ax2 = ax1.twinx() 43 | ax3 = ax1.twinx() 44 | ax3.spines["right"].set_position(("axes", 1.2)) 45 | fig.subplots_adjust(right=0.75) 46 | 47 | ax3.plot(original['Time_ms'], original['dshot'], color='y', label='dshot') 48 | ax3.set_ylabel('dshot') 49 | ax3.set_ylim([0, 2100]) 50 | 51 | ax1.plot(original['Time_ms'], original['RPM'] / original['Voltage_V'], color='b', label='original') 52 | ax1.plot(eight_turn['Time_ms'], eight_turn['RPM'] / eight_turn['Voltage_V'], color='r', label='8 turn') 53 | ax1.plot(nine_turn['Time_ms'], nine_turn['RPM'] / nine_turn['Voltage_V'], color='g', label='9 turn') 54 | ax1.plot(eleven_turn['Time_ms'], eleven_turn['RPM'] / eleven_turn['Voltage_V'], color='orange', label='11 turn') 55 | ax1.set_xlabel('Time_ms') 56 | ax1.set_xlim([3500, 25000]) 57 | ax1.set_ylabel('KV') 58 | ax1.set_ylim([1500, 2500]) 59 | ax1.legend() 60 | 61 | 62 | ## Response plot 63 | ax1 = fig.add_subplot(223) 64 | ax1.title.set_text('Response - Cyclone 5046') 65 | #ax2 = ax1.twinx() 66 | ax3 = ax1.twinx() 67 | ax3.spines["right"].set_position(("axes", 1.2)) 68 | fig.subplots_adjust(right=0.75) 69 | 70 | ax3.plot(original['Time_ms'], original['dshot'], color='y', label='dshot') 71 | ax3.set_xlabel('Time_ms') 72 | ax3.set_ylabel('dshot') 73 | ax3.set_ylim([0, 2100]) 74 | 75 | ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 76 | ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 77 | ax1.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'], color='g', label='9 turn') 78 | ax1.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'], color='orange', label='11 turn') 79 | ax1.set_xlabel('Time_ms') 80 | ax1.set_xlim([3500, 25000]) 81 | ax1.set_ylabel('Thrust (g)') 82 | ax1.set_xlim([11900, 12300]) 83 | ax1.set_ylim([0, 1500]) 84 | ax1.legend() 85 | 86 | 87 | ## Thrust efficiency plot Cyclone 5046 88 | ax1 = fig.add_subplot(222) 89 | ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5046') 90 | ax2 = ax1.twinx() 91 | ax3 = ax1.twinx() 92 | ax3.spines["right"].set_position(("axes", 1.2)) 93 | 94 | ax3.plot(original_5046['Time_ms'], original_5046['dshot'], color='y', label='dshot') 95 | ax3.set_xlabel('Time_ms') 96 | ax3.set_ylabel('dshot') 97 | ax3.set_ylim([0, 2100]) 98 | 99 | ax2.plot(original_5046['Time_ms'], original_5046['Thrust_g'] / (original_5046['Voltage_V'] * original_5046['Current_A']/10), color='b', label='original') 100 | ax2.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'] / (eight_turn_5046['Voltage_V'] * eight_turn_5046['Current_A']/10), color='r', label='8 turn') 101 | ax2.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'] / (nine_turn_5046['Voltage_V'] * nine_turn_5046['Current_A']/10), color='g', label='9 turn') 102 | ax2.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'] / (eleven_turn_5046['Voltage_V'] * eleven_turn_5046['Current_A']/10), color='orange', label='11 turn') 103 | ax2.set_ylabel('Efficiency (g/W)') 104 | ax2.set_ylim([0, 5]) 105 | 106 | ax1.plot(original_5046['Time_ms'], original_5046['Thrust_g'], color='b', label='original') 107 | ax1.plot(eight_turn_5046['Time_ms'], eight_turn_5046['Thrust_g'], color='r', label='8 turn') 108 | ax1.plot(nine_turn_5046['Time_ms'], nine_turn_5046['Thrust_g'], color='g', label='9 turn') 109 | ax1.plot(eleven_turn_5046['Time_ms'], eleven_turn_5046['Thrust_g'], color='orange', label='11 turn') 110 | ax1.set_xlabel('Time_ms') 111 | ax1.set_xlim([3500, 25000]) 112 | ax1.set_ylabel('Thrust (g)') 113 | ax1.set_ylim([0, 1500]) 114 | ax1.legend() 115 | 116 | 117 | ## Thrust efficiency plot Cyclone 5050 118 | ax1 = fig.add_subplot(224) 119 | ax1.title.set_text('Thrust (g) & Efficiency (g/W) - Cyclone 5050') 120 | ax2 = ax1.twinx() 121 | ax3 = ax1.twinx() 122 | ax3.spines["right"].set_position(("axes", 1.2)) 123 | 124 | ax3.plot(original_5050['Time_ms'], original_5050['dshot'], color='y', label='dshot') 125 | ax3.set_xlabel('Time_ms') 126 | ax3.set_ylabel('dshot') 127 | ax3.set_ylim([0, 2100]) 128 | 129 | ax2.plot(original_5050['Time_ms'], original_5050['Thrust_g'] / (original_5050['Voltage_V'] * original_5050['Current_A']/10), color='b', label='original') 130 | ax2.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'] / (eight_turn_5050['Voltage_V'] * eight_turn_5050['Current_A']/10), color='r', label='8 turn') 131 | ax2.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'] / (nine_turn_5050['Voltage_V'] * nine_turn_5050['Current_A']/10), color='g', label='9 turn') 132 | ax2.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'] / (eleven_turn_5050['Voltage_V'] * eleven_turn_5050['Current_A']/10), color='orange', label='11 turn') 133 | ax2.set_ylabel('Efficiency (g/W)') 134 | ax2.set_ylim([0, 5]) 135 | 136 | ax1.plot(original_5050['Time_ms'], original_5050['Thrust_g'], color='b', label='original') 137 | ax1.plot(eight_turn_5050['Time_ms'], eight_turn_5050['Thrust_g'], color='r', label='8 turn') 138 | ax1.plot(nine_turn_5050['Time_ms'], nine_turn_5050['Thrust_g'], color='g', label='9 turn') 139 | ax1.plot(eleven_turn_5050['Time_ms'], eleven_turn_5050['Thrust_g'], color='orange', label='11 turn') 140 | ax1.set_xlabel('Time_ms') 141 | ax1.set_xlim([3500, 25000]) 142 | ax1.set_ylabel('Thrust (g)') 143 | ax1.set_ylim([0, 1500]) 144 | ax1.legend() -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/old excel/EMAX RS2306 2400KV.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/old excel/EMAX RS2306 2400KV.xlsx -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/old excel/plots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/old excel/plots.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/original.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/original.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/original_cyclone_5046.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/original_cyclone_5046.csv.plot.png -------------------------------------------------------------------------------- /data/EMAX RS2306 2400KV/original_cyclone_5050.csv.plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JyeSmith/dshot-esc-tester/8695f27fb705892a0906acddc60b4a4e8dfb21a3/data/EMAX RS2306 2400KV/original_cyclone_5050.csv.plot.png -------------------------------------------------------------------------------- /data/drop csv on here to plot.bat: -------------------------------------------------------------------------------- 1 | python "C:\Users\Jye\Documents\GitHub\dshot-esc-tester\data\thrustPlot.py" %* -------------------------------------------------------------------------------- /data/thrustPlot.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import sys 5 | 6 | print(sys.argv[1]) 7 | 8 | thrustFile = sys.argv[1] 9 | 10 | data = np.genfromtxt(thrustFile, delimiter=',', skip_header=1, 11 | names=['Time_ms', 'dshot', 'Voltage_V', 'Current_A', 'RPM', 'Thrust_g']) 12 | fig = plt.figure() 13 | 14 | ax1 = fig.add_subplot(311) 15 | fig.subplots_adjust(right=0.75) 16 | ax2 = ax1.twinx() 17 | ax3 = ax1.twinx() 18 | ax3.spines["right"].set_position(("axes", 1.2)) 19 | 20 | ax3.plot(data['Time_ms'], data['dshot'], color='y', label='dshot') 21 | ax3.set_xlabel('Time_ms') 22 | ax3.set_ylabel('dshot') 23 | ax3.set_ylim([0, 2100]) 24 | 25 | ax2.plot(data['Time_ms'], data['Thrust_g']/(data['Voltage_V']*data['Current_A']/10), color='r', label='g/W') 26 | ax2.set_ylabel('g/W') 27 | ax2.set_ylim([0, 5]) 28 | ax2.legend() 29 | 30 | ax1.plot(data['Time_ms'], data['Thrust_g'], color='b', label='Thrust (g)') 31 | ax1.set_ylabel('Thrust (g)') 32 | ax1.set_ylim([0, 1500]) 33 | ax1.legend() 34 | 35 | 36 | ax1 = fig.add_subplot(312) 37 | fig.subplots_adjust(right=0.75) 38 | ax2 = ax1.twinx() 39 | ax3 = ax1.twinx() 40 | ax3.spines["right"].set_position(("axes", 1.2)) 41 | 42 | ax3.plot(data['Time_ms'], data['dshot'], color='y', label='dshot') 43 | ax3.set_xlabel('Time_ms') 44 | ax3.set_ylabel('dshot') 45 | ax3.set_ylim([0, 2100]) 46 | 47 | ax2.plot(data['Time_ms'], data['Voltage_V'], color='r', label='Voltage (V)') 48 | ax2.set_ylabel('Voltage (V)') 49 | ax2.set_ylim([15.5, 26]) 50 | ax2.legend() 51 | 52 | ax1.plot(data['Time_ms'], data['Current_A']/10, color='b', label='Current (A)') 53 | ax1.set_ylabel('Current (A)') 54 | ax1.set_ylim([0, 50]) 55 | ax1.legend() 56 | 57 | 58 | ax1 = fig.add_subplot(313) 59 | fig.subplots_adjust(right=0.75) 60 | ax2 = ax1.twinx() 61 | ax3 = ax1.twinx() 62 | ax3.spines["right"].set_position(("axes", 1.2)) 63 | 64 | ax3.plot(data['Time_ms'], data['dshot'], color='y', label='dshot') 65 | ax3.set_xlabel('Time_ms') 66 | ax3.set_ylabel('dshot') 67 | ax3.set_ylim([0, 2100]) 68 | 69 | ax1.plot(data['Time_ms'], data['RPM'], color='r', label='RPM') 70 | ax1.set_ylabel('RPM') 71 | ax1.set_ylim([0, 30000]) 72 | ax1.legend() 73 | 74 | ax2.plot(data['Time_ms'], data['RPM']/data['Voltage_V'], color='b', label='KV') 75 | ax2.set_ylabel('KV') 76 | ax2.set_ylim([0, 2600]) 77 | ax2.legend() 78 | 79 | 80 | fig.savefig(thrustFile+'.plot.png') 81 | #fig.savefig('plot.pdf') -------------------------------------------------------------------------------- /dshot-esc-tester.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * "THE PROP-WARE LICENSE" (Revision 42): 4 | * wrote this file. As long as you retain this notice you 5 | * can do whatever you want with this stuff. If we meet some day, and you think 6 | * this stuff is worth it, you can buy me some props in return. Jye Smith 7 | * ---------------------------------------------------------------------------- 8 | */ 9 | 10 | /* Some of the below code is taken from examples provided by Felix on RCGroups.com 11 | * 12 | * KISS ESC 24A Serial Example Code for Arduino. 13 | * https://www.rcgroups.com/forums/showthread.php?2555162-KISS-ESC-24A-Race-Edition-Flyduino-32bit-ESC 14 | * https://www.rcgroups.com/forums/showatt.php?attachmentid=8521072&d=1450345654 * 15 | */ 16 | 17 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 18 | // www.miniquadtestbench.com 19 | // Uncommenting the below define will start the test sequence defined on MQTB 20 | // WARNING - THE MOTOR WILL START TO SPIN AUTOMATICALLY!!! 21 | //#define MINIQUADTESTBENCH 22 | //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 | 24 | #include 25 | #include "SSD1306.h" 26 | #include "freertos/FreeRTOS.h" 27 | #include "freertos/task.h" 28 | #include "freertos/event_groups.h" 29 | #include "Arduino.h" 30 | #include "esp32-hal.h" 31 | #include "HX711.h" 32 | 33 | #define MOTOR_POLES 14 34 | 35 | // HX711 36 | #define LOADCELL_DOUT_PIN 25 37 | #define LOADCELL_SCK_PIN 26 38 | #define LOADCELL_CALIBRATION 345.0 39 | HX711 loadcell; 40 | long thrust = 0; 41 | 42 | TaskHandle_t Task1; 43 | 44 | rmt_data_t dshotPacket[16]; 45 | rmt_obj_t* rmt_send = NULL; 46 | 47 | hw_timer_t * timer = NULL; 48 | 49 | HardwareSerial MySerial(1); 50 | 51 | SSD1306 display(0x3c, 21, 22); // 21 and 22 are default pins 52 | 53 | uint8_t receivedBytes = 0; 54 | volatile bool requestTelemetry = false; 55 | bool printTelemetry = true; 56 | uint16_t dshotUserInputValue = 0; 57 | uint16_t dshotmin = 48; 58 | uint16_t dshotmax = 2047; 59 | uint16_t dshotidle = dshotmin + round(3.5*(dshotmax-dshotmin)/100); // 3.5% 60 | uint16_t dshot50 = dshotmin + round(50*(dshotmax-dshotmin)/100); // 50% 61 | uint16_t dshot75 = dshotmin + round(75*(dshotmax-dshotmin)/100); // 75% 62 | int16_t ESC_telemetrie[5]; // Temperature, Voltage, Current, used mAh, eRpM 63 | bool runMQTBSequence = false; 64 | 65 | uint32_t currentTime; 66 | uint8_t temperature = 0; 67 | uint8_t temperatureMax = 0; 68 | float voltage = 0; 69 | float voltageMin = 99; 70 | uint32_t current = 0; 71 | uint32_t currentMax = 0; 72 | uint32_t erpm = 0; 73 | uint32_t erpmMax = 0; 74 | uint32_t rpm = 0; 75 | uint32_t rpmMAX = 0; 76 | uint32_t kv = 0; 77 | uint32_t kvMax = 0; 78 | 79 | void gotTouch8(){ 80 | dshotUserInputValue = 0; 81 | runMQTBSequence = false; 82 | printTelemetry = true; 83 | } // DIGITAL_CMD_MOTOR_STOP 84 | void gotTouch9(){ 85 | dshotUserInputValue = 247; 86 | resetMaxMinValues(); 87 | runMQTBSequence = false; 88 | printTelemetry = true; 89 | } // 10% 90 | void gotTouch7(){ 91 | dshotUserInputValue = 447; 92 | resetMaxMinValues(); 93 | runMQTBSequence = false; 94 | printTelemetry = true; 95 | } // 20% 96 | void gotTouch6(){ 97 | dshotUserInputValue = 1047; 98 | resetMaxMinValues(); 99 | runMQTBSequence = false; 100 | printTelemetry = true; 101 | } // 50% 102 | void gotTouch5(){ 103 | dshotUserInputValue = 2047; 104 | resetMaxMinValues(); 105 | runMQTBSequence = false; 106 | printTelemetry = true; 107 | } // 100% 108 | void gotTouch4(){ 109 | temperatureMax = 0; 110 | voltageMin = 99; 111 | currentMax = 0; 112 | erpmMax = 0; 113 | rpmMAX = 0; 114 | kvMax = 0; 115 | runMQTBSequence = false; 116 | printTelemetry = true; 117 | } 118 | void resetMaxMinValues() { 119 | gotTouch4(); 120 | } 121 | 122 | void IRAM_ATTR getTelemetry(){ 123 | requestTelemetry = true; 124 | } 125 | 126 | void startTelemetryTimer() { 127 | timer = timerBegin(0, 80, true); // timer_id = 0; divider=80; countUp = true; 128 | timerAttachInterrupt(timer, &getTelemetry, true); // edge = true 129 | timerAlarmWrite(timer, 20000, true); //1000 = 1 ms 130 | timerAlarmEnable(timer); 131 | } 132 | 133 | // Second core used to handle dshot packets 134 | void secondCoreTask( void * pvParameters ){ 135 | while(1){ 136 | 137 | dshotOutput(dshotUserInputValue, requestTelemetry); 138 | 139 | if (requestTelemetry) { 140 | requestTelemetry = false; 141 | receivedBytes = 0; 142 | } 143 | 144 | delay(1); 145 | 146 | } 147 | } 148 | 149 | void setup() { 150 | 151 | Serial.begin(115200); 152 | MySerial.begin(115200, SERIAL_8N1, 16, 17); 153 | 154 | loadcell.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); 155 | loadcell.set_scale(LOADCELL_CALIBRATION); 156 | loadcell.tare(); 157 | 158 | if ((rmt_send = rmtInit(5, true, RMT_MEM_64)) == NULL) { 159 | Serial.println("init sender failed\n"); 160 | } 161 | 162 | float realTick = rmtSetTick(rmt_send, 12.5); // 12.5ns sample rate 163 | Serial.printf("rmt_send tick set to: %fns\n", realTick); 164 | 165 | display.init(); 166 | display.flipScreenVertically(); 167 | display.setFont(ArialMT_Plain_10); 168 | 169 | // Output disarm signal while esc initialises and do some display stuff. 170 | uint8_t xbeep = random(15, 100); 171 | uint8_t ybeep = random(15, 50); 172 | uint8_t ibeep = 0; 173 | while (millis() < 3500) { 174 | dshotOutput(0, false); 175 | delay(1); 176 | 177 | display.clear(); 178 | ibeep++; 179 | if (ibeep == 100) { 180 | ibeep = 0; 181 | xbeep = random(15, 50); 182 | ybeep = random(15, 50); 183 | } 184 | display.drawString(xbeep, ybeep, "beep"); 185 | if (millis() < 500) { 186 | display.drawString(0, 0, "Initialising ESC... 4s"); 187 | } else if (millis() < 1500) { 188 | display.drawString(0, 0, "Initialising ESC... 3s"); 189 | } else if (millis() < 2500) { 190 | display.drawString(0, 0, "Initialising ESC... 2s"); 191 | } else { 192 | display.drawString(0, 0, "Initialising ESC... 1s"); 193 | } 194 | display.display(); 195 | } 196 | 197 | touchAttachInterrupt(T4, gotTouch4, 40); 198 | touchAttachInterrupt(T5, gotTouch5, 40); 199 | touchAttachInterrupt(T6, gotTouch6, 40); 200 | touchAttachInterrupt(T7, gotTouch7, 40); 201 | touchAttachInterrupt(T8, gotTouch8, 40); 202 | touchAttachInterrupt(T9, gotTouch9, 40); 203 | 204 | // Empty Rx Serial of garbage telemtry 205 | while(MySerial.available()) 206 | MySerial.read(); 207 | 208 | requestTelemetry = true; 209 | 210 | BeginWebUpdate(); 211 | 212 | startTelemetryTimer(); // Timer used to request tlm continually in case ESC rcv bad packet 213 | 214 | xTaskCreatePinnedToCore(secondCoreTask, "Task1", 10000, NULL, 1, &Task1, 0); 215 | 216 | Serial.print("Time (ms)"); 217 | Serial.print(","); 218 | Serial.print("dshot"); 219 | Serial.print(","); 220 | Serial.print("Voltage (V)"); 221 | Serial.print(","); 222 | Serial.print("Current (A)"); 223 | Serial.print(","); 224 | Serial.print("RPM"); 225 | Serial.print(","); 226 | Serial.println("Thrust (g)"); 227 | 228 | #ifdef MINIQUADTESTBENCH 229 | dshotUserInputValue = dshotidle; 230 | runMQTBSequence = true; 231 | display.clear(); 232 | display.setTextAlignment(TEXT_ALIGN_LEFT); 233 | display.drawString(0, 0, "Running MQTB Sequence..."); 234 | display.display(); 235 | #endif 236 | 237 | } 238 | 239 | void loop() { 240 | 241 | HandleWebUpdate(); 242 | 243 | if(loadcell.is_ready()) { 244 | thrust = loadcell.get_units(1); 245 | } 246 | 247 | if(!requestTelemetry) { 248 | receiveTelemtrie(); 249 | } 250 | 251 | #ifdef MINIQUADTESTBENCH 252 | if(runMQTBSequence) { 253 | currentTime = millis(); 254 | if(currentTime >= 4000 && currentTime < 6000) { 255 | dshotUserInputValue = dshot50; 256 | } else if(currentTime >= 6000 && currentTime < 8000) { 257 | dshotUserInputValue = dshotidle; 258 | } else if(currentTime >= 8000 && currentTime < 10000) { 259 | dshotUserInputValue = dshot75; 260 | } else if(currentTime >= 10000 && currentTime < 12000) { 261 | dshotUserInputValue = dshotidle; 262 | } else if(currentTime >= 12000 && currentTime < 14000) { 263 | dshotUserInputValue = dshotmax; 264 | } else if(currentTime >= 14000 && currentTime < 16000) { 265 | dshotUserInputValue = dshotmin; 266 | } else if(currentTime >= 16000 && currentTime < 22000) { 267 | dshotUserInputValue = dshotmin + (currentTime-16000)*(dshotmax-dshotmin)/6000.0; 268 | } else if(currentTime >= 24000 && currentTime < 26000) { 269 | dshotUserInputValue = dshotidle; 270 | } else if(currentTime >= 26000 && currentTime < 28000) { 271 | printTelemetry = false; 272 | dshotUserInputValue = 0; 273 | } 274 | } 275 | #endif 276 | 277 | } 278 | 279 | void receiveTelemtrie(){ 280 | static uint8_t SerialBuf[10]; 281 | 282 | if(MySerial.available()){ 283 | SerialBuf[receivedBytes] = MySerial.read(); 284 | receivedBytes++; 285 | } 286 | 287 | if(receivedBytes > 9){ // transmission complete 288 | 289 | uint8_t crc8 = get_crc8(SerialBuf, 9); // get the 8 bit CRC 290 | 291 | if(crc8 != SerialBuf[9]) { 292 | // Serial.println("CRC transmission failure"); 293 | 294 | // Empty Rx Serial of garbage telemtry 295 | while(MySerial.available()) 296 | MySerial.read(); 297 | 298 | requestTelemetry = true; 299 | 300 | return; // transmission failure 301 | } 302 | 303 | // compute the received values 304 | ESC_telemetrie[0] = SerialBuf[0]; // temperature 305 | ESC_telemetrie[1] = (SerialBuf[1]<<8)|SerialBuf[2]; // voltage 306 | ESC_telemetrie[2] = (SerialBuf[3]<<8)|SerialBuf[4]; // Current 307 | ESC_telemetrie[3] = (SerialBuf[5]<<8)|SerialBuf[6]; // used mA/h 308 | ESC_telemetrie[4] = (SerialBuf[7]<<8)|SerialBuf[8]; // eRpM *100 309 | 310 | requestTelemetry = true; 311 | 312 | if(!runMQTBSequence) { // Do not update during MQTB sequence. Slows serial output. 313 | updateDisplay(); 314 | } 315 | 316 | // Serial.println("Requested Telemetrie"); 317 | // Serial.print("Temperature (C): "); 318 | // Serial.println(ESC_telemetrie[0]); 319 | // Serial.print("Voltage (V): "); 320 | // Serial.println(ESC_telemetrie[1] / 100.0); 321 | // Serial.print("Current (mA): "); 322 | // Serial.println(ESC_telemetrie[2] * 100); 323 | // Serial.print("mA/h: "); 324 | // Serial.println(ESC_telemetrie[3] * 10); 325 | // Serial.print("eRPM : "); 326 | // Serial.println(ESC_telemetrie[4] * 100); 327 | // Serial.print("RPM : "); 328 | // Serial.println(ESC_telemetrie[4] * 100 / 7.0); // 7 = 14 magnet count / 2 329 | // Serial.print("KV : "); 330 | // Serial.println( (ESC_telemetrie[4] * 100 / 7.0) / (ESC_telemetrie[1] / 100.0) ); // 7 = 14 magnet count / 2 331 | // Serial.println(" "); 332 | // Serial.println(" "); 333 | 334 | if(printTelemetry) { 335 | Serial.print(millis()); 336 | Serial.print(","); 337 | Serial.print(dshotUserInputValue); 338 | Serial.print(","); 339 | // Serial.print("Voltage (V): "); 340 | Serial.print(ESC_telemetrie[1] / 100.0); 341 | Serial.print(","); 342 | // Serial.print("Current (A): "); 343 | Serial.print(ESC_telemetrie[2] / 10.0); 344 | Serial.print(","); 345 | // Serial.print("RPM : "); 346 | Serial.print(ESC_telemetrie[4] * 100 / (MOTOR_POLES / 2)); 347 | Serial.print(","); 348 | // Thrust 349 | Serial.println(thrust); 350 | } 351 | 352 | temperature = 0.9*temperature + 0.1*ESC_telemetrie[0]; 353 | if (temperature > temperatureMax) { 354 | temperatureMax = temperature; 355 | } 356 | 357 | voltage = 0.9*voltage + 0.1*(ESC_telemetrie[1] / 100.0); 358 | if (voltage < voltageMin) { 359 | voltageMin = voltage; 360 | } 361 | 362 | current = 0.9*current + 0.1*(ESC_telemetrie[2] * 100); 363 | if (current > currentMax) { 364 | currentMax = current; 365 | } 366 | 367 | erpm = 0.9*erpm + 0.1*(ESC_telemetrie[4] * 100); 368 | if (erpm > erpmMax) { 369 | erpmMax = erpm; 370 | } 371 | 372 | rpm = erpm / (MOTOR_POLES / 2); 373 | if (rpm > rpmMAX) { 374 | rpmMAX = rpm; 375 | } 376 | 377 | if (rpm) { // Stops weird numbers :| 378 | kv = rpm / voltage / ( (float(dshotUserInputValue) - dshotmin) / (dshotmax - dshotmin) ); 379 | } else { 380 | kv = 0; 381 | } 382 | if (kv > kvMax) { 383 | kvMax = kv; 384 | } 385 | 386 | } 387 | 388 | return; 389 | 390 | } 391 | 392 | void dshotOutput(uint16_t value, bool telemetry) { 393 | 394 | uint16_t packet; 395 | 396 | // telemetry bit 397 | if (telemetry) { 398 | packet = (value << 1) | 1; 399 | } else { 400 | packet = (value << 1) | 0; 401 | } 402 | 403 | // https://github.com/betaflight/betaflight/blob/09b52975fbd8f6fcccb22228745d1548b8c3daab/src/main/drivers/pwm_output.c#L523 404 | int csum = 0; 405 | int csum_data = packet; 406 | for (int i = 0; i < 3; i++) { 407 | csum ^= csum_data; 408 | csum_data >>= 4; 409 | } 410 | csum &= 0xf; 411 | packet = (packet << 4) | csum; 412 | 413 | // durations are for dshot600 414 | // https://blck.mn/2016/11/dshot-the-new-kid-on-the-block/ 415 | // Bit length (total timing period) is 1.67 microseconds (T0H + T0L or T1H + T1L). 416 | // For a bit to be 1, the pulse width is 1250 nanoseconds (T1H – time the pulse is high for a bit value of ONE) 417 | // For a bit to be 0, the pulse width is 625 nanoseconds (T0H – time the pulse is high for a bit value of ZERO) 418 | for (int i = 0; i < 16; i++) { 419 | if (packet & 0x8000) { 420 | dshotPacket[i].level0 = 1; 421 | dshotPacket[i].duration0 = 100; 422 | dshotPacket[i].level1 = 0; 423 | dshotPacket[i].duration1 = 34; 424 | } else { 425 | dshotPacket[i].level0 = 1; 426 | dshotPacket[i].duration0 = 50; 427 | dshotPacket[i].level1 = 0; 428 | dshotPacket[i].duration1 = 84; 429 | } 430 | packet <<= 1; 431 | } 432 | 433 | rmtWrite(rmt_send, dshotPacket, 16); 434 | 435 | return; 436 | 437 | } 438 | 439 | uint8_t update_crc8(uint8_t crc, uint8_t crc_seed){ 440 | uint8_t crc_u, i; 441 | crc_u = crc; 442 | crc_u ^= crc_seed; 443 | for ( i=0; i<8; i++) crc_u = ( crc_u & 0x80 ) ? 0x7 ^ ( crc_u << 1 ) : ( crc_u << 1 ); 444 | return (crc_u); 445 | } 446 | 447 | uint8_t get_crc8(uint8_t *Buf, uint8_t BufLen){ 448 | uint8_t crc = 0, i; 449 | for( i=0; i