Mixers: raise exception when geom file is incomplete

pylint format
This commit is contained in:
Julien Lecoeur
2017-10-10 10:05:05 +02:00
committed by Beat Küng
parent cb8d951a7e
commit d46c37be79
2 changed files with 33 additions and 17 deletions
@@ -13,7 +13,7 @@ Cm = 0.05
[[rotors]] [[rotors]]
name = "front_right" name = "front_right"
position = [0.707107, 0.707107, 0.0] position = [0.707107, 0.707107]#, 0.0]
direction = "CCW" direction = "CCW"
[[rotors]] [[rotors]]
@@ -68,8 +68,6 @@ def parse_geom_toml(filename):
Parses toml geometry file and returns a dictionary with curated list of rotors Parses toml geometry file and returns a dictionary with curated list of rotors
''' '''
import toml
# Load toml file # Load toml file
d = toml.load(filename) d = toml.load(filename)
@@ -79,6 +77,16 @@ def parse_geom_toml(filename):
else: else:
default = {} default = {}
# Check info section
if 'info' not in d:
raise AttributeError('{}: Error, missing info section'.format(filename))
# Check info section
for field in ['name', 'key', 'description']:
if field not in d['info']:
raise AttributeError('{}: Error, unspecified info field "{}"'.format(filename, field))
# Convert rotors # Convert rotors
rotor_list = [] rotor_list = []
if 'rotors' in d: if 'rotors' in d:
@@ -89,20 +97,28 @@ def parse_geom_toml(filename):
if field in default: if field in default:
r[field] = default[field] r[field] = default[field]
else: else:
print(filename + ': Error, unspecified field ' + field + ' for rotor ' + r['name']) raise AttributeError('{}: Error, unspecified field "{}" for rotor "{}"'
.format(filename, field, r['name']))
# Check fields # Check direction field
r['direction'] = r['direction'].upper() r['direction'] = r['direction'].upper()
if r['direction'] not in ['CW', 'CCW']: if r['direction'] not in ['CW', 'CCW']:
print(filename + ': Error, invalid direction value "' + r['direction'] + '" for rotor ' + r['name']) raise AttributeError('{}: Error, invalid direction value "{}" for rotor "{}"'
.format(filename, r['direction'], r['name']))
# Check vector3 fields
for field in ['position', 'axis']:
if len(r[field]) != 3:
raise AttributeError('{}: Error, field "{}" for rotor "{}"'
.format(filename, field, r['name']) +
' must be an array of length 3')
# Add rotor to list # Add rotor to list
rotor_list.append(r) rotor_list.append(r)
# Clean dictionary # Clean dictionary
geom = {'info': d['info'], geom = {'info': d['info'],
'rotors': rotor_list} 'rotors': rotor_list}
return geom return geom
@@ -111,7 +127,7 @@ def torque_matrix(center, axis, dirs, Ct, Cm):
Compute torque generated by rotors Compute torque generated by rotors
''' '''
# normalize rotor axis # normalize rotor axis
ax = axis / np.linalg.norm(axis, axis=1)[:,np.newaxis] ax = axis / np.linalg.norm(axis, axis=1)[:, np.newaxis]
torque = Ct * np.cross(center, ax) - Cm * ax * dirs torque = Ct * np.cross(center, ax) - Cm * ax * dirs
return torque return torque
@@ -124,7 +140,7 @@ def geom_to_torque_matrix(geom):
Am = torque_matrix(center=np.array([rotor['position'] for rotor in geom['rotors']]), Am = torque_matrix(center=np.array([rotor['position'] for rotor in geom['rotors']]),
axis=np.array([rotor['axis'] for rotor in geom['rotors']]), axis=np.array([rotor['axis'] for rotor in geom['rotors']]),
dirs=np.array([[1.0 if rotor['direction'] == 'CCW' else -1.0] dirs=np.array([[1.0 if rotor['direction'] == 'CCW' else -1.0]
for rotor in geom['rotors']]), for rotor in geom['rotors']]),
Ct=np.array([[rotor['Ct']] for rotor in geom['rotors']]), Ct=np.array([[rotor['Ct']] for rotor in geom['rotors']]),
Cm=np.array([[rotor['Cm']] for rotor in geom['rotors']])).T Cm=np.array([[rotor['Cm']] for rotor in geom['rotors']])).T
return Am return Am
@@ -134,7 +150,7 @@ def thrust_matrix(axis, Ct):
Compute thrust generated by rotors Compute thrust generated by rotors
''' '''
# Normalize rotor axis # Normalize rotor axis
ax = axis / np.linalg.norm(axis, axis=1)[:,np.newaxis] ax = axis / np.linalg.norm(axis, axis=1)[:, np.newaxis]
thrust = Ct * ax thrust = Ct * ax
return thrust return thrust
@@ -175,8 +191,8 @@ def normalize_mix_px4(B):
Normalize mix for PX4 Normalize mix for PX4
This is for compatibility only and should ideally not be used This is for compatibility only and should ideally not be used
''' '''
B_norm = np.linalg.norm(B,axis=0) B_norm = np.linalg.norm(B, axis=0)
B_max = np.abs(B).max(axis=0) B_max = np.abs(B).max(axis=0)
# Same scale on roll and pitch # Same scale on roll and pitch
B_norm[0] = max(B_norm[0], B_norm[1]) / np.sqrt(B.shape[0] / 2.0) B_norm[0] = max(B_norm[0], B_norm[1]) / np.sqrt(B.shape[0] / 2.0)
@@ -193,7 +209,7 @@ def normalize_mix_px4(B):
B_norm[5] = B_max[5] B_norm[5] = B_max[5]
# Normalize # Normalize
B_norm[np.abs(B_norm)<1e-3] = 1 B_norm[np.abs(B_norm) < 1e-3] = 1
B_px = (B / B_norm) B_px = (B / B_norm)
return B_px return B_px
@@ -287,9 +303,9 @@ if __name__ == '__main__':
parser.add_argument('-o', dest='outputfile', parser.add_argument('-o', dest='outputfile',
help='output header file') help='output header file')
parser.add_argument('--normalize', help='Use normalized mixers (compatibility mode)', parser.add_argument('--normalize', help='Use normalized mixers (compatibility mode)',
action='store_true') action='store_true')
parser.add_argument('--sixdof', help='Use 6dof mixers', parser.add_argument('--sixdof', help='Use 6dof mixers',
action='store_true') action='store_true')
args = parser.parse_args() args = parser.parse_args()
# Find toml files # Find toml files
@@ -331,8 +347,8 @@ if __name__ == '__main__':
# Generate header file # Generate header file
header = generate_mixer_multirotor_header(geom_list, header = generate_mixer_multirotor_header(geom_list,
use_normalized_mix=args.normalize, use_normalized_mix=args.normalize,
use_6dof=args.sixdof) use_6dof=args.sixdof)
# print(header) # print(header)
# Write header file # Write header file