Skip to content
LIBRARY
ControlledRotorCraft.md

ControlledRotorCraft ​

Quadrotor with three PID feedback loops (altitude, roll, pitch) and a 4-element thrust-mixing matrix. Wraps a RotorCraft and drives its thrusters from the controller outputs.

Usage ​

MultibodyComponents.ControlledRotorCraft(kalt=2.7, Tialt=3, Tdalt=0.5, kroll=0.2, Tiroll=100, Tdroll=1, kpitch=0.2, Tipitch=100, Tdpitch=1)

Parameters: ​

NameDescriptionUnitsDefault value
end_joints–true
number_of_links–3
kaltAltitude PID proportional gain–2.7
TialtAltitude PID integral times3
TdaltAltitude PID derivative times0.5
krollRoll PID proportional gain–0.2
TirollRoll PID integral times100
TdrollRoll PID derivative times1
kpitchPitch PID proportional gain–0.2
TipitchPitch PID integral times100
TdpitchPitch PID derivative times1

Behavior ​

Source ​

dyad
"""
Quadrotor with three PID feedback loops (altitude, roll, pitch) and a
4-element thrust-mixing matrix. Wraps a `RotorCraft` and drives its
thrusters from the controller outputs.
"""
component ControlledRotorCraft
  world = MultibodyComponents.World(nominal_length = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
      },
      "tags": []
    }
  }
  rotorcraft = RotorCraft(number_of_links = number_of_links, add_load = true, end_joints = end_joints) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 715, "y1": 161, "x2": 815, "y2": 261, "rot": 0}
      },
      "tags": []
    }
  }
  Calt = BlockComponents.Continuous.LimPID(k = kalt, Ti = Tialt, Td = Tdalt) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 315, "y1": 30, "x2": 415, "y2": 130, "rot": 0}
      },
      "tags": []
    }
  }
  Croll = BlockComponents.Continuous.LimPID(k = kroll, Ti = Tiroll, Td = Tdroll) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 315, "y1": 160, "x2": 415, "y2": 260, "rot": 0}
      },
      "tags": []
    }
  }
  Cpitch = BlockComponents.Continuous.LimPID(k = kpitch, Ti = Tipitch, Td = Tdpitch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 315, "y1": 290, "x2": 415, "y2": 390, "rot": 0}
      },
      "tags": []
    }
  }
  mixer = ControlMixer() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 585, "y1": 161, "x2": 685, "y2": 261, "rot": 0}
      },
      "tags": []
    }
  }
  pid_mux = Mux3() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 455, "y1": 161, "x2": 555, "y2": 261, "rot": 0}
      },
      "tags": []
    }
  }
  pos_demux = Demux6() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 165, "y1": 93, "x2": 265, "y2": 193, "rot": 0}
      },
      "tags": []
    }
  }
  "Altitude PID proportional gain"
  parameter kalt::Real = 2.7
  "Altitude PID integral time"
  parameter Tialt::Time = 3
  "Altitude PID derivative time"
  parameter Tdalt::Time = 0.5
  "Roll PID proportional gain"
  parameter kroll::Real = 0.2
  "Roll PID integral time"
  parameter Tiroll::Time = 100
  "Roll PID derivative time"
  parameter Tdroll::Time = 1
  "Pitch PID proportional gain"
  parameter kpitch::Real = 0.2
  "Pitch PID integral time"
  parameter Tipitch::Time = 100
  "Pitch PID derivative time"
  parameter Tdpitch::Time = 1
  structural parameter end_joints::Boolean = true
  structural parameter number_of_links::Integer = 3
relations
  Calt.u_s = 0
  Calt.u_ff = 0
  Croll.u_s = 0
  Croll.u_ff = 0
  Cpitch.u_s = 0
  Cpitch.u_ff = 0
  connect(Calt.y, pid_mux.u1) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 435, "y": 81}, {"x": 435, "y": 184}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(Croll.y, pid_mux.u2) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(Cpitch.y, pid_mux.u3) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 435, "y": 341}, {"x": 435, "y": 238}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pid_mux.y, mixer.u_in) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(mixer.u_out, rotorcraft.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rotorcraft.y_pos, pos_demux.u_in) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 835, "y": 182},
            {"x": 835, "y": 440},
            {"x": 145, "y": 440},
            {"x": 145, "y": 143}
          ],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(pos_demux.y1, Calt.u_m) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(pos_demux.y2, Croll.u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 295, "y": 119}, {"x": 295, "y": 233}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pos_demux.y3, Cpitch.u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 285, "y": 135}, {"x": 285, "y": 363}], "E": 2}],
      "renderStyle": "standard"
    }
  }
