def combine_bike_rider(bicyclePar, riderPar): """ Combines the inertia of the bicycle frame with the inertia of a rider. Parameters ---------- bicyclePar : dictionary The benchmark parameter set of a bicycle. riderPar : dictionary The rider's mass, center of mass, and inertia expressed in the benchmark bicycle reference frame. Returns ------- bicyclePar : dictionary The benchmark bicycle parameters with a rigid rider added to the bicycle frame. """ # list the masses of the rider and bicycle masses = np.array([riderPar['mB'], bicyclePar['mB']]) # list the centers of mass of the rider and bicycle coordinates = np.array([[riderPar['xB'], bicyclePar['xB']], [riderPar['yB'], 0.], [riderPar['zB'], bicyclePar['zB']]]) # calculate the new mass and center of mass mT, cT = total_com(coordinates, masses) # get inertia tensors for the bicycle and rider IRider = part_inertia_tensor(riderPar, 'B') IBicycle = part_inertia_tensor(bicyclePar, 'B') # calculate the distance from the center of mass of each body to the # center of mass of the combined body dRider = np.array([riderPar['xB'] - cT[0], riderPar['yB'] - cT[1], riderPar['zB'] - cT[2]]) dBicycle = np.array([bicyclePar['xB'] - cT[0], 0., bicyclePar['zB'] - cT[2]]) # calculate the total inertia about the total body center of mass I = (parallel_axis(IRider, riderPar['mB'], dRider) + parallel_axis(IBicycle, bicyclePar['mB'], dBicycle)) # assign new inertia back to bike bicyclePar['xB'] = cT[0] bicyclePar['zB'] = cT[2] bicyclePar['yB'] = 0.0 bicyclePar['mB'] = mT bicyclePar['IBxx'] = I[0, 0] bicyclePar['IBxz'] = I[0, 2] bicyclePar['IByy'] = I[1, 1] bicyclePar['IBzz'] = I[2, 2] return bicyclePar
def steer_assembly_moment_of_inertia(self, handlebar=True, fork=True, wheel=True, aboutSteerAxis=False, nominal=False): """ Returns the inertia tensor of the steer assembly with respect to a reference frame aligned with the steer axis. Parameters ---------- handlebar : boolean, optional If true the handlebar will be included in the calculation. fork : boolean, optional If true the fork will be included in the calculation. wheel : boolean, optional If true then the wheel will be included in the calculation. aboutSteerAxis : boolean, optional If true the inertia tensor will be with respect to a point made from the projection of the center of mass onto the steer axis. nominal : boolean, optional If true the nominal values will be returned instead of a uarray. Returns ------- iAss : float Inertia tensor of the specified steer assembly parts with respect to a reference frame aligned with the steer axis. Notes ----- The 3 component is aligned with the steer axis (pointing downward), the 1 component is perpendicular to the steer axis (pointing forward) and the 2 component is perpendicular to the steer axis (pointing to the right). This function does not currently take into account the flywheel, D, if it is defined, beware. """ # load in the Benchmark parameter set par = self.parameters['Benchmark'] if 'mD' in par.keys(): print( "You have a flywheel defined. Beware that it is ignored in " + "the calculations and the results do not reflect that it is " + "there.") # there should always be either an H (handlebar/fork) and sometimes # there is a G (handlebar) and S (fork) if the fork and handlebar were # measured separately try: if fork and handlebar: # handlebar/fork I = inertia.part_inertia_tensor(par, 'H') m = par['mH'] x = par['xH'] z = par['zH'] elif fork and not handlebar: # fork alone I = inertia.part_inertia_tensor(par, 'S') m = par['mS'] x = par['xS'] z = par['zS'] elif handlebar and not fork: # handlebar alone I = inertia.part_inertia_tensor(par, 'G') m = par['mG'] x = par['xG'] z = par['zG'] else: # if neither set to zero I = np.zeros((3, 3)) m = 0. x = 0. z = 0. except KeyError: raise ValueError("The fork and handlebar were not measured " + "separately for this bicycle." + " Try making both the fork and handlebar either" + " both True or both False.") if wheel: # list the mass and com of the handlebar/assembly and the front # wheel masses = np.array([m, par['mF']]) coords = np.array([[x, par['w']], [0., 0.], [z, -par['rF']]]) # mass and com of the entire assembly mAss, cAss = com.total_com(coords, masses) # front wheel inertia in the benchmark reference frame about the # com IF = inertia.part_inertia_tensor(par, 'F') # distance from the fork/handlebar assembly (without wheel) to the # new center of mass for the assembly with the wheel d = np.array([x - cAss[0], 0., z - cAss[2]]) # distance from the front wheel center to the new center of mass # for the assembly with the wheel dF = np.array([par['w'] - cAss[0], 0., -par['rF'] - cAss[2]]) # this is the inertia of the assembly about the com with reference # to the benchmark bicycle reference frame iAss = (inertia.parallel_axis(I, m, d) + inertia.parallel_axis(IF, par['mF'], dF)) # this is the inertia of the assembly about a reference frame aligned with # the steer axis and through the center of mass iAssRot = inertia.rotate_inertia_tensor(iAss, par['lam']) else: # don't add the wheel mAss = m cAss = np.array([x, 0., z]) iAssRot = inertia.rotate_inertia_tensor(I, par['lam']) if aboutSteerAxis: # this is the distance from the assembly com to the steer axis distance = geometry.distance_to_steer_axis(par['w'], par['c'], par['lam'], cAss) print "handlebar cg distance", distance # now calculate the inertia about the steer axis of the rotated frame iAss = inertia.parallel_axis(iAssRot, mAss, np.array([distance, 0., 0.])) else: iAss = iAssRot if nominal: return unumpy.nominal_values(iAss) else: return iAss
def calculate_benchmark_from_measured(mp): '''Returns the benchmark (Meijaard 2007) parameter set based on the measured data. Parameters ---------- mp : dictionary Complete set of measured data. Returns ------- par : dictionary Benchmark bicycle parameter set. ''' forkIsSplit = is_fork_split(mp) par = {} # calculate the wheelbase, steer axis tilt and trail par = geometry.calculate_benchmark_geometry(mp, par) # masses par['mB'] = mp['mB'] par['mF'] = mp['mF'] par['mR'] = mp['mR'] try: # we measured the mass of the flywheel plus the mass of the front # wheel, mp['mD'], so to get the actual mass of the flywheel, subtract # the mass of the front wheel par['mD'] = mp['mD'] - mp['mF'] except KeyError: pass if forkIsSplit: par['mS'] = mp['mS'] par['mG'] = mp['mG'] else: par['mH'] = mp['mH'] # get the slopes, intercepts and betas for each part slopes, intercepts, betas = com.part_com_lines(mp, par, forkIsSplit) # calculate the centers of mass for part in slopes.keys(): par['x' + part], par['z' + part] = com.center_of_mass( slopes[part], intercepts[part]) # find the center of mass of the handlebar/fork assembly if the fork was # split if forkIsSplit: coordinates = np.array([[par['xS'], par['xG']], [0., 0.], [par['zS'], par['zG']]]) masses = np.array([par['mS'], par['mG']]) mH, cH = inertia.total_com(coordinates, masses) par['mH'] = mH par['xH'] = cH[0] par['zH'] = cH[2] # local accelation due to gravity par['g'] = mp['g'] # calculate the wheel y inertias par['IFyy'] = inertia.compound_pendulum_inertia(mp['mF'], mp['g'], mp['lF'], mp['TcF1']) par['IRyy'] = inertia.compound_pendulum_inertia(mp['mR'], mp['g'], mp['lR'], mp['TcR1']) try: # we measured the inertia of the front wheel with the flywheel inside iFlywheelPlusFwheel = inertia.compound_pendulum_inertia( mp['mD'], mp['g'], mp['lF'], mp['TcD1']) par['IDyy'] = iFlywheelPlusFwheel - par['IFyy'] except KeyError: pass # calculate the y inertias for the frame and fork lB = (par['xB']**2 + (par['zB'] + par['rR'])**2)**(0.5) par['IByy'] = inertia.compound_pendulum_inertia(mp['mB'], mp['g'], lB, mp['TcB1']) if forkIsSplit: # fork lS = ((par['xS'] - par['w'])**2 + (par['zS'] + par['rF'])**2)**(0.5) par['ISyy'] = inertia.compound_pendulum_inertia( mp['mS'], mp['g'], lS, mp['TcS1']) # handlebar l1, l2 = geometry.calculate_l1_l2(mp['h6'], mp['h7'], mp['d5'], mp['d6'], mp['l']) u1, u2 = geometry.fwheel_to_handlebar_ref(par['lam'], l1, l2) lG = ((par['xG'] - par['w'] + u1)**2 + (par['zG'] + par['rF'] + u2)**2)**(.5) par['IGyy'] = inertia.compound_pendulum_inertia( mp['mG'], mp['g'], lG, mp['TcG1']) else: lH = ((par['xH'] - par['w'])**2 + (par['zH'] + par['rF'])**2)**(0.5) par['IHyy'] = inertia.compound_pendulum_inertia( mp['mH'], mp['g'], lH, mp['TcH1']) # calculate the stiffness of the torsional pendulum IPxx, IPyy, IPzz = inertia.tube_inertia(mp['lP'], mp['mP'], mp['dP'] / 2., 0.) torStiff = inertia.torsional_pendulum_stiffness(IPyy, mp['TtP1']) #print "Torsional pendulum stiffness:", torStiff # calculate the wheel x/z inertias par['IFxx'] = inertia.tor_inertia(torStiff, mp['TtF1']) par['IRxx'] = inertia.tor_inertia(torStiff, mp['TtR1']) try: par['IDxx'] = inertia.tor_inertia(torStiff, mp['TtD1']) - par['IFxx'] except KeyError: pass pendulumInertias = {} # calculate the in plane moments of inertia for part, slopeSet in slopes.items(): # the number of orientations for this part numOrien = len(slopeSet) # intialize arrays to store the inertia values and orientation angles penInertia = np.zeros(numOrien, dtype=object) beta = np.array(betas[part]) # fill arrays of the inertias for i in range(numOrien): penInertia[i] = inertia.tor_inertia(torStiff, mp['Tt' + part + str(i + 1)]) # store these inertias pendulumInertias[part] = list(penInertia) inert = inertia.inertia_components(penInertia, beta) for i, axis in enumerate(['xx', 'xz', 'zz']): par['I' + part + axis] = inert[i] if forkIsSplit: # combine the moments of inertia to find the total handlebar/fork MoI IG = inertia.part_inertia_tensor(par, 'G') IS = inertia.part_inertia_tensor(par, 'S') # columns are parts, rows = x, y, z coordinates = np.array([[par['xG'], par['xS']], [0., 0.], [par['zG'], par['zS']]]) masses = np.array([par['mG'], par['mS']]) par['mH'], cH = com.total_com(coordinates, masses) par['xH'] = cH[0] par['zH'] = cH[2] dG = np.array([par['xG'] - par['xH'], 0., par['zG'] - par['zH']]) dS = np.array([par['xS'] - par['xH'], 0., par['zS'] - par['zH']]) IH = (inertia.parallel_axis(IG, par['mG'], dG) + inertia.parallel_axis(IS, par['mS'], dS)) par['IHxx'] = IH[0, 0] par['IHxz'] = IH[0, 2] par['IHyy'] = IH[1, 1] par['IHzz'] = IH[2, 2] # package the extra information that is useful outside this function extras = { 'slopes': slopes, 'intercepts': intercepts, 'betas': betas, 'pendulumInertias': pendulumInertias } return par, extras
def steer_assembly_moment_of_inertia(self, handlebar=True, fork=True, wheel=True, aboutSteerAxis=False, nominal=False): """ Returns the inertia tensor of the steer assembly with respect to a reference frame aligned with the steer axis. Parameters ---------- handlebar : boolean, optional If true the handlebar will be included in the calculation. fork : boolean, optional If true the fork will be included in the calculation. wheel : boolean, optional If true then the wheel will be included in the calculation. aboutSteerAxis : boolean, optional If true the inertia tensor will be with respect to a point made from the projection of the center of mass onto the steer axis. nominal : boolean, optional If true the nominal values will be returned instead of a uarray. Returns ------- iAss : float Inertia tensor of the specified steer assembly parts with respect to a reference frame aligned with the steer axis. Notes ----- The 3 component is aligned with the steer axis (pointing downward), the 1 component is perpendicular to the steer axis (pointing forward) and the 2 component is perpendicular to the steer axis (pointing to the right). This function does not currently take into account the flywheel, D, if it is defined, beware. """ # load in the Benchmark parameter set par = self.parameters['Benchmark'] if 'mD' in par.keys(): print("You have a flywheel defined. Beware that it is ignored in " + "the calculations and the results do not reflect that it is " + "there.") # there should always be either an H (handlebar/fork) and sometimes # there is a G (handlebar) and S (fork) if the fork and handlebar were # measured separately try: if fork and handlebar: # handlebar/fork I = inertia.part_inertia_tensor(par, 'H') m = par['mH'] x = par['xH'] z = par['zH'] elif fork and not handlebar: # fork alone I = inertia.part_inertia_tensor(par, 'S') m = par['mS'] x = par['xS'] z = par['zS'] elif handlebar and not fork: # handlebar alone I = inertia.part_inertia_tensor(par, 'G') m = par['mG'] x = par['xG'] z = par['zG'] else: # if neither set to zero I = np.zeros((3, 3)) m = 0. x = 0. z = 0. except KeyError: raise ValueError("The fork and handlebar were not measured " + "separately for this bicycle." + " Try making both the fork and handlebar either" + " both True or both False.") if wheel: # list the mass and com of the handlebar/assembly and the front # wheel masses = np.array([m, par['mF']]) coords = np.array([[x, par['w']], [0., 0.], [z, -par['rF']]]) # mass and com of the entire assembly mAss, cAss = com.total_com(coords, masses) # front wheel inertia in the benchmark reference frame about the # com IF = inertia.part_inertia_tensor(par, 'F') # distance from the fork/handlebar assembly (without wheel) to the # new center of mass for the assembly with the wheel d = np.array([x - cAss[0], 0., z - cAss[2]]) # distance from the front wheel center to the new center of mass # for the assembly with the wheel dF = np.array([par['w'] - cAss[0], 0., -par['rF'] - cAss[2]]) # this is the inertia of the assembly about the com with reference # to the benchmark bicycle reference frame iAss = (inertia.parallel_axis(I, m, d) + inertia.parallel_axis(IF, par['mF'], dF)) # this is the inertia of the assembly about a reference frame aligned with # the steer axis and through the center of mass iAssRot = inertia.rotate_inertia_tensor(iAss, par['lam']) else: # don't add the wheel mAss = m cAss = np.array([x, 0., z]) iAssRot = inertia.rotate_inertia_tensor(I, par['lam']) if aboutSteerAxis: # this is the distance from the assembly com to the steer axis distance = geometry.distance_to_steer_axis(par['w'], par['c'], par['lam'], cAss) print "handlebar cg distance", distance # now calculate the inertia about the steer axis of the rotated frame iAss = inertia.parallel_axis(iAssRot, mAss, np.array([distance, 0., 0.])) else: iAss = iAssRot if nominal: return unumpy.nominal_values(iAss) else: return iAss
def calculate_benchmark_from_measured(mp): '''Returns the benchmark (Meijaard 2007) parameter set based on the measured data. Parameters ---------- mp : dictionary Complete set of measured data. Returns ------- par : dictionary Benchmark bicycle parameter set. ''' forkIsSplit = is_fork_split(mp) par = {} # calculate the wheelbase, steer axis tilt and trail par = geometry.calculate_benchmark_geometry(mp, par) # masses par['mB'] = mp['mB'] par['mF'] = mp['mF'] par['mR'] = mp['mR'] try: # we measured the mass of the flywheel plus the mass of the front # wheel, mp['mD'], so to get the actual mass of the flywheel, subtract # the mass of the front wheel par['mD'] = mp['mD'] - mp['mF'] except KeyError: pass if forkIsSplit: par['mS'] = mp['mS'] par['mG'] = mp['mG'] else: par['mH'] = mp['mH'] # get the slopes, intercepts and betas for each part slopes, intercepts, betas = com.part_com_lines(mp, par, forkIsSplit) # calculate the centers of mass for part in slopes.keys(): par['x' + part], par['z' + part] = com.center_of_mass(slopes[part], intercepts[part]) # find the center of mass of the handlebar/fork assembly if the fork was # split if forkIsSplit: coordinates = np.array([[par['xS'], par['xG']], [0., 0.], [par['zS'], par['zG']]]) masses = np.array([par['mS'], par['mG']]) mH, cH = inertia.total_com(coordinates, masses) par['mH'] = mH par['xH'] = cH[0] par['zH'] = cH[2] # local accelation due to gravity par['g'] = mp['g'] # calculate the wheel y inertias par['IFyy'] = inertia.compound_pendulum_inertia(mp['mF'], mp['g'], mp['lF'], mp['TcF1']) par['IRyy'] = inertia.compound_pendulum_inertia(mp['mR'], mp['g'], mp['lR'], mp['TcR1']) try: # we measured the inertia of the front wheel with the flywheel inside iFlywheelPlusFwheel = inertia.compound_pendulum_inertia(mp['mD'], mp['g'], mp['lF'], mp['TcD1']) par['IDyy'] = iFlywheelPlusFwheel - par['IFyy'] except KeyError: pass # calculate the y inertias for the frame and fork lB = (par['xB']**2 + (par['zB'] + par['rR'])**2)**(0.5) par['IByy'] = inertia.compound_pendulum_inertia(mp['mB'], mp['g'], lB, mp['TcB1']) if forkIsSplit: # fork lS = ((par['xS'] - par['w'])**2 + (par['zS'] + par['rF'])**2)**(0.5) par['ISyy'] = inertia.compound_pendulum_inertia(mp['mS'], mp['g'], lS, mp['TcS1']) # handlebar l1, l2 = geometry.calculate_l1_l2(mp['h6'], mp['h7'], mp['d5'], mp['d6'], mp['l']) u1, u2 = geometry.fwheel_to_handlebar_ref(par['lam'], l1, l2) lG = ((par['xG'] - par['w'] + u1)**2 + (par['zG'] + par['rF'] + u2)**2)**(.5) par['IGyy'] = inertia.compound_pendulum_inertia(mp['mG'], mp['g'], lG, mp['TcG1']) else: lH = ((par['xH'] - par['w'])**2 + (par['zH'] + par['rF'])**2)**(0.5) par['IHyy'] = inertia.compound_pendulum_inertia(mp['mH'], mp['g'], lH, mp['TcH1']) # calculate the stiffness of the torsional pendulum IPxx, IPyy, IPzz = inertia.tube_inertia(mp['lP'], mp['mP'], mp['dP'] / 2., 0.) torStiff = inertia.torsional_pendulum_stiffness(IPyy, mp['TtP1']) #print "Torsional pendulum stiffness:", torStiff # calculate the wheel x/z inertias par['IFxx'] = inertia.tor_inertia(torStiff, mp['TtF1']) par['IRxx'] = inertia.tor_inertia(torStiff, mp['TtR1']) try: par['IDxx'] = inertia.tor_inertia(torStiff, mp['TtD1']) - par['IFxx'] except KeyError: pass pendulumInertias = {} # calculate the in plane moments of inertia for part, slopeSet in slopes.items(): # the number of orientations for this part numOrien = len(slopeSet) # intialize arrays to store the inertia values and orientation angles penInertia = np.zeros(numOrien, dtype=object) beta = np.array(betas[part]) # fill arrays of the inertias for i in range(numOrien): penInertia[i] = inertia.tor_inertia(torStiff, mp['Tt' + part + str(i + 1)]) # store these inertias pendulumInertias[part] = list(penInertia) inert = inertia.inertia_components(penInertia, beta) for i, axis in enumerate(['xx', 'xz', 'zz']): par['I' + part + axis] = inert[i] if forkIsSplit: # combine the moments of inertia to find the total handlebar/fork MoI IG = inertia.part_inertia_tensor(par, 'G') IS = inertia.part_inertia_tensor(par, 'S') # columns are parts, rows = x, y, z coordinates = np.array([[par['xG'], par['xS']], [0., 0.], [par['zG'], par['zS']]]) masses = np.array([par['mG'], par['mS']]) par['mH'], cH = com.total_com(coordinates, masses) par['xH'] = cH[0] par['zH'] = cH[2] dG = np.array([par['xG'] - par['xH'], 0., par['zG'] - par['zH']]) dS = np.array([par['xS'] - par['xH'], 0., par['zS'] - par['zH']]) IH = (inertia.parallel_axis(IG, par['mG'], dG) + inertia.parallel_axis(IS, par['mS'], dS)) par['IHxx'] = IH[0, 0] par['IHxz'] = IH[0, 2] par['IHyy'] = IH[1, 1] par['IHzz'] = IH[2, 2] # package the extra information that is useful outside this function extras = {'slopes' : slopes, 'intercepts' : intercepts, 'betas' : betas, 'pendulumInertias' : pendulumInertias} return par, extras