Sizing of a multi-rotor drone#

Written by Marc Budinger (INSA Toulouse) and Scott Delbecq (ISAE-SUPAERO), Toulouse, France.

The objective of this notebook is to select the best compromise of components (propeller, motor, ESC, battery) of a multi-rotor drone for given specifiations.

Scipy and math packages will be used for this notebook in order to illustrate the optimization algorithms of python.

import scipy
import scipy.optimize
from math import pi
from math import sqrt
from math import sin
import math
import numpy as np
import timeit
import pandas as pd
from IPython.display import display, HTML
pd.options.display.float_format = '{:,.2f}'.format
import ipywidgets as widgets
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 12
     10 from IPython.display import display, HTML
     11 pd.options.display.float_format = '{:,.2f}'.format
---> 12 import ipywidgets as widgets

ModuleNotFoundError: No module named 'ipywidgets'

Sizing code#

The set of equations of a sizing code can generate typical issues such :

  • Underconstrained set of equations: the lacking equations can come from additional scenarios, estimation models or additional sizing variable.

  • overconstrained equations often due to the selection of a component on multiple critera: the adding of over-sizing coefficients and constraints in the optimization problem can generally fix this issue

  • algebraic loops often due to selection criteria requiring informations generally available after the selection

Concerning overconstraints components, we have here:

  • Brushless motors with multiple torque and voltage constraints (hover and transient vertical displacement)

Multiple algebraic loops appears in the sizing problem:

  • The thrust depends of the total mass which depend of components required for generating this thrust

The final optimization problem depends thus of these parameters:

  • \(\beta_{pro}=pitch/diameter\) ratio to define the propeller

  • \(k_{os}\) over sizing coefficient on the load mass to estimate the final total mass

  • \(k_{mot}\) over sizing coefficient on the motor torque to estimate the max torque with the hover flight conditions

  • \(k_{speed,mot}\) over sizing coeffcient on the motor speed to take into account voltage limits during hover or take-off flight

  • \(k_{ND}\) slow down propeller coef : ND = kNDmax / k_ND

  • \(k_{D}\) aspect ratio D_in_arm/D_out_arm (diameters ratio) for the beam of the frame

  • \(k_{mb}\) ratio battery mass / payload mass

  • \(k_{vb}\) over sizing coefficient for the battery voltage

More details in the setting up of sizing code can be found in the following paper:

Delbecq, S., Budinger, M., Ochotorena, A., Reysset, A., & Defaÿ, F. (2020). Efficient sizing and optimization of multirotor drones based on scaling laws and similarity models. Aerospace Science and Technology, 102, 105873.

The sizing code is defined here in a function which can give:

  • an evaluation of the objective: here the total mass

  • an evaluation of the constraints:

Objectives and specifications#

Main specifications :

  • a load (video, control card) of mass \(M_{load}\).

  • an autonomy \(t_{hf}\) for the hover flight.

  • an acceleration to take off \(a_{to}\).

# Specifications

# Load
M_pay = 1 # [kg] load mass

# Acceleration during take off
a_to = 2 * 9.81 # [m/s²] acceleration

# Autonomy
t_hov_spec = 18. # [min] time of hover flight

# MTOW
MTOW = 12 # [kg] maximal mass

# Objectif
MAX_TIME = False # Objective

# Optimization bounds
# beta,  k_os, k_ND, k_mot, k_speed_mot, k_mb, k_vb, k_D
bounds = [(0.3,0.6), (1,400), (1,100), (1,100), (1,400), (0.1,100), (1,5), (0,0.95)]

Architecture defintion and design assumptions#

# Architecture of the multi-rotor drone (4,6, 8 arms, ...)
N_arm = 4 # [-] number of arm
N_pro_arm = 1 # [-] number of propeller per arm (1 or 2)
N_pro = N_pro_arm * N_arm # [-] Propellers number

Reference parameters#

Battery#

# Reference parameters for scaling laws
# Ref : MK-quadro
M_bat_ref = .329 # [kg] mass
E_bat_ref = 220.*3600.*.329 # [J]

# Ref : Turnigy K_Force 70HV 
P_esc_ref = 3108. # [W] Power
M_esc_ref = .115 # [kg] Mass

Motor#

