// Wrapper for the above function that assumes that the rotation rate is vrot. // Calling the function directly allows more control but will probably be used less bool SetAttitude(double TargetAttitude, double CurrentAttitude, AXIS Axis, DEADBAND DeadbandLow) { VESSEL *Vessel; // Spacecraft interface VESSELSTATUS Status; // Spacecraft status Vessel = oapiGetFocusInterface(); Vessel->GetStatus(Status); return SetAttitude(TargetAttitude, CurrentAttitude, Status.vrot.data[Axis], Axis, DeadbandLow); }
void RMANAGER::CreateResourceAndStreams(VOBJ * vbj) { if (!oapiIsVessel(vbj->hook)) return; VESSEL * vessel = oapiGetVesselInterface(vbj->hook); PROPELLANT_HANDLE hpr = vessel->CreatePropellantResource(1); vbj->th = vessel->CreateThruster(_V(0,0,0),vbj->dir,1e0,hpr,500000e50); for (int i = 0; i < vbj->streams.size(); i++) { vessel->AddExhaustStream(vbj->th,vbj->streams[i]->pos,vbj->streams[i]->stream); } }
// Basically NAVMODE_KILLROT in a single dimension. Returns true when the rate has been nulled // out, otherwise it returns false. bool NullRate(AXIS Axis) { VESSEL *Vessel = oapiGetFocusInterface(); VESSELSTATUS Status; Vessel->GetStatus(Status); double RateDeadband = Radians(0.001), Thrust, Level, Rate = Status.vrot.data[Axis], Mass = Vessel->GetMass(), MaxThrust = Vessel->GetMaxThrust(ENGINE_ATTITUDE), Size = Vessel->GetSize(); VECTOR3 PMI; Vessel->GetPMI(PMI); if (fabs(Rate) < RATE_NULL) { Vessel->SetAttitudeRotLevel(Axis, 0.0); return true; } Thrust = -(Mass * PMI.data[Axis] * Rate) / (Size); Level = min((Thrust/MaxThrust), 1); Vessel->SetAttitudeRotLevel(Axis, Level); return false; }
// Callback from Target Selection Input Box bool RVO_DialogFunc::clbkTGT(void *id, char *str, void *usrdata) { OBJHANDLE hTgtV; VESSEL* tv; bool DockFree = false; RVO_LCore* LC = (RVO_LCore*) usrdata; RVO_GCore* GC = LC->GC; RVO_VCore* VC = LC->VC; if (strlen(str) == 0) return true; // Empty string - assume canceled dialog hTgtV = oapiGetVesselByName(str); if (!hTgtV) return true; // String was not a vessel tv = oapiGetVesselInterface(hTgtV); if (!tv) return true; // Couldn't find the vessel interface if (tv == LC->v) return true; // We can't dock with ourself (that would be rude!) // Target accepted strcpy_s(VC->TargetText, 50, tv->GetName()); VC->hTgtV = hTgtV; VC->tv = tv; VC->MaxPorts = VC->tv->DockCount(); for (int i=0; i<VC->MaxPorts; i++) { VC->hDock = VC->tv->GetDockHandle(i); if (!VC->hDock) continue; // Couldn't find the dock?? if (VC->tv->DockingStatus(i)==0) { // dock free DockFree = true; VC->tv->GetDockParams(VC->hDock, VC->rtvdPos, VC->rtvdDir, VC->rtvdRot); VC->CreatePortRotMatrix(VC->rtvPortOri,VC->rtvdDir,VC->rtvdRot); VC->PortNumber = i; break; } } if (!DockFree) { LC->showMessage = true; sprintf_s(LC->Message,"No free ports on %s!", VC->TargetText); VC->PortNumber = -1; VC->hDock = 0; } return true; }
bool RMANAGER::isAttended(VESSEL * v) { if (!v) return false; VESSEL * vessel; for (int i = 0; i < atList.size(); i++) { if (!atList[i]) continue; if (!oapiIsVessel(atList[i]->hook)) continue; vessel = oapiGetVesselInterface(atList[i]->hook); if (v->GetHandle() == vessel->GetHandle()) return true; } return false; }
int VOBJ::nextlock() { VESSEL * v = oapiGetVesselInterface(hook); UINT count = v->DockCount(); if (dock+1 >= count) dock=0; else dock++; VECTOR3 pos, rot, dir; DOCKHANDLE dHandle = v->GetDockHandle(dock); v->GetDockParams(dHandle, pos, dir, rot); //crew.DefineAirLockShape(TRUE,-5,5,-5,5,-5,5); crew.DefineAirLockShape(TRUE, min(pos.x, -pos.x)-5, max(pos.x, -pos.x)+5, min(pos.y, -pos.y)-5, max(pos.y, -pos.y)+5, min(pos.z, -pos.z)-5, max(pos.z, -pos.z)+5); crew.SetMembersPosRotOnEVA(pos, rot); crew.SetActiveDockForTransfer(dock); return dock; }
DLLCLBK void opcPreStep(double simt, double simdt, double mjd) { OrbiterPluginMessage * opm; // holds our msg and msg data char * msg; int len; // nextMessage() returns MESSAGE_OK if a message is succesfully polled while(OICOM::nextMessage(pid, &opm)==MESSAGE_OK) { msg=opm->strMsg; len=strlen(msg); // we don't care about any text only events for this module if ( opm->data == 0 ) { // remove this message from the message stack OICOM::removeLastMessage(pid); continue; } // perma-link! hook up this module's state variables with any module providing input // this is powerful if ( !_strnicmp(msg, "link_state", len) ) active=(bool*)opm->data; else if (!_strnicmp(msg, "link_setpoint", len) ) setpoint=(double*)opm->data; OICOM::removeLastMessage(pid); // this is important otherwise we'll end up with an infinite loop! // I am thinking about automating it.. calling this at nextMessage } // if not linked to any module for input, no need to proceed if ( active == 0 || setpoint == 0 ) return; if ( !*active ) return; // crappy "autopilot" code follows, IGNORE IT xD VESSEL * vessel = oapiGetFocusInterface(); DWORD inx = vessel->GetGroupThrusterCount(THGROUP_MAIN); VECTOR3 dv; vessel->GetDragVector(dv); THRUSTER_HANDLE th; double e = *setpoint-vessel->GetAirspeed(); double lvl = 0; for (DWORD i = 0; i < inx; i++) { th = vessel->GetGroupThruster(THGROUP_MAIN, i); lvl = (-dv.z+e*vessel->GetMass()*70)/vessel->GetThrusterMax0(th); if (lvl<0) lvl=0; else if (lvl>1) lvl=1; vessel->SetThrusterLevel(th, lvl); } }
void RMANAGER::TimeStep() { VESSEL * v = NULL; OBJHANDLE hVes = NULL; char ini[255]; for (int i = 0; i < oapiGetVesselCount(); i++) { hVes = oapiGetVesselByIndex(i); if (!oapiIsVessel(hVes)) continue; v = oapiGetVesselInterface(hVes); if (isAttended(v)) continue; if (!hasConfig(v)) continue; sprintf(ini,"./Config/orbReentryStream/%s.ini",INI(v)); atList.push_back(ReadAndAssign(ini,v)); } VOBJ * vbj = NULL; for (int i = 0; i < atList.size(); i++) { if (!atList[i]) continue; if (!oapiIsVessel(atList[i]->hook)) continue; vbj = atList[i]; v = oapiGetVesselInterface(vbj->hook); hVes = v->GetHandle(); if (calcFlux(v) > vbj->flux) { if (!vbj->th) CreateResourceAndStreams(vbj); v->SetThrusterLevel(vbj->th,1); }else if (vbj->th) v->SetThrusterLevel(vbj->th,0); } }
int VOBJ::TimeStep(void) { int r = crew.ProcessUniversalMMu(); char cbuf[255]; switch(r) { case UMMU_RETURNED_TO_OUR_SHIP: { sprintf(cbuf,"%s %s aged %d entered the ship",crew.GetCrewMiscIdByName(crew.GetLastEnteredCrewName()),crew.GetLastEnteredCrewName(),crew.GetCrewAgeByName(crew.GetLastEnteredCrewName())); hudprint.insert(cbuf); break; } case UMMU_TRANSFERED_TO_OUR_SHIP: { sprintf(cbuf,"%s %s aged %d entered to ship",crew.GetCrewMiscIdByName(crew.GetLastEnteredCrewName()),crew.GetLastEnteredCrewName(),crew.GetCrewAgeByName(crew.GetLastEnteredCrewName())); hudprint.insert(cbuf); break; } } if (!koc || !crew.GetCrewTotalNumber()) return r; VESSEL * v = oapiGetVesselInterface(hook); VECTOR3 horz; v->GetHorizonAirspeedVector(horz); if (horz.y < khv && v->GroundContact()) { for (int i = 0; i < crew.GetCrewTotalNumber(); i++) { crew.SetCrewMemberPulseByName(crew.GetCrewNameBySlotNumber(i),0); } while(crew.GetCrewTotalNumber()) crew.EjectCrewMember(crew.GetCrewNameBySlotNumber(0)); sprintf(cbuf,"crash at %.2f everybody dead",horz.y); hudprint.insert(cbuf); } return r; }
DLLCLBK void opcPreStep(double simt, double simdt, double mjd) { if (Init==FALSE) { if (ConfigLoaded==FALSE) g_UFA.init(); LoadOptions(); Init=TRUE; srand(time(NULL)); return; } g_UFA.TimeStep(); HUD.TimeStep(); VOBJ * v = g_UFA.GetFocus(); if (v==NULL) return; char cbuf[255]; if (Ejection==TRUE) { if (lEjectionTime>oapiGetSimTime()) return; lEjectionTime=oapiGetSimTime()+1; int crewcount = v->crew.GetCrewTotalNumber(); if (!crewcount){ Ejection=FALSE; return; } double eVel = 0; VESSEL * vessel = NULL; VESSEL * focus = oapiGetFocusInterface(); VESSELSTATUS vs; OBJHANDLE hVes=NULL; if (VESSEL(v->hook).GetAtmPressure() < 2.5) { eVel=5; v->crew.SetEjectPosRotRelSpeed(_V(0, 0, 0),_V(0,1,0), _V(eVel,eVel, 0)); v->crew.EjectCrewMember(v->crew.GetCrewNameBySlotNumber(0)); }else { v->crew.SetEjectPosRotRelSpeed(_V(0, 0, 0),_V(0,1,0), _V(0,0, 0)); v->crew.EjectCrewMember(v->crew.GetCrewNameBySlotNumber(0)); } hVes = v->crew.GetObjHandleOfLastEVACrew(); if (!oapiIsVessel(hVes)) return; vessel = oapiGetVesselInterface(hVes); sprintf(cbuf,"%s-pack",vessel->GetName()); vessel->GetStatus(vs); oapiCreateVessel(cbuf,"Ummuturbopack",vs); } double yofs = Y_OFS_START; for (int i = 0; i < v->hudprint.m.size(); i++) { sprintf(cbuf,"%s",v->hudprint.m[i].c_str()); HUD.Add(0.0001,v->hook,HUD._D(X_OFS_START,1,yofs,1,Size,COLOR,cbuf)); yofs+=LINE_SPACE; } HUD.TimeStep(); }
void DockingProbe::TimeStep(double simt, double simdt) { if (!FirstTimeStepDone) { DoFirstTimeStep(); FirstTimeStepDone = true; return; } if (UndockNextTimestep) { UpdatePort(Dockparam[1] * 0.5, simdt); OurVessel->Undock(ourPort); UndockNextTimestep = false; } if (ExtendingRetracting > 0) { if (Status >= DOCKINGPROBE_STATUS_EXTENDED) { Status = DOCKINGPROBE_STATUS_EXTENDED; ExtendingRetracting = 0; Dockproc = DOCKINGPROBE_PROC_UNDOCKED; OurVessel->Undocking(ourPort); OurVessel->SetDockingProbeMesh(); } else { Status += 0.33 * simdt; } } else if (ExtendingRetracting < 0) { if (Status <= DOCKINGPROBE_STATUS_RETRACTED) { Status = DOCKINGPROBE_STATUS_RETRACTED; ExtendingRetracting = 0; OurVessel->HaveHardDocked(ourPort); OurVessel->SetDockingProbeMesh(); } else { Status -= 0.33 * simdt; } } if (Dockproc == DOCKINGPROBE_PROC_SOFTDOCKED) { UpdatePort(Dockparam[1] * 0.5, simdt); Dockproc = DOCKINGPROBE_PROC_HARDDOCKED; } else if (Dockproc == DOCKINGPROBE_PROC_HARDDOCKED) { if (Status > DOCKINGPROBE_STATUS_RETRACTED) { UpdatePort(Dockparam[1] * 0.5 * Status / 0.9, simdt); } else { UpdatePort(_V(0,0,0), simdt); Dockproc = DOCKINGPROBE_PROC_UNDOCKED; } } // sprintf(oapiDebugString(), "Docked %d Status %.3f Dockproc %d ExtendingRetracting %d", (Docked ? 1 : 0), Status, Dockproc, ExtendingRetracting); // Switching logic if (OurVessel->DockingProbeExtdRelSwitch.IsUp() && IsPowered()) { Extend(); } else if (OurVessel->DockingProbeExtdRelSwitch.IsDown()) { if ((!OurVessel->DockingProbeRetractPrimSwitch.IsCenter() && OurVessel->DockProbeMnACircuitBraker.IsPowered() && OurVessel->PyroBusA.Voltage() > SP_MIN_DCVOLTAGE) || (!OurVessel->DockingProbeRetractSecSwitch.IsCenter() && OurVessel->DockProbeMnBCircuitBraker.IsPowered() && OurVessel->PyroBusB.Voltage() > SP_MIN_DCVOLTAGE)) { int ActiveCharges = 0; if (OurVessel->DockingProbeRetractPrimSwitch.IsUp()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_PRIM1; if (OurVessel->DockingProbeRetractPrimSwitch.IsDown()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_PRIM2; if (OurVessel->DockingProbeRetractSecSwitch.IsUp()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_SEC1; if (OurVessel->DockingProbeRetractSecSwitch.IsDown()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_SEC2; if ((ActiveCharges & RetractChargesUsed)!= ActiveCharges) Retract(); RetractChargesUsed = RetractChargesUsed | ActiveCharges; // sprintf(oapiDebugString(), "Charge Used: P1%d P2%d S1%d S2%d", RetractChargesUsed & DOCKINGPROBE_CHARGE_PRIM1 , RetractChargesUsed & DOCKINGPROBE_CHARGE_PRIM2 , RetractChargesUsed & DOCKINGPROBE_CHARGE_SEC1 , RetractChargesUsed & DOCKINGPROBE_CHARGE_SEC2); } } /// /// Begin Advanced Docking Code /// if (DockingMethod > ADVANCED){ // Code that follows is largely lifted from Atlantis... // Goal is to handle close proximity docking between a probe and drogue VECTOR3 gdrgPos, gdrgDir, gprbPos, gprbDir, gvslPos, rvel, pos, dir, rot; OurVessel->Local2Global (Dockparam[0],gprbPos); //converts probe location to global OurVessel->GlobalRot (Dockparam[1],gprbDir); //rotates probe direction to global // Search the complete vessel list for a grappling candidate. // Not very scalable ... for (DWORD i = 0; i < oapiGetVesselCount(); i++) { OBJHANDLE hV = oapiGetVesselByIndex (i); if (hV == OurVessel->GetHandle()) continue; // we don't want to grapple ourselves ... oapiGetGlobalPos (hV, &gvslPos); if (dist (gvslPos, gprbPos) < oapiGetSize (hV)) { // in range VESSEL *v = oapiGetVesselInterface (hV); DWORD nAttach = v->AttachmentCount (true); for (DWORD j = 0; j < nAttach; j++) { // now scan all attachment points of the candidate ATTACHMENTHANDLE hAtt = v->GetAttachmentHandle (true, j); const char *id = v->GetAttachmentId (hAtt); if (strncmp (id, "PADROGUE", 8)) continue; // attachment point not compatible v->GetAttachmentParams (hAtt, pos, dir, rot); v->Local2Global (pos, gdrgPos); // converts found drogue position to global v->GlobalRot (dir, gdrgDir); // rotates found drogue direction to global if (dist (gdrgPos, gprbPos) < COLLISION_DETECT_RANGE && DockingMethod == ADVANCEDPHYSICS) { // found one less than a meter away! // Detect if collision has happend, if so, t will return intersection point along the probe line X(t) = gprbPos + t * gprbDir double t = CollisionDetection(gprbPos, gprbDir, gdrgPos, gdrgDir); // Calculate time of penetration according to current velocity OurVessel->GetRelativeVel(hV, rvel); // Determine resultant force //APPLY rforce to DockingProbe Vessel, and APPLY -rforce to Drogue Vessel return; } if (dist(gdrgPos, gprbPos) < CAPTURE_DETECT_RANGE && DockingMethod > ADVANCED) { // If we're within capture range, set docking port to attachment so docking can take place // Originally, I would have used the Attachment features to soft dock and move the LM during retract // but Artlav's docking method does this better and uses the docking port itself. // Attachment is being used as a placeholder for the docking port and to identify its orientation. OurVessel->GetAttachmentParams(hattPROBE, pos, dir, rot); DOCKHANDLE dock = OurVessel->GetDockHandle(ourPort); OurVessel->SetDockParams(dock, pos, dir, rot); } }//for nAttach }//if inRange }//for nVessel } }
void SwitchPanel::updateDisplay() { // 0x00 off // 0x07 green // 0x38 red static unsigned char buf[2]; if (!handle) { return; } buf[0]=0x00; buf[1]=0x00; VESSEL *vessel = oapiGetFocusInterface(); // Get current vessel if (vessel!=NULL) // check if pointer is valid { if (XRVesselCtrl::IsXRVesselCtrl(vessel)) { // is XR vessel XRVesselCtrl * xrVessel = static_cast<XRVesselCtrl *>(vessel); if (xrVessel->GetCtrlAPIVersion() >= THIS_XRVESSELCTRL_API_VERSION) { XRDoorState doorState = xrVessel->GetDoorState(XRD_Gear,NULL); switch (doorState) { case XRDS_Open: // green buf[1]=0x07; break; case XRDS_Opening: case XRDS_Closing: // red buf[1]=0x38; break; default: // off buf[1]=0x00; break; } } } else if(strcmp(vessel->GetClassNameA(),"DeltaGlider")==0 || strcmp(vessel->GetClassNameA(),"DG-S")==0) { DeltaGlider * dgVessel = static_cast<DeltaGlider *>(vessel); switch (dgVessel->gear_status) { case DeltaGlider::DOOR_OPEN: // green buf[1]=0x07; break; case DeltaGlider::DOOR_OPENING: case DeltaGlider::DOOR_CLOSING: // red buf[1]=0x38; break; default: // off buf[1]=0x00; break; } } } int res = hid_send_feature_report(handle, buf, 2); }
void VOBJ::TimeStep(int SoundID) { if (!oapiIsVessel(hook)){ sprintf(msg, "Unknown Error"); return; } if (!oapiGetVesselByIndex(iTarget) && mode == VTOV){ mode=MAGIC; iTargetSource=0; iTarget=0; } if (VESSEL(hook).GetPropellantCount() < 1) { sprintf(msg, "No fuel sources available"); return; } if (status==IDLE) { sprintf(msg, "IDLE: Waiting for action"); return; } PlayMFDWave(SoundID, 0); if (mode==VTOV) { VESSEL * vHook = oapiGetVesselInterface(hook); VESSEL * vTarget = oapiGetVesselInterface(oapiGetVesselByIndex(iTarget)); if (vTarget->GetPropellantCount() < 1) { sprintf(msg, "Target has no fuel sources"); return; } PROPELLANT_HANDLE hpTarget = vTarget->GetPropellantHandleByIndex(iTargetSource); PROPELLANT_HANDLE hpHook = vHook->GetPropellantHandleByIndex(iSelectedSource); if (!hpHook||!hpTarget){ sprintf(msg, "Unknown Error!"); return; } double maxMasstarget = vTarget->GetPropellantMaxMass(hpTarget); double massTarget = vTarget->GetPropellantMass(hpTarget); double maxMasshook = vHook->GetPropellantMaxMass(hpHook); double massHook = vHook->GetPropellantMass(hpHook); if (massTarget<CUT_OFF) { sprintf(msg, "No fuel left to transfer!"); return; } if (fabs(maxMasshook-massHook) < CUT_OFF) { sprintf(msg, "Tank full"); return; } if (hook == oapiGetVesselByIndex(iTarget)) { if (iSelectedSource == iTargetSource) { sprintf(msg, "Cannot transfer fuel to the same source"); return; } } double dFuelTrans = 0; if (massTarget-dTransferRate >= 0 && massHook+dTransferRate <= maxMasshook) { dFuelTrans = dTransferRate; }else { if (maxMasshook-massHook < massTarget) { dFuelTrans = maxMasshook-massHook; }else if (maxMasshook-massHook > massTarget) { dFuelTrans = massTarget; }else dFuelTrans = massTarget; } dFuelTrans*=oapiGetSimStep(); vTarget->SetPropellantMass(hpTarget, massTarget-dFuelTrans); vHook->SetPropellantMass(hpHook, massHook+dFuelTrans); sprintf(msg, "Transfering %.2f%%", ((massHook+dFuelTrans)/maxMasshook)*100, vTarget->GetName(), ((massTarget-dFuelTrans)/maxMasstarget)*100); } else if (mode == MAGIC) { VESSEL * v = oapiGetVesselInterface(hook); PROPELLANT_HANDLE hpr = v->GetPropellantHandleByIndex(iSelectedSource); if (!hpr) { sprintf(msg, "Unknown error!"); return; } double mass = v->GetPropellantMass(hpr); double maxmass = v->GetPropellantMaxMass(hpr); if (fabs(maxmass-mass) < CUT_OFF){ sprintf(msg, "Tank full"); return; } double dFuelTrans = 0; if (mass+dTransferRate > maxmass) dFuelTrans = maxmass-mass; else dFuelTrans = dTransferRate; dFuelTrans*=oapiGetSimStep(); v->SetPropellantMass(hpr, dFuelTrans+mass); sprintf(msg, "Transfering %.2f%%", ((mass+dFuelTrans)/maxmass)*100); }else if (mode == DUMPING) { VESSEL * v = oapiGetVesselInterface(hook); PROPELLANT_HANDLE hpr = v->GetPropellantHandleByIndex(iSelectedSource); if (!hpr) { sprintf(msg, "Unknown error!"); return; } double mass = v->GetPropellantMass(hpr); double maxmass = v->GetPropellantMaxMass(hpr); if (mass <CUT_OFF) { sprintf(msg, "No more fuel left"); return; } double dFuelTrans=0; if (mass-dTransferRate < 0) dFuelTrans = mass; else dFuelTrans = dTransferRate; dFuelTrans*=oapiGetSimStep(); v->SetPropellantMass(hpr, mass-dFuelTrans); sprintf(msg, "Dumping %.2f%%", ((mass-dFuelTrans)/maxmass)*100); } }
void EVA::clbkPreStep (double simt, double SimDT, double mjd) { char EVAName[256]=""; char CSMName[256]=""; char MSName[256]=""; strcpy(EVAName,GetName()); double VessCount; int i=0; VessCount=oapiGetVesselCount(); hMaster=oapiGetVesselByIndex(i); while (i<VessCount)i++;{ oapiGetObjectName(hMaster,MSName,256); strcpy(CSMName,MSName);strcat(CSMName,"-EVA"); if (strcmp(CSMName,EVAName)==0) { i=int(VessCount); } } sprintf(oapiDebugString(), "EVA Cable Attached to %s", MSName); VESSELSTATUS csmV; VESSELSTATUS evaV; VESSEL *csmvessel; VECTOR3 rdist = {0,0,0}; VECTOR3 posr = {0,0,0}; VECTOR3 rvel = {0,0,0}; VECTOR3 RelRot = {0,0,0}; double dist = 0.0; double Vel = 0.0; if (hMaster) { csmvessel = oapiGetVesselInterface(hMaster); oapiGetRelativePos (GetHandle() ,hMaster, &posr); oapiGetRelativeVel (GetHandle() ,hMaster , &rvel); GetStatus(evaV); csmvessel->GetStatus(csmV); GlobalRot (posr, RelRot); dist = sqrt(posr.x * posr.x + posr.y * posr.y + posr.z * posr.z); Vel = sqrt(rvel.x * rvel.x + rvel.y * rvel.y + rvel.z * rvel.z); if (dist >= 25) { rvel = evaV.rvel-csmV.rvel; rvel.x = -rvel.x; rvel.y = -rvel.y; rvel.z = -rvel.z; GetStatus(evaV); csmvessel->GetStatus(csmV); evaV.rvel = csmV.rvel + rvel; DefSetState(&evaV); } if (GoDock1){ sprintf(oapiDebugString(), "EVA Back CSM Mode Relative Distance M/s %f", dist); if (dist <= 0.55 && dist>=0.50 ){ GoDock1 =false; oapiSetFocusObject(hMaster); oapiDeleteVessel(GetHandle()); } } } }
// Generates rotational commands in order to achieve a target attitude in a given axis. // Note that the user is responsible for providing an accurate current attitude information. // This allows for greater flexability but also can be a source of problems if you pass // incorrect data to the function. For example, if you invert signs, then the spacecraft will // fly out of control because as it rotates in the correct direction, the DeltaAngle will // increase! Please be careful :-) The function returns true when the desired attitude // has been reached (within the given deadband) and the velocity has been nulled; otherwise, // it returns false. bool SetAttitude(double TargetAttitude, double CurrentAttitude, double RotRate, AXIS Axis, DEADBAND DeadbandLow) { VESSEL *Vessel; // Spacecraft interface double Rate; // Depends on magnitude of DeltaAngle double RateDeadband; // Depends on the magnitude of Rate double Thrust; // Thrust required double Level; // Required thrust level [0 - 1] VECTOR3 PMI; // Prinicple moment of inertia double MaxThrust; // Maximum thrust delivered by the engines double Size; // Spacecraft radius double Mass; // Spacecraft mass double DeltaRate; // The difference between the desired and the actual rate double DeltaAngle = TargetAttitude - CurrentAttitude; // Get State Vessel = oapiGetFocusInterface(); Vessel->GetPMI(PMI); MaxThrust = Vessel->GetMaxThrust(ENGINE_ATTITUDE); Mass = Vessel->GetMass(); Size = Vessel->GetSize(); // Let's take care of the good case first :-) if ((fabs(DeltaAngle) < DeadbandLow)) { //sprintf(oapiDebugString(), "NULL"); if (fabs(RotRate) < RATE_NULL) { Vessel->SetAttitudeRotLevel(Axis, 0); return true; } return (NullRate(Axis)); } // CCK // Now, we actually have to DO something! ;-) Well divide it up into two cases, once // for each direction. There's probably a better way, but not right now :-) //if (fabs(DeltaAngle) < DEADBAND_MID) { // Rate = RATE_LOW; // sprintf(oapiDebugString(), "LOW"); //} else if(fabs(DeltaAngle) < DEADBAND_HIGH) { // Rate = RATE_MID; // sprintf(oapiDebugString(), "MID"); //} else { // Rate = RATE_HIGH; // sprintf(oapiDebugString(), "HIGH"); //} if (fabs(DeltaAngle) < DEADBAND_LOW) { Rate = RATE_FINE; //sprintf(oapiDebugString(), "FINE"); } else if (fabs(DeltaAngle) < DEADBAND_MID) { Rate = RATE_LOW; //sprintf(oapiDebugString(), "LOW"); } else if (fabs(DeltaAngle) < DEADBAND_HIGH) { Rate = RATE_MID; //sprintf(oapiDebugString(), "MID"); } else if (fabs(DeltaAngle) < DEADBAND_MAX) { Rate = RATE_HIGH; //sprintf(oapiDebugString(), "HIGH"); } else { Rate = RATE_MAX; //sprintf(oapiDebugString(), "MAX"); } // CCK End RateDeadband = min(Rate / 2, Radians(0.01/*2*/)); if (DeltaAngle < 0 ) { Rate = -Rate; RateDeadband = -RateDeadband; } DeltaRate = Rate - RotRate; if (DeltaAngle > 0) { if (DeltaRate > RateDeadband) { Thrust = (Mass * PMI.data[Axis] * DeltaRate) / (Size); Level = min((Thrust/MaxThrust), 1); Vessel->SetAttitudeRotLevel(Axis, Level); } else if (DeltaRate < -RateDeadband) { Thrust = (Mass * PMI.data[Axis] * DeltaRate) / (Size); Level = max((Thrust/MaxThrust), -1); Vessel->SetAttitudeRotLevel(Axis, Level); } else { Vessel->SetAttitudeRotLevel(Axis, 0); } } else { if (DeltaRate < RateDeadband) { Thrust = (Mass * PMI.data[Axis] * DeltaRate) / (Size); Level = max((Thrust/MaxThrust), -1); Vessel->SetAttitudeRotLevel(Axis, Level); } else if (DeltaRate > -RateDeadband) { Thrust = (Mass * PMI.data[Axis] * DeltaRate) / (Size); Level = min((Thrust/MaxThrust), 1); Vessel->SetAttitudeRotLevel(Axis, Level); } else { Vessel->SetAttitudeRotLevel(Axis, 0); } } return false; }
const MATRIX3 &AttitudeReference::GetFrameRotMatrix () const { // Returns rotation matrix for rotation from reference frame to global frame if (!valid_axes) { VECTOR3 axis1, axis2, axis3; switch (mode) { case 0: // inertial (ecliptic) axis3 = _V(1,0,0); axis2 = _V(0,1,0); break; case 1: { // inertial (equator) MATRIX3 R; oapiGetPlanetObliquityMatrix (v->GetGravityRef(), &R); //axis3 = _V(R.m13, R.m23, R.m33); axis3 = _V(R.m11, R.m21, R.m31); axis2 = _V(R.m12, R.m22, R.m32); } break; case 2: { // orbital velocity / orbital momentum vector OBJHANDLE hRef = v->GetGravityRef(); v->GetRelativeVel (hRef, axis3); axis3 = unit (axis3); VECTOR3 vv, vm; v->GetRelativePos (hRef, vv); // local vertical vm = crossp (axis3,vv); // direction of orbital momentum axis2 = unit (crossp (vm,axis3)); } break; case 3: { // local horizon / local north (surface) OBJHANDLE hRef = v->GetSurfaceRef(); v->GetRelativePos (hRef, axis2); axis2 = unit (axis2); MATRIX3 prot; oapiGetRotationMatrix (hRef, &prot); VECTOR3 paxis = {prot.m12, prot.m22, prot.m32}; // planet rotation axis in global frame VECTOR3 yaxis = unit (crossp (paxis,axis2)); // direction of yaw=+90 pole in global frame axis3 = crossp (axis2,yaxis); } break; case 4: { // synced to NAV source (type-specific) NAVDATA ndata; NAVHANDLE hNav = v->GetNavSource (navid); axis3 = _V(0,0,1); axis2 = _V(0,1,0); if (hNav) { oapiGetNavData (hNav, &ndata); switch (ndata.type) { case TRANSMITTER_IDS: { VECTOR3 pos, dir, rot; MATRIX3 R; VESSEL *vtgt = oapiGetVesselInterface (ndata.ids.hVessel); vtgt->GetRotationMatrix (R); vtgt->GetDockParams (ndata.ids.hDock, pos, dir, rot); axis3 = -mul(R,dir); axis2 = mul(R,rot); } break; case TRANSMITTER_VTOL: case TRANSMITTER_VOR: { OBJHANDLE hRef = v->GetSurfaceRef(); VECTOR3 spos, npos; v->GetRelativePos (hRef, axis2); v->GetGlobalPos (spos); axis2 = unit (axis2); oapiGetNavPos (hNav, &npos); npos -= spos; axis3 = unit(crossp(crossp(axis2,npos),axis2)); } break; } } } break; } axis1 = crossp(axis2,axis3); R = _M(axis1.x, axis2.x, axis3.x, axis1.y, axis2.y, axis3.y, axis1.z, axis2.z, axis3.z); valid_axes = true; valid_euler = false; } return R; }