void Power::Propeller::ReloadParams(SimpleXMLTransfer* xml) { Gearing::ReloadParams(xml); SimpleXMLTransfer* prop; bool fExtern = true; if (xml->indexOfAttribute("filename") >= 0) { prop = new SimpleXMLTransfer(FileSysTools::getDataPath("models/propeller/" + xml->getString("filename") + ".xml", true)); } else { prop = xml; fExtern = false; } // Der Sturz wird in jedem Fall aus der Modelldatei gelesen, ansonsten muss man ja eine // Propellerdatei fuer jeden Sturz extra haben. CalcDownthrust(xml); D = prop->getDouble("D"); H = prop->getDouble("H"); J = prop->getDouble("J"); omega_fold = prop->attributeAsDouble("n_fold", -1)*2*M_PI; std::cout << " Propeller: D=" << D << " m, H=" << H << " m, J=" << J << " kg m^2"; if (fExtern) delete prop; }
void Power::Propeller::CalcDownthrust(SimpleXMLTransfer* xml) { int idx = xml->indexOfChild("pos"); if (idx < 0) { dirThrust = CRRCMath::Vector3(1, 0, 0); mulForce = CRRCMath::Vector3(1, 0, 0); mulMoment = CRRCMath::Vector3(0, 0, 0); } else { SimpleXMLTransfer* sxtpos = xml->getChildAt(idx); double downthrust = M_PI * sxtpos->getDouble("downthrust", 0) / 180; dirThrust = CRRCMath::Vector3(cos(downthrust), 0, sin(downthrust)); CRRCMath::Vector3 pos = CRRCMath::Vector3(sxtpos->getDouble("x", 0), 0, sxtpos->getDouble("z", 0)); CRRCMath::Vector3 dirForce = pos * (1/pos.length()); // Split thrust vector into a part parallel to dirForce and a part parallel to dirMoment: // dirThrust = a * dirForce + b * dirMoment // After simplifying all this (and using the variable expressions above) the solution boils down to: double a = sin(downthrust) * dirForce.r[2] + cos(downthrust) * dirForce.r[0]; double b = cos(downthrust) * dirForce.r[2] - sin(downthrust) * dirForce.r[0]; mulForce = dirForce * a; mulMoment = CRRCMath::Vector3(0, b * pos.length(), 0); } mulForce.print("mulForce=", ", "); mulMoment.print("mulMoment=", "\n"); }
void Power::Propeller::ReloadParams_automagic(SimpleXMLTransfer* xml) { SimpleXMLTransfer* p = xml->getChild("battery.shaft.propeller"); D = p->getDouble("D"); H = p->getDouble("H"); J = p->getDouble("J"); double F = xml->getDouble("F"); double V = xml->getDouble("V"); // Der Sturz wird in jedem Fall aus der Modelldatei gelesen, ansonsten muss man ja eine // Propellerdatei fuer jeden Sturz extra haben. CalcDownthrust(p); { // Calculate rotational speed and torque needed: // F = M_PI * 0.25 * D*D * RHO * (V_X + filter.val/2) * filter.val * ETA_PROP; // F = M_PI * 0.25 * D*D * RHO * (V + (Hn-V)/2) * (Hn-V) * ETA_PROP; // F = M_PI * 0.25 * D*D * RHO * (V/2 + Hn/2) * (Hn-V) * ETA_PROP; double n = sqrt( (8*F/(M_PI*D*D*RHO*ETA_PROP)) + V*V)/H; double M = F * (V + (V + H*n)/2) / (2*M_PI*n) * i; // Save these values so the engine can adjust itself to them: p->setAttribute("automagic.n_P", doubleToString(n)); p->setAttribute("automagic.M_P", doubleToString(M)); } omega_fold = p->attributeAsDouble("n_fold", -1)*2*M_PI; }
/** \brief Initialize the mixer from a config file. * * The mixer object will be initialized from the given config file. * This file may contain more than one branch with interface settings, * so the name of the child has to be specified. */ int T_TX_Mixer::init(SimpleXMLTransfer* cfg, std::string child) { #if DEBUG_TX_INTERFACE > 0 printf("T_TX_Mixer::init(cfg, child)\n"); printf(" <-- %s\n", child.c_str()); #endif SimpleXMLTransfer* mixer; SimpleXMLTransfer* item; SimpleXMLTransfer* inter; // store the child's name for writing back the settings child_in_cfg = child; printf("Loading mixer settings from %s:\n", child.c_str()); try { inter = cfg->getChild(child, true); mixer = inter->getChild("mixer", true); enabled = mixer->attributeAsInt("enabled", 1); dr_enabled = mixer->attributeAsInt("dr_enabled", 0); for (int i = T_AxisMapper::AILERON; i <= T_AxisMapper::PITCH; i++) { item = mixer->getChild(Global::inputDev->AxisStringsXML[i], true); trim_val[i] = item->getDouble("trim", 0.0); nrate_val[i] = item->getDouble("nrate", 1.0); srate_val[i] = item->getDouble("srate", 1.0); exp_val[i] = item->getDouble("exp", 0.0); mtravel_val[i] = item->getDouble("mtravel", -0.5); ptravel_val[i] = item->getDouble("ptravel", 0.5); } for (int i = 0; i < T_TX_Mixer::NUM_MIXERS; i++) { item = mixer->getChild(Global::inputDev->MixerStringsXML[i], true); mixer_enabled[i] = item->attributeAsInt("enabled", 0); mixer_src[i] = item->getDouble("src", T_AxisMapper::NOTHING); mixer_dst[i] = item->getDouble("dst", T_AxisMapper::NOTHING); mixer_val[i] = item->getDouble("val", 0.0); } } catch (XMLException e) { errMsg = e.what(); return 1; } return 0; }
void CRRCAirplaneLaRCSim::initSound(SimpleXMLTransfer* xml) { SimpleXMLTransfer* cfg = XMLModelFile::getConfig(xml); SimpleXMLTransfer* sndcfg = cfg->getChild("sound", true); int children = sndcfg->getChildCount(); int units = sndcfg->getInt("units", 0); for (int i = 0; i < children; i++) { SimpleXMLTransfer *child = sndcfg->getChildAt(i); std::string name = child->getName(); if (name.compare("sample") == 0) { T_AirplaneSound *sample; // assemble relative path std::string soundfile; soundfile = child->attribute("filename"); // other sound attributes int sound_type = child->getInt("type", SOUND_TYPE_GLIDER); double dPitchFactor = child->getDouble("pitchfactor", 0.002); double dMaxVolume = child->getDouble("maxvolume", 1.0); if (dMaxVolume < 0.0) { dMaxVolume = 0.0; } else if (dMaxVolume > 1.0) { dMaxVolume = 1.0; } //~ if (cfg->indexOfChild("power") < 0) //~ max_thrust = 0; //~ else //~ max_thrust = 1; if (soundfile != "") { // Get full path (considering search paths). soundfile = FileSysTools::getDataPath("sounds/" + soundfile); } // File ok? Use default otherwise. if (!FileSysTools::fileExists(soundfile)) soundfile = FileSysTools::getDataPath("sounds/fan.wav"); std::cout << "soundfile: " << soundfile << "\n"; //~ std::cout << "max_thrust: " << max_thrust << "\n"; std::cout << "soundserver: " << Global::soundserver << "\n"; // Only make noise if a sound file is available if (soundfile != "" && Global::soundserver != (CRRCAudioServer*)0) { std::cout << "Using airplane sound " << soundfile << ", type " << sound_type << ", max vol " << dMaxVolume << std::endl; if (sound_type == SOUND_TYPE_GLIDER) { T_GliderSound *glidersound; float flMinRelV, flMaxRelV, flMaxDist; flMinRelV = (float)child->getDouble("v_min", 1.5); flMaxRelV = (float)child->getDouble("v_max", 4.0); flMaxDist = (float)child->getDouble("dist_max", 300); if (units == 1) { // convert from metric units to ft. flMaxDist *= M_TO_FT; } glidersound = new T_GliderSound(soundfile.c_str(), Global::soundserver->getAudioSpec()); glidersound->setMinRelVelocity(flMinRelV); glidersound->setMaxRelVelocity(flMaxRelV); glidersound->setMaxDistanceFeet(flMaxDist); sample = glidersound; } else { sample = new T_EngineSound(soundfile.c_str(), Global::soundserver->getAudioSpec()); } sample->setType(sound_type); sample->setPitchFactor(dPitchFactor); sample->setMaxVolume(dMaxVolume); sample->setChannel(Global::soundserver->playSample((T_SoundSample*)sample)); sound.push_back(sample); } } } }
/** * Create a CRRCControlSurfaceAnimation object * * Initialize the animation from an * <animation type="ControlSurface"> tag */ CRRCControlSurfaceAnimation::CRRCControlSurfaceAnimation(SimpleXMLTransfer *xml) : CRRCAnimation(new ssgTransform()), fallback_data(0.0f), eventAdapter(this, &CRRCControlSurfaceAnimation::axisValueCallback, Event::Input), aileron(0.0f), elevator(0.0f), rudder(0.0f), throttle(0.0f), spoiler(0.0f), flap(0.0f), retract(0.0f), pitch(0.0f) { bool failed = false; // evaluate <object> tag SimpleXMLTransfer *map = xml->getChild("object", true); symbolic_name = map->getString("name", "no_name_set"); max_angle = (float)(map->getDouble("max_angle", 0.0) * SG_RADIANS_TO_DEGREES); abs_max_angle = (float)fabs((double)max_angle); // find hinges and evaluate all <control> tags int num_controls = 0; int num_hinges = 0; for (int i = 0; i < xml->getChildCount(); i++) { SimpleXMLTransfer *child = xml->getChildAt(i); if (child->getName() == "hinge") { // found a <hinge> child sgVec3 pos; pos[SG_X] = (float)(-1 * child->getDouble("y", 0.0)); pos[SG_Y] = (float)(-1 * child->getDouble("x", 0.0)); pos[SG_Z] = (float)(-1 * child->getDouble("z", 0.0)); if (num_hinges == 0) { sgCopyVec3(hinge_1, pos); } else if (num_hinges == 1) { sgCopyVec3(hinge_2, pos); } num_hinges++; } else if (child->getName() == "control") { // found a <control> child // The "*2" factor for each gain value scales the control input // values from -0.5...+0.5 to -1.0...+1.0. This saves one // float multiplication per mapping in the runtime update() routine. std::string mapping = child->getString("mapping", "NOTHING"); float gain = (float)child->getDouble("gain", 1.0); if (mapping == "ELEVATOR") { datasource.push_back(&elevator); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "AILERON") { datasource.push_back(&aileron); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "THROTTLE") { datasource.push_back(&throttle); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "RUDDER") { datasource.push_back(&rudder); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "FLAP") { datasource.push_back(&flap); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "SPOILER") { datasource.push_back(&spoiler); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "RETRACT") { datasource.push_back(&retract); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "PITCH") { datasource.push_back(&pitch); source_gain.push_back(gain * 2); num_controls++; } else { std::cerr << "ControlSurfaceAnimation: ignoring <control> tag without mapping." << std::endl; } } } if (num_controls < 1) { std::cerr << "ControlSurfaceAnimation: found animation without proper <control> tag. Animation disabled." << std::endl; failed = true; } if (num_hinges < 2) { std::cerr << "ControlSurfaceAnimation: Must specify exactly two hinges!" << std::endl; failed = true; } else { if (num_hinges > 2) { std::cerr << "ControlSurfaceAnimation: Must specify exactly two hinges!" << std::endl; std::cerr << "ControlSurfaceAnimation: Ignoring excessive hinge tag(s)." << std::endl; } sgSubVec3(axis, hinge_2, hinge_1); if (sgLengthVec3(axis) < 0.001) { std::cerr << "ControlSurfaceAnimation: Insufficient spacing between hinges!" << std::endl; failed = true; } } if (failed) { std::cerr << "ControlSurfaceAnimation: Animation setup failed." << std::endl; // set to some non-critical defaults datasource.resize(1); datasource[0] = &fallback_data; source_gain.resize(1); source_gain[0] = 1.0; sgSetVec3(hinge_1, 0.0f, 0.0f, 0.0f); sgSetVec3(hinge_2, 1.0f, 0.0f, 0.0f); sgSubVec3(axis, hinge_2, hinge_1); } sgMakeIdentMat4(move_to_origin); move_to_origin[3][0] = -hinge_1[0]; move_to_origin[3][1] = -hinge_1[1]; move_to_origin[3][2] = -hinge_1[2]; sgMakeTransMat4(move_back, hinge_1); realInit(); }
void CRRC_AirplaneSim_MCopter01::LoadFromXML(SimpleXMLTransfer* xml, int nVerbosity) { if (xml->getString("type").compare("mcopter01") != 0 || xml->getInt("version") != 1) { throw XMLException("file is not for mcopter01"); } SimpleXMLTransfer* i; SimpleXMLTransfer* cfg = XMLModelFile::getConfig(xml); { double to_slug; double to_slug_ft_ft; i = cfg->getChild("mass_inertia"); switch (i->getInt("units")) { case 0: to_slug = 1; to_slug_ft_ft = 1; break; case 1: to_slug = KG_TO_SLUG; to_slug_ft_ft = KG_M_M_TO_SLUG_FT_FT; break; default: { throw std::runtime_error("Unknown units in mass_inertia"); } break; } Mass = i->getDouble("Mass") * to_slug; I_xx = i->getDouble("I_xx") * to_slug_ft_ft; I_yy = i->getDouble("I_yy") * to_slug_ft_ft; I_zz = i->getDouble("I_zz") * to_slug_ft_ft; I_xz = i->getDouble("I_xz") * to_slug_ft_ft; } { speed_damp = cfg->getDouble("aero.speed.damp"); roll_damp1 = cfg->getDouble("aero.roll.damp1", 0); yaw_damp1 = cfg->getDouble("aero.yaw.damp1", 0); roll_damp2 = cfg->getDouble("aero.roll.damp2", 0); yaw_damp2 = cfg->getDouble("aero.yaw.damp2", 0); yaw_dist = cfg->getDouble("aero.yaw.dist", 0); roll_dist = cfg->getDouble("aero.roll.dist", 0); pitch_dist = cfg->getDouble("aero.pitch.dist", roll_dist); // The ground effect parameters should be quite independent of the helicopter // parameters...shouldn't they? However, they can be adjusted. dGEDistMul = xml->getDouble("GroundEffect.dist.mul", 1.5); { double tau = xml->getDouble("Disturbance.tau_filter", 0.2); dist_t_init = xml->getDouble("Disturbance.time", 0.2); filt_rnd_yaw.SetTau(tau); filt_rnd_roll.SetTau(tau); filt_rnd_pitch.SetTau(tau); } } wheels.init(xml, 0); dRotorRadius = wheels.getWingspan()*0.5; dRotorZ = wheels.getZHigh(); wheels.init(xml, 0); dRotorRadius = wheels.getWingspan()*0.5; dRotorZ = wheels.getZHigh(); props.clear(); i = cfg->getChild("aero.props"); for (int n=0; n<i->getChildCount(); n++) props.push_back(Propdata(i->getChildAt(n))); if (power.size() == 0) { for (unsigned int n=0; n<props.size(); n++) power.push_back(new Power::Power(cfg, nVerbosity)); dURef = 0.7 * cfg->getDouble("power.battery.U_0"); } else { for (unsigned int n=0; n<power.size(); n++) power[n]->ReloadParams(cfg, nVerbosity); } controllers.clear(); Controller::LoadList(cfg->getChild("controllers"), controllers); }
/** * Create a HardPointRotation * * \param xml <animation> part of the model file that contains the * description of the animation */ HardPointRotation::HardPointRotation(SimpleXMLTransfer *xml, TSimInputs const& in) { bool failed = false; // evaluate <object> tag SimpleXMLTransfer *map = xml->getChild("object", true); symbolic_name = map->getString("name", "no_name_set"); max_angle_rad = (float)map->getDouble("max_angle", 0.0); abs_max_angle_rad = (float)fabs((double)max_angle_rad); // find hinges and evaluate all <control> tags int num_controls = 0; int num_hinges = 0; for (int i = 0; i < xml->getChildCount(); i++) { SimpleXMLTransfer *child = xml->getChildAt(i); if (child->getName() == "hinge") { // found a <hinge> child CRRCMath::Vector3 pos; pos.r[0] = (float)(child->getDouble("x", 0.0)); pos.r[1] = (float)(child->getDouble("y", 0.0)); pos.r[2] = (float)(child->getDouble("z", 0.0)); if (num_hinges < 2) { hinge[num_hinges] = pos; } num_hinges++; } else if (child->getName() == "control") { // found a <control> child // The "*2" factor for each gain value scales the control input // values from -0.5...+0.5 to -1.0...+1.0. This saves one // float multiplication per mapping in the runtime update() routine. // NB: unsigned control (throttle, spoiler, retract) are not scaled, // since control input is already in range 0.0...+1.0 std::string mapping = child->getString("mapping", "NOTHING"); float gain = (float)child->getDouble("gain", 1.0); std::cout << " mapped to " << mapping << " with gain " << gain; std::cout << " and max_angle_rad " << max_angle_rad << std::endl; if (mapping == "ELEVATOR") { datasource.push_back(&in.elevator); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "AILERON") { datasource.push_back(&in.aileron); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "THROTTLE") { datasource.push_back(&in.throttle); source_gain.push_back(gain); num_controls++; } else if (mapping == "RUDDER") { datasource.push_back(&in.rudder); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "FLAP") { datasource.push_back(&in.flap); source_gain.push_back(gain * 2); num_controls++; } else if (mapping == "SPOILER") { datasource.push_back(&in.spoiler); source_gain.push_back(gain); num_controls++; } else if (mapping == "RETRACT") { datasource.push_back(&in.retract); source_gain.push_back(gain); num_controls++; } else if (mapping == "PITCH") { datasource.push_back(&in.pitch); source_gain.push_back(gain * 2); num_controls++; } else { fprintf(stderr, "HardPointRotation: ignoring <control> tag without mapping.\n"); } } } if (num_controls < 1) { fprintf(stderr, "HardPointRotation: found animation without proper <control> tag. Animation disabled.\n"); failed = true; } if (num_hinges < 2) { fprintf(stderr, "HardPointRotation: Must specify exactly two hinges!\n"); failed = true; } else { if (num_hinges > 2) { fprintf(stderr, "HardPointRotation: Must specify exactly two hinges!\n"); fprintf(stderr, "HardPointRotation: Ignoring excessive hinge tag(s).\n"); } axis = hinge[1] - hinge[0]; if (axis.length() < 0.001) { fprintf(stderr, "HardPointRotation: Insufficient spacing between hinges!\n"); failed = true; } } if (failed) { fprintf(stderr, "HardPointRotation: Animation setup failed.\n"); // set to some non-critical defaults datasource.resize(1); datasource[0] = &fallback_data; source_gain.resize(1); source_gain[0] = 1.0; hinge[0] = CRRCMath::Vector3(0.0, 0.0, 0.0); hinge[1] = CRRCMath::Vector3(1.0, 0.0, 0.0); axis = hinge[1] - hinge[0]; } else { std::cerr << "HardPointRotation: set up animated hardpoint "; std::cerr << symbolic_name << std::endl; } move_orig.makeTranslation(hinge[0] * -1); move_back.makeTranslation(hinge[0]); //~ realInit(); }