# Motor reference
# Ref : AXI 5325/16 GOLD LINE
T_nom_mot_ref = 2.32  # [N.m] rated torque
T_max_mot_ref = 85./70.*T_nom_mot_ref # [N.m] max torque
R_mot_ref = 0.03  # [Ohm] resistance
M_mot_ref = 0.575 # [kg] mass
K_mot_ref = 0.03 # [N.m/A] torque coefficient
T_mot_fr_ref = 0.03 # [N.m] friction torque (zero load, nominal speed)

Frame#

# Reference parameters for scaling laws
sigma_max = 280e6/4. # [Pa] Composite max stress (2 reduction for dynamic, 2 reduction for stress concentration)
rho_s = 1700. # [kg/m3] Volumic mass of aluminum

Propeller#

# Specifications
rho_air=1.18# [kg/m^3] Air density
ND_max=105000./60.*.0254 #[Hz.m] Max speed limit (N.D max) for APC MR propellers


# Reference parameters for scaling laws
D_pro_ref=11.*.0254# [m] Reference propeller diameter
M_pro_ref=0.53*0.0283# [kg] Reference propeller mass
# -----------------------
# sizing code
# -----------------------
# inputs: 
# - param: optimisation variables vector (reduction ratio, oversizing coefficient)
# - arg: selection of output  
# output: 
# - objective if arg='Obj', problem characteristics if arg='Prt', constraints other else
def SizingCode(param, arg):
# Design variables
# ---
    beta_pro = param[0] # pitch/diameter ratio of the propeller
    k_os = param[1] # over sizing coefficient on the load mass 
    k_ND = param[2] # slow down propeller coef : ND = kNDmax / k_ND
    k_mot = param[3] # over sizing coefficient on the motor torque
    k_speed_mot = param[4] # over sizing coefficient on the motor speed
    k_mb = param[5] # ratio battery / payload mass 
    k_vb = param[6] # over sizing coefficient for the battery voltage
    k_D = param[7] # aspect ratio e_arm/D_out_arm (thickness/diameter) for the beam of the frame

# Hover& Take-Off thrust 
# ---
    M_total = k_os * M_pay # [kg] Estimation of the total mass (or equivalent weight of dynamic scenario)
    F_pro_hov = M_total * (9.81) / N_pro # [N] Thrust per propeller for hover
    F_pro_to = M_total * (9.81 + a_to) / N_pro # [N] Thrust per propeller for take-off


#PROPELLER
# --- 

    C_t = 4.27e-02 + 1.44e-01 * beta_pro  # Thrust coef with T=C_T.rho.n^2.D^4 - 0.8 for de-rating of APC catalog
    C_p = -1.48e-03 + 9.72e-02 * beta_pro  # Power coef with P=C_p.rho.n^3.D^5

    # Propeller selection with take-off scenario
    D_pro = (F_pro_to / (C_t*rho_air*(ND_max/k_ND)**2.))**0.5  # [m] Propeller diameter
    n_pro_to = ND_max / k_ND / D_pro # [Hz] Propeller speed 
    Omega_pro_to = n_pro_to * 2*pi # [rad/s] Propeller speed

    M_pro = M_pro_ref * (D_pro/D_pro_ref)**2. # [kg] Propeller mass

    P_pro_to = C_p * rho_air * n_pro_to**3. * D_pro**5. # [W] Power per propeller
    T_pro_to = P_pro_to / Omega_pro_to # [N.m] Propeller torque

    # Propeller torque & speed for hover
    n_pro_hov = sqrt(F_pro_hov/(C_t * rho_air *D_pro**4.)) # [Hz] hover speed
    Omega_pro_hov = n_pro_hov * 2.*pi # [rad/s] Propeller speed

    P_pro_hov = C_p * rho_air * n_pro_hov**3. * D_pro**5. # [W] Power per propeller
    T_pro_hov = P_pro_hov / Omega_pro_hov # [N.m] Propeller torque       
    U_bat_est = k_vb*1.84*P_pro_to**(0.36) # [V] battery voltage estimation
    