end
Flattened Source
dyad
"""
Quadrotor with three PID feedback loops (altitude, roll, pitch) and a
4-element thrust-mixing matrix. Wraps a `RotorCraft` and drives its
thrusters from the controller outputs.
"""
component ControlledRotorCraft
  world = MultibodyComponents.World(nominal_length = 0.1) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 20, "y1": 20, "x2": 120, "y2": 120, "rot": 0}
      },
      "tags": []
    }
  }
  rotorcraft = RotorCraft(number_of_links = number_of_links, add_load = true, end_joints = end_joints) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 715, "y1": 161, "x2": 815, "y2": 261, "rot": 0}
      },
      "tags": []
    }
  }
  Calt = BlockComponents.Continuous.LimPID(k = kalt, Ti = Tialt, Td = Tdalt) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 315, "y1": 30, "x2": 415, "y2": 130, "rot": 0}
      },
      "tags": []
    }
  }
  Croll = BlockComponents.Continuous.LimPID(k = kroll, Ti = Tiroll, Td = Tdroll) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 315, "y1": 160, "x2": 415, "y2": 260, "rot": 0}
      },
      "tags": []
    }
  }
  Cpitch = BlockComponents.Continuous.LimPID(k = kpitch, Ti = Tipitch, Td = Tdpitch) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 315, "y1": 290, "x2": 415, "y2": 390, "rot": 0}
      },
      "tags": []
    }
  }
  mixer = ControlMixer() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 585, "y1": 161, "x2": 685, "y2": 261, "rot": 0}
      },
      "tags": []
    }
  }
  pid_mux = Mux3() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 455, "y1": 161, "x2": 555, "y2": 261, "rot": 0}
      },
      "tags": []
    }
  }
  pos_demux = Demux6() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 165, "y1": 93, "x2": 265, "y2": 193, "rot": 0}
      },
      "tags": []
    }
  }
  "Altitude PID proportional gain"
  parameter kalt::Real = 2.7
  "Altitude PID integral time"
  parameter Tialt::Time = 3
  "Altitude PID derivative time"
  parameter Tdalt::Time = 0.5
  "Roll PID proportional gain"
  parameter kroll::Real = 0.2
  "Roll PID integral time"
  parameter Tiroll::Time = 100
  "Roll PID derivative time"
  parameter Tdroll::Time = 1
  "Pitch PID proportional gain"
  parameter kpitch::Real = 0.2
  "Pitch PID integral time"
  parameter Tipitch::Time = 100
  "Pitch PID derivative time"
  parameter Tdpitch::Time = 1
  structural parameter end_joints::Boolean = true
  structural parameter number_of_links::Integer = 3
relations
  Calt.u_s = 0
  Calt.u_ff = 0
  Croll.u_s = 0
  Croll.u_ff = 0
  Cpitch.u_s = 0
  Cpitch.u_ff = 0
  connect(Calt.y, pid_mux.u1) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 435, "y": 81}, {"x": 435, "y": 184}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(Croll.y, pid_mux.u2) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(Cpitch.y, pid_mux.u3) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 435, "y": 341}, {"x": 435, "y": 238}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pid_mux.y, mixer.u_in) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(mixer.u_out, rotorcraft.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(rotorcraft.y_pos, pos_demux.u_in) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 835, "y": 182},
            {"x": 835, "y": 440},
            {"x": 145, "y": 440},
            {"x": 145, "y": 143}
          ],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(pos_demux.y1, Calt.u_m) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(pos_demux.y2, Croll.u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 295, "y": 119}, {"x": 295, "y": 233}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pos_demux.y3, Cpitch.u_m) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 285, "y": 135}, {"x": 285, "y": 363}], "E": 2}],
      "renderStyle": "standard"
    }
  }
metadata {}
end


Test Cases ​

No test cases defined.

  • Examples

  • Experiments

  • Analyses