# MOTOR
# --- 
    T_nom_mot = k_mot * T_pro_hov   # [N.m] Motor nominal torque per propeller

    M_mot = M_mot_ref * (T_nom_mot/T_nom_mot_ref)**(3./3.5) # [kg] Motor mass

    # Selection with take-off speed
    K_mot = U_bat_est / (k_speed_mot*Omega_pro_to) # [N.m/A] or [V/(rad/s)] Kt motor

    R_mot = R_mot_ref * (T_nom_mot/T_nom_mot_ref)**(-5./3.5)*(K_mot/K_mot_ref)**2.  # [Ohm] motor resistance
    T_mot_fr = T_mot_fr_ref * (T_nom_mot/T_nom_mot_ref)**(3./3.5) # [N.m] Friction torque
    T_max_mot = T_max_mot_ref * (T_nom_mot/T_nom_mot_ref)

    # Hover current and voltage
    I_mot_hov = (T_pro_hov+T_mot_fr) / K_mot # [I] Current of the motor per propeller
    U_mot_hov = R_mot*I_mot_hov + Omega_pro_hov*K_mot # [V] Voltage of the motor per propeller
    P_el_mot_hov = U_mot_hov*I_mot_hov # [W] Hover : electrical power

    # Takeoff current and voltage
    I_mot_to = (T_pro_to+T_mot_fr) / K_mot # [I] Current of the motor per propeller
    U_mot_to = R_mot*I_mot_to + Omega_pro_to*K_mot # [V] Voltage of the motor per propeller
    P_el_mot_to = U_mot_to*I_mot_to # [W] Takeoff : electrical power

# BATTERY AND ESC
# ---     
    # Battery selection & scaling laws sized from hover
    
    N_s_bat = U_bat_est/3.7 # [-] Cell number, round (up value)
    U_bat = 3.7 * N_s_bat # [V] Battery voltage

    M_bat = k_mb * M_pay # [kg] Battery mass

    # Hover --> autonomy
    E_bat = E_bat_ref * M_bat/M_bat_ref*.8 # [J] Energy  of the battery (.8 coefficient because 80% use only of the total capacity)
    C_bat = E_bat/U_bat # [A.s] Capacity  of the battery 
    I_bat = (P_el_mot_hov * N_pro) /.95/U_bat # [A] Current of the battery
    t_hov = C_bat/I_bat/60. # [min] Hover time 

    # ESC
    P_esc = P_el_mot_to * U_bat_est / U_mot_to # [W] power electronic power (corner power or apparent power)
    M_esc = M_esc_ref * (P_esc/P_esc_ref) # [kg] Mass ESC
    V_esc = 1.84 * P_esc**0.36 # [V] ESC voltage        

# Frame sized from max thrust
# ---
    alpha_sep = 2*pi / N_arm # [rad] interior angle separation between propellers
    L_arm = D_pro / (2.*sin(alpha_sep/2.)) # [m] length of the arm

    # Tube diameter & thickness
    D_out_arm = (F_pro_to*N_pro_arm/sigma_max*L_arm*32./(pi*(1.-k_D**4.)))**(1/3)  # [m] outer diameter of the arm (hollow cylinder)
    D_in_arm = k_D * D_out_arm # [m] inner diameter of the arm (hollow cylinder) 

    # Mass
    M_arm = pi/4. * (D_out_arm**2.-D_in_arm**2)*L_arm*rho_s # [kg] mass of the arm (x1) (beams only)  composite
    M_frame = N_arm * M_arm / 0.4 # [kg] mass of the frame (40% of total mass is the arms)

# Objective and Constraints sum up
# ---
    M_total_real=(M_esc+M_pro+M_mot)*N_pro+M_pay+M_bat+M_frame+M_arm

    if MAX_TIME == True:
            constraints = [M_total-M_total_real,
                           U_bat-U_mot_to,
                           T_max_mot-T_pro_to,
                           U_bat-V_esc,
                           MTOW-M_total_real]
    else:
            constraints = [M_total-M_total_real,
                           U_bat-U_mot_to,
                           T_max_mot-T_pro_to,
                           U_bat-V_esc,
                           t_hov-t_hov_spec]

    # Run algorithm slsqp
    if arg == 'Obj':
        if MAX_TIME == True:
            return 1./t_hov # for time maximisation
        else:
            return M_total_real # for mass optimisation

     # Run algorithm differential evolution
    elif arg == 'ObjP':
        P = 0. # Penalisation nulle
        for C in constraints: 
            if (C < 0.): 
                P = P-1e9*C
        if MAX_TIME==True:
            return 1./t_hov + P # for time maximisation
        else:
            return M_total_real + P # for mass optimisation       

    elif arg=='Prt':
        data={
        0 :{'Type': 'Optimization', 'Name': 'beta_pro', 'Value': beta_pro,  'Unit': '[-]', 'Comment': 'ratio pitch-to-diameter '},        1 :{'Type': 'Optimization', 'Name': 'k_os', 'Min': bounds[1][0], 'Value': k_os,  'Unit': '[-]', 'Comment': 'over sizing coefficient on the load mass '},
        1 :{'Type': 'Optimization', 'Name': 'k_ND',  'Value': k_ND,  'Unit': '[-]', 'Comment': 'over sizing coefficient on the propeller speed'},
        2 :{'Type': 'Optimization', 'Name': 'k_mot',  'Value': k_mot,  'Unit': '[-]', 'Comment': 'over sizing coefficient on the motor torque  '},
        3 :{'Type': 'Optimization', 'Name': 'k_speed_mot',  'Value': k_speed_mot,  'Unit': '[-]', 'Comment': 'over sizing coefficient on the propeller speed'},
        4 :{'Type': 'Optimization', 'Name': 'k_mb',  'Value': k_mb,  'Unit': '[-]', 'Comment': 'over sizing coefficient on the battery load mass'},
        5 :{'Type': 'Optimization', 'Name': 'k_vb',  'Value': k_vb,  'Unit': '[-]', 'Comment': 'over sizing coefficient for the battery voltage'},
        6 :{'Type': 'Optimization', 'Name': 'k_D',  'Value': k_D,  'Unit': '[-]', 'Comment': 'aspect ratio e/c (thickness/side) for the beam of the frame'},
        7 :{'Type': 'Constraints', 'Name': 'Const 0',  'Value': constraints[0],  'Unit': '[-]', 'Comment': 'M_total-M_total_real'},
        8 :{'Type': 'Constraints', 'Name': 'Const 1',  'Value': constraints[1],  'Unit': '[-]', 'Comment': 'U_bat-U_mot_to'},
        9 :{'Type': 'Constraints', 'Name': 'Const 2',  'Value': constraints[2],  'Unit': '[-]', 'Comment': 'T_max_mot-T_pro_to'},
        10:{'Type': 'Constraints', 'Name': 'Const 3',  'Value': constraints[3],  'Unit': '[-]', 'Comment': 'U_bat-V_esc'},
        11:{'Type': 'Constraints', 'Name': 'Const 4',  'Value': constraints[4],  'Unit': '[-]', 'Comment': 't_hov-t_hov_spec'},
        12:{'Type': 'Objective', 'Name': 'Objective',  'Value': M_total_real,  'Unit': '[kg]', 'Comment': 'Total mass'},
        13:{'Type': 'Propeller', 'Name': 'F_pro_to', 'Value': F_pro_to, 'Unit': '[N]', 'Comment': 'Thrust for 1 propeller during Take Off'},
        14:{'Type': 'Propeller', 'Name': 'F_pro_hov', 'Value': F_pro_hov, 'Unit': '[N]', 'Comment': 'Thrust for 1 propeller during Hover'},
        15:{'Type': 'Propeller', 'Name': 'rho_air', 'Value': rho_air, 'Unit': '[kg/m^3]', 'Comment': 'Air density'},
        16:{'Type': 'Propeller', 'Name': 'ND_max', 'Value': ND_max, 'Unit': '[Hz.m]', 'Comment': 'Max speed limit (N.D max)'},
        17:{'Type': 'Propeller', 'Name': 'Dpro_ref', 'Value': D_pro_ref, 'Unit': '[m]', 'Comment': 'Reference propeller diameter'},
        18:{'Type': 'Propeller', 'Name': 'M_pro_ref', 'Value': M_pro_ref, 'Unit': '[kg]', 'Comment': 'Reference propeller mass'},
        19:{'Type': 'Propeller', 'Name': 'C_t_sta', 'Value': C_t, 'Unit': '[-]', 'Comment': 'Static thrust coefficient of the propeller'},
        20:{'Type': 'Propeller', 'Name': 'C_p_sta', 'Value': C_p, 'Unit': '[-]', 'Comment': 'Static power coefficient of the propeller'},
        21:{'Type': 'Propeller', 'Name': 'D_pro', 'Value': D_pro, 'Unit': '[m]', 'Comment': 'Diameter of the propeller'},
        22:{'Type': 'Propeller', 'Name': 'n_pro_to', 'Value': n_pro_to, 'Unit': '[Hz]', 'Comment': 'Rev speed of the propeller during takeoff'},
        23:{'Type': 'Propeller', 'Name': 'n_pro_hov', 'Value': n_pro_hov, 'Unit': '[Hz]', 'Comment': 'Rev speed of the propeller during hover'},
        24:{'Type': 'Propeller', 'Name': 'P_pro_to', 'Value': P_pro_to, 'Unit': '[W]', 'Comment': 'Power on the mechanical shaft of the propeller during takeoff'},
        25:{'Type': 'Propeller', 'Name': 'P_pro_hov', 'Value': P_pro_hov, 'Unit': '[W]', 'Comment': 'Power on the mechanical shaft of the propeller during hover'},
        26:{'Type': 'Propeller', 'Name': 'M_pro', 'Value': M_pro, 'Unit': '[kg]', 'Comment': 'Mass of the propeller'},
        27:{'Type': 'Propeller', 'Name': 'Omega_pro_to', 'Value': Omega_pro_to, 'Unit': '[rad/s]', 'Comment': 'Rev speed of the propeller during takeoff'},
        28:{'Type': 'Propeller', 'Name': 'Omega_pro_hov', 'Value': Omega_pro_hov, 'Unit': '[rad/s]', 'Comment': 'Rev speed of the propeller during hover'},
        29:{'Type': 'Propeller', 'Name': 'T_pro_hov', 'Value': T_pro_hov, 'Unit': '[N.m]', 'Comment': 'Torque on the mechanical shaft of the propeller during hover'},
        30:{'Type': 'Propeller', 'Name': 'T_pro_to', 'Value': T_pro_to, 'Unit': '[N.m]', 'Comment': 'Torque on the mechanical shaft of the propeller during takeoff'},
        31:{'Type': 'Motor', 'Name': 'T_max_mot_ref', 'Value': T_max_mot_ref, 'Unit': '[N.m]', 'Comment': 'Max torque'},
        32:{'Type': 'Motor', 'Name': 'R_mot_ref', 'Value': R_mot_ref, 'Unit': '[Ohm]', 'Comment': 'Resistance'},
        33:{'Type': 'Motor', 'Name': 'M_mot_ref', 'Value': M_mot_ref, 'Unit': '[kg]', 'Comment': 'Reference motor mass'},
        34:{'Type': 'Motor', 'Name': 'K_mot_ref', 'Value': K_mot_ref, 'Unit': '[N.m/A]', 'Comment': 'Torque coefficient'},
        35:{'Type': 'Motor', 'Name': 'T_mot_fr_ref', 'Value': T_mot_fr_ref, 'Unit': '[N.m]', 'Comment': 'Friction torque (zero load, nominal speed)'},
        36:{'Type': 'Motor', 'Name': 'T_nom_mot', 'Value': T_nom_mot, 'Unit': '[N.m]', 'Comment': 'Continuous of the selected motor torque'},
        37:{'Type': 'Motor', 'Name': 'T_max_mot', 'Value': T_max_mot, 'Unit': '[N.m]', 'Comment': 'Transient torque possible for climbing'},
        38:{'Type': 'Motor', 'Name': 'R_mot', 'Value': R_mot, 'Unit': '[Ohm]', 'Comment': 'Resistance'},
        39:{'Type': 'Motor', 'Name': 'M_mot', 'Value': M_mot, 'Unit': '[kg]', 'Comment': 'Motor mass'},
        40:{'Type': 'Motor', 'Name': 'K_mot', 'Value': K_mot, 'Unit': '[N.m/A', 'Comment': 'Torque constant of the selected motor'},
        41:{'Type': 'Motor', 'Name': 'T_mot_fr', 'Value': T_mot_fr, 'Unit': '[N.m]', 'Comment': 'Friction torque of the selected motor'},
        42:{'Type': 'Motor', 'Name': 'I_mot_hov', 'Value': I_mot_hov, 'Unit': '[A]', 'Comment': 'Motor current for hover'},
        43:{'Type': 'Motor', 'Name': 'I_mot_to', 'Value': I_mot_to, 'Unit': '[A]', 'Comment': 'Motor current for takeoff'},
        44:{'Type': 'Motor', 'Name': 'U_mot_to', 'Value': U_mot_to, 'Unit': '[V]', 'Comment': 'Motor voltage for takeoff'},
        45:{'Type': 'Motor', 'Name': 'U_mot', 'Value': U_mot_hov, 'Unit': '[V]', 'Comment': 'Nominal voltage '},
        46:{'Type': 'Motor', 'Name': 'P_el_mot_to', 'Value': P_el_mot_to, 'Unit': '[W]', 'Comment': 'Motor electrical power for takeoff'},
        47:{'Type': 'Motor', 'Name': 'P_el_mot_hov', 'Value': P_el_mot_hov, 'Unit': '[W]', 'Comment': 'Motor electrical power for hover'},
        48:{'Type': 'Battery & ESC', 'Name': 'M_bat_ref', 'Value': M_bat_ref, 'Unit': '[kg]', 'Comment': 'Mass of the reference battery '},
        49:{'Type': 'Battery & ESC', 'Name': 'M_esc_ref', 'Value': M_esc_ref, 'Unit': '[kg]', 'Comment': 'Reference ESC mass '},
        50:{'Type': 'Battery & ESC', 'Name': 'P_esc_ref', 'Value': P_esc_ref, 'Unit': '[W]', 'Comment': 'Reference ESC power '},
        51:{'Type': 'Battery & ESC', 'Name': 'N_s_bat', 'Value': np.ceil(N_s_bat), 'Unit': '[-]', 'Comment': 'Number of battery cells '},
        52:{'Type': 'Battery & ESC', 'Name': 'U_bat', 'Value': U_bat, 'Unit': '[V]', 'Comment': 'Battery voltage '},
        53:{'Type': 'Battery & ESC', 'Name': 'M_bat', 'Value': M_bat, 'Unit': '[kg]', 'Comment': 'Battery mass '},
        54:{'Type': 'Battery & ESC', 'Name': 'C_bat', 'Value': C_bat, 'Unit': '[A.s]', 'Comment': 'Battery capacity '},
        55:{'Type': 'Battery & ESC', 'Name': 'I_bat', 'Value': I_bat, 'Unit': '[A]', 'Comment': 'Battery current '},
        56:{'Type': 'Battery & ESC', 'Name': 't_hf', 'Value': t_hov, 'Unit': '[min]', 'Comment': 'Hovering time '},
        57:{'Type': 'Battery & ESC', 'Name': 'P_esc', 'Value': P_esc, 'Unit': '[W]', 'Comment': 'Power electronic power (corner power or apparent power) '},
        58:{'Type': 'Battery & ESC', 'Name': 'M_esc', 'Value': M_esc, 'Unit': '[kg]', 'Comment': 'ESC mass '},
        59:{'Type': 'Battery & ESC', 'Name': 'V_esc', 'Value': V_esc, 'Unit': '[V]', 'Comment': 'ESC voltage '},
        60:{'Type': 'Frame', 'Name': 'N_arm', 'Value': N_arm, 'Unit': '[-]', 'Comment': 'Number of arms '},
        61:{'Type': 'Frame', 'Name': 'N_pro_arm', 'Value': N_pro_arm, 'Unit': '[-]', 'Comment': 'Number of propellers per arm '},
        62:{'Type': 'Frame', 'Name': 'sigma_max', 'Value': sigma_max, 'Unit': '[Pa]', 'Comment': 'Max admisible stress'},
        63:{'Type': 'Frame', 'Name': 'L_arm', 'Value': L_arm, 'Unit': '[m]', 'Comment': 'Length of the arm'},
        64:{'Type': 'Frame', 'Name': 'D_out', 'Value': D_out_arm, 'Unit': '[m]', 'Comment': 'Outer diameter of the arm (tube)'},
        65:{'Type': 'Frame', 'Name': 'Marm', 'Value': M_arm, 'Unit': '[kg]', 'Comment': '1 Arm mass'},
        66:{'Type': 'Frame', 'Name': 'M_frame', 'Value': M_frame, 'Unit': '[kg]', 'Comment': 'Frame mass'},
        67:{'Type': 'Specifications', 'Name': 'M_load', 'Value': M_pay, 'Unit': '[kg]', 'Comment': 'Payload mass'},
        68:{'Type': 'Specifications', 'Name': 't_hf', 'Value': t_hov, 'Unit': '[min]', 'Comment': 'Hovering time '},
        69:{'Type': 'Specifications', 'Name': 'N_arm', 'Value': N_arm, 'Unit': '[-]', 'Comment': 'Number of arms '},
        70:{'Type': 'Specifications', 'Name': 'N_pro_arm', 'Value': N_pro_arm, 'Unit': '[-]', 'Comment': 'Number of propellers per arm '},
        71:{'Type': 'Specifications', 'Name': 'MTOW', 'Value': MTOW, 'Unit': '[kg]', 'Comment': 'Max takeoff Weight'},
        }

        df=pd.DataFrame(data)
        
        # swap the columns with indexes
        df = df.transpose()
   
        items = sorted(df['Type'].unique().tolist())
        def f(Type):
            return df[df['Type']==Type] 
        widgets.interact(f, Type=items)
        return f
        
    else:
        return constraints

Optimization problem#

We will now use the optimization algorithms of the Scipy package to solve and optimize the configuration. We use here the SLSQP algorithm without explicit expression of the gradient (Jacobian). A course on Multidisplinary Gradient optimization algorithms and gradient optimization algorithm is given here:

Joaquim R. R. A. Martins (2012). A Short Course on Multidisciplinary Design Optimization. University of Michigan

The first step is to give an initial value of optimisation variables:

# Optimisation variables
beta_pro = .33 # pitch/diameter ratio of the propeller
k_os = 3.2 # over sizing coefficient on the load mass 
k_ND = 1.2 # slow down propeller coef : ND = kNDmax / k_ND
k_mot = 1. # over sizing coefficient on the motor torque
k_speed_mot = 1.2 # adaption winding coef on the motor speed
k_mb = 1. # ratio battery/load mass
k_vb = 1. # oversizing coefficient for voltage evaluation
k_D = .9 # aspect ratio D_in/D_out (diameters ratio) for the beam of the frame


# Vector of parameters
import numpy as np
parameters = np.array([beta_pro, k_os, k_ND,k_mot, k_speed_mot, k_mb, k_vb,k_D])

We can print of the characterisitcs of the problem before optimization with the initial vector of optimization variables:

# Initial characteristics before optimization 
print("-----------------------------------------------")
print("Initial characteristics before optimization :")
SizingCode(parameters,'Prt')
print("-----------------------------------------------")
-----------------------------------------------
Initial characteristics before optimization :
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[10], line 4
      2 print("-----------------------------------------------")
      3 print("Initial characteristics before optimization :")
----> 4 SizingCode(parameters,'Prt')
      5 print("-----------------------------------------------")

Cell In[8], line 228, in SizingCode(param, arg)
    226     def f(Type):
    227         return df[df['Type']==Type] 
--> 228     widgets.interact(f, Type=items)
    229     return f
    231 else:

NameError: name 'widgets' is not defined

Then we can solve the problem and print of the optimized solution:

# Optimization with SLSQP algorithm
contrainte = lambda x: SizingCode(x, 'Const')
objectif = lambda x: SizingCode(x, 'Obj')
objectifP = lambda x: SizingCode(x, 'ObjP')

SLSQP = True # Optimization algorithm choice

if SLSQP == True:
    # SLSQP omptimisation
    result = scipy.optimize.fmin_slsqp(func=objectif, x0=parameters, 
                                   bounds=bounds,
                                   f_ieqcons=contrainte, iter=1500, acc=1e-5)
else:
    # Differential evolution omptimisation
    result = scipy.optimize.differential_evolution(func=objectifP,
                                   bounds=bounds,
                                   tol=1e-12)

# Final characteristics after optimization 
print("-----------------------------------------------")
print("Final characteristics after optimization :")

if SLSQP == True:
    SizingCode(result,'Obj')
    SizingCode(result, 'Prt')
else:
    SizingCode(result.x,'Obj')
    SizingCode(result.x, 'Prt')
print("-----------------------------------------------")
Optimization terminated successfully    (Exit mode 0)
            Current function value: 1.56796162321685
            Iterations: 7
            Function evaluations: 64
            Gradient evaluations: 7
-----------------------------------------------
Final characteristics after optimization :
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[11], line 25
     23 if SLSQP == True:
     24     SizingCode(result,'Obj')
---> 25     SizingCode(result, 'Prt')
     26 else:
     27     SizingCode(result.x,'Obj')

Cell In[8], line 228, in SizingCode(param, arg)
    226     def f(Type):
    227         return df[df['Type']==Type] 
--> 228     widgets.interact(f, Type=items)
    229     return f
    231 else:

NameError: name 'widgets' is not defined