bool ScopeASCOM::SlewToCoordinates(double ra, double dec) { bool bError = false; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot slew when not connected"); } if (!m_bCanSlew) { throw THROW_INFO("ASCOM Scope: not capable of slewing"); } GITObjRef scope(m_gitEntry); Variant vRes; if (!scope.InvokeMethod(&vRes, dispid_slewtocoordinates, ra, dec)) { throw ERROR_INFO("ASCOM Scope: slew to coordinates failed"); } } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); bError = true; } return bError; }
Mount::MOVE_RESULT StepGuider::CalibrationMove(GUIDE_DIRECTION direction, int steps) { MOVE_RESULT result = MOVE_OK; Debug.AddLine(wxString::Format("stepguider calibration move dir= %d steps= %d", direction, steps)); try { MoveResultInfo move; result = Move(direction, steps, false, &move); if (move.amountMoved != steps) { throw THROW_INFO("stepsTaken != m_calibrationStepsPerIteration"); } } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); if (result == MOVE_OK) result = MOVE_ERROR; } return result; }
bool ScopeASCOM::GetCoordinates(double *ra, double *dec, double *siderealTime) { bool bError = false; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get coordinates when not connected"); } if (!m_bCanGetCoordinates) { throw THROW_INFO("ASCOM Scope: not capable of getting coordinates"); } GITObjRef scope(m_gitEntry); Variant vRA; if (!scope.GetProp(&vRA, dispid_rightascension)) { throw ERROR_INFO("ASCOM Scope: get right ascension failed: " + ExcepMsg(scope.Excep())); } Variant vDec; if (!scope.GetProp(&vDec, dispid_declination)) { throw ERROR_INFO("ASCOM Scope: get declination failed: " + ExcepMsg(scope.Excep())); } Variant vST; if (!scope.GetProp(&vST, dispid_siderealtime)) { throw ERROR_INFO("ASCOM Scope: get sidereal time failed: " + ExcepMsg(scope.Excep())); } *ra = vRA.dblVal; *dec = vDec.dblVal; *siderealTime = vST.dblVal; } catch (wxString Msg) { bError = true; POSSIBLY_UNUSED(Msg); } return bError; }
// Return RA and Dec guide rates in native ASCOM units, degrees/sec. // Convention is to return true on an error bool ScopeASCOM::GetGuideRates(double *pRAGuideRate, double *pDecGuideRate) { bool bError = false; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get guide rates when not connected"); } if (!m_bCanGetGuideRates) { throw THROW_INFO("ASCOM Scope: not capable of getting guide rates"); } GITObjRef scope(m_gitEntry); Variant vRes; if (!scope.GetProp(&vRes, dispid_decguiderate)) { throw ERROR_INFO("ASCOM Scope: GuideRateDec() failed: " + ExcepMsg(scope.Excep())); } *pDecGuideRate = vRes.dblVal; if (!scope.GetProp(&vRes, dispid_raguiderate)) { throw ERROR_INFO("ASCOM Scope: GuideRateRA() failed: " + ExcepMsg(scope.Excep())); } *pRAGuideRate = vRes.dblVal; } catch (wxString Msg) { bError = true; POSSIBLY_UNUSED(Msg); } Debug.AddLine("ScopeASCOM::GetGuideRates() returns %u %.4f %.4f", bError, bError ? 0.0 : *pDecGuideRate, bError ? 0.0 : *pRAGuideRate); return bError; }
PierSide ScopeASCOM::SideOfPier(void) { PierSide pierSide = PIER_SIDE_UNKNOWN; try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get side of pier when not connected"); } if (dispid_sideofpier == DISPID_UNKNOWN) { throw THROW_INFO("ASCOM Scope: not capable of getting side of pier"); } GITObjRef scope(m_gitEntry); Variant vRes; if (!scope.GetProp(&vRes, dispid_sideofpier)) { throw ERROR_INFO("ASCOM Scope: SideOfPier failed: " + ExcepMsg(scope.Excep())); } switch (vRes.intVal) { case 0: pierSide = PIER_SIDE_EAST; break; case 1: pierSide = PIER_SIDE_WEST; break; } } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); } Debug.AddLine("ScopeASCOM::SideOfPier() returns %d", pierSide); return pierSide; }
PierSide ScopeINDI::SideOfPier(void) { PierSide pierSide = PIER_SIDE_UNKNOWN; try { if (!IsConnected()) { throw ERROR_INFO("INDI Scope: cannot get side of pier when not connected"); } if (pierside_prop == NULL) { throw THROW_INFO("INDI Scope: not capable of getting side of pier"); } else { if (piersideEast_prop->s == ISS_ON) { pierSide = PIER_SIDE_EAST; } if (piersideWest_prop->s == ISS_ON) { pierSide = PIER_SIDE_WEST; } } } catch (const wxString& Msg) { POSSIBLY_UNUSED(Msg); } Debug.Write(wxString::Format("ScopeINDI::SideOfPier() returns %d\n", pierSide)); return pierSide; }
// Special purpose function to return the guiding declination (radians) - either the actual scope position or the // default values defined in mount.cpp. Doesn't throw exceptions to callers. double ScopeASCOM::GetGuidingDeclination(void) { double dReturn = Scope::GetDefGuidingDeclination(); try { if (!IsConnected()) { throw ERROR_INFO("ASCOM Scope: cannot get Declination when not connected to mount"); } if (!m_bCanGetCoordinates) { throw THROW_INFO("!m_bCanGetCoordinates"); } GITObjRef scope(m_gitEntry); Variant vRes; if (!scope.GetProp(&vRes, dispid_declination)) { throw ERROR_INFO("GetDeclination() fails: " + ExcepMsg(scope.Excep())); } dReturn = radians(vRes.dblVal); } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); m_bCanGetCoordinates = false; } Debug.AddLine("ScopeASCOM::GetDeclination() returns %.1f", degrees(dReturn)); return dReturn; }
Mount::MOVE_RESULT StepGuider::Move(const PHD_Point& cameraVectorEndpoint, bool normalMove) { MOVE_RESULT result = MOVE_OK; try { MOVE_RESULT mountResult = Mount::Move(cameraVectorEndpoint, normalMove); if (mountResult != MOVE_OK) Debug.AddLine("StepGuider::Move: Mount::Move failed!"); if (!m_guidingEnabled) { throw THROW_INFO("Guiding disabled"); } // keep a moving average of the AO position if (m_avgOffset.IsValid()) { static double const alpha = .33; // moderately high weighting for latest sample m_avgOffset.X += alpha * (m_xOffset - m_avgOffset.X); m_avgOffset.Y += alpha * (m_yOffset - m_avgOffset.Y); } else { m_avgOffset.SetXY((double) m_xOffset, (double) m_yOffset); } pFrame->pStepGuiderGraph->AppendData(m_xOffset, m_yOffset, m_avgOffset); // consider bumping the secondary mount if this is a normal move if (normalMove && pSecondaryMount && pSecondaryMount->IsConnected()) { int absX = abs(CurrentPosition(RIGHT)); int absY = abs(CurrentPosition(UP)); bool isOutside = absX > m_xBumpPos1 || absY > m_yBumpPos1; bool forceStartBump = false; if (m_forceStartBump) { Debug.Write("stepguider::Move: will start forced bump\n"); forceStartBump = true; m_forceStartBump = false; } // if the current bump has not brought us in, increase the bump size if (isOutside && m_bumpInProgress) { if (absX > m_xBumpPos2 || absY > m_yBumpPos2) { Debug.AddLine("FAR outside bump range, increase bump weight %.2f => %.2f", m_bumpStepWeight, m_bumpStepWeight + 1.0); m_bumpStepWeight += 1.0; } else { Debug.AddLine("outside bump range, increase bump weight %.2f => %.2f", m_bumpStepWeight, m_bumpStepWeight + 1./6.); m_bumpStepWeight += 1./6.; } } // if we are back inside, decrease the bump weight if (!isOutside && m_bumpStepWeight > 1.0) { double prior = m_bumpStepWeight; m_bumpStepWeight *= 0.5; if (m_bumpStepWeight < 1.0) m_bumpStepWeight = 1.0; Debug.AddLine("back inside bump range: decrease bump weight %.2f => %.2f", prior, m_bumpStepWeight); } if (m_bumpInProgress && !m_bumpTimeoutAlertSent) { long now = ::wxGetUTCTime(); if (now - m_bumpStartTime > BumpWarnTime) { pFrame->Alert(_("A mount \"bump\" was needed to bring the AO back to its center position,\n" "but the bump did not complete in a reasonable amount of time.\n" "You probably need to increase the AO Bump Step setting."), wxICON_INFORMATION); m_bumpTimeoutAlertSent = true; } } if ((isOutside || forceStartBump) && !m_bumpInProgress) { // start a new bump m_bumpInProgress = true; m_bumpStartTime = ::wxGetUTCTime(); m_bumpTimeoutAlertSent = false; Debug.AddLine("starting a new bump"); } // stop the bump if we are "close enough" to the center position if ((!isOutside || forceStartBump) && m_bumpInProgress) { int minDist = m_bumpCenterTolerance; if (m_avgOffset.X * m_avgOffset.X + m_avgOffset.Y * m_avgOffset.Y <= minDist * minDist) { Debug.AddLine("Stop bumping, close enough to center -- clearing m_bumpInProgress"); m_bumpInProgress = false; pFrame->pStepGuiderGraph->ShowBump(PHD_Point()); } } } if (m_bumpInProgress && pSecondaryMount->IsBusy()) Debug.AddLine("secondary mount is busy, cannot bump"); // if we have a bump in progress and the secondary mount is not moving, // schedule another move if (m_bumpInProgress && !pSecondaryMount->IsBusy()) { // compute incremental bump based on average position PHD_Point vectorEndpoint(xRate() * -m_avgOffset.X, yRate() * -m_avgOffset.Y); // we have to transform our notion of where we are (which is in "AO Coordinates") // into "Camera Coordinates" so we can bump the secondary mount to put us closer // to the center of the AO PHD_Point bumpVec; if (TransformMountCoordinatesToCameraCoordinates(vectorEndpoint, bumpVec)) { throw ERROR_INFO("MountToCamera failed"); } Debug.AddLine("incremental bump (%.3f, %.3f) isValid = %d", bumpVec.X, bumpVec.Y, bumpVec.IsValid()); double maxBumpPixelsX = m_calibration.xRate * m_bumpMaxStepsPerCycle * m_bumpStepWeight; double maxBumpPixelsY = m_calibration.yRate * m_bumpMaxStepsPerCycle * m_bumpStepWeight; double len = bumpVec.Distance(); double xBumpSize = bumpVec.X * maxBumpPixelsX / len; double yBumpSize = bumpVec.Y * maxBumpPixelsY / len; PHD_Point thisBump(xBumpSize, yBumpSize); // display the current bump vector on the stepguider graph { PHD_Point tcur; TransformCameraCoordinatesToMountCoordinates(thisBump, tcur); tcur.X /= xRate(); tcur.Y /= yRate(); pFrame->pStepGuiderGraph->ShowBump(tcur); } Debug.AddLine("Scheduling Mount bump of (%.3f, %.3f)", thisBump.X, thisBump.Y); pFrame->ScheduleSecondaryMove(pSecondaryMount, thisBump, false); } } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); result = MOVE_ERROR; } return result; }
Mount::MOVE_RESULT StepGuider::Move(GUIDE_DIRECTION direction, int steps, bool normalMove, MoveResultInfo *moveResult) { MOVE_RESULT result = MOVE_OK; bool limitReached = false; try { Debug.AddLine(wxString::Format("Move(%d, %d, %d)", direction, steps, normalMove)); // Compute the required guide steps if (!m_guidingEnabled) { throw THROW_INFO("Guiding disabled"); } // Acutally do the guide assert(steps >= 0); if (steps > 0) { int yDirection = 0; int xDirection = 0; switch (direction) { case UP: yDirection = 1; break; case DOWN: yDirection = -1; break; case RIGHT: xDirection = 1; break; case LEFT: xDirection = -1; break; default: throw ERROR_INFO("StepGuider::Move(): invalid direction"); break; } assert(yDirection == 0 || xDirection == 0); assert(yDirection != 0 || xDirection != 0); Debug.AddLine(wxString::Format("stepping direction=%d steps=%d xDirection=%d yDirection=%d", direction, steps, xDirection, yDirection)); if (WouldHitLimit(direction, steps)) { int new_steps = MaxPosition(direction) - 1 - CurrentPosition(direction); Debug.AddLine(wxString::Format("StepGuider step would hit limit: truncate move direction=%d steps=%d => %d", direction, steps, new_steps)); steps = new_steps; limitReached = true; } if (steps > 0) { if (Step(direction, steps)) { throw ERROR_INFO("step failed"); } m_xOffset += xDirection * steps; m_yOffset += yDirection * steps; Debug.AddLine(wxString::Format("stepped: xOffset=%d yOffset=%d", m_xOffset, m_yOffset)); } } } catch (const wxString& Msg) { POSSIBLY_UNUSED(Msg); steps = 0; result = MOVE_ERROR; } if (moveResult) { moveResult->amountMoved = steps; moveResult->limited = limitReached; } return result; }
void GuiderOneStar::OnLClick(wxMouseEvent &mevent) { try { if (mevent.GetModifiers() == wxMOD_CONTROL) { double const scaleFactor = ScaleFactor(); wxRealPoint pt((double) mevent.m_x / scaleFactor, (double) mevent.m_y / scaleFactor); ToggleBookmark(pt); m_showBookmarks = true; pFrame->bookmarks_menu->Check(MENU_BOOKMARKS_SHOW, GetBookmarksShown()); Refresh(); Update(); return; } if (GetState() > STATE_SELECTED) { mevent.Skip(); throw THROW_INFO("Skipping event because state > STATE_SELECTED"); } if (mevent.GetModifiers() == wxMOD_SHIFT) { // Deselect guide star InvalidateCurrentPosition(true); } else { if ((mevent.m_x <= m_searchRegion) || (mevent.m_x + m_searchRegion >= XWinSize) || (mevent.m_y <= m_searchRegion) || (mevent.m_y + m_searchRegion >= YWinSize)) { mevent.Skip(); throw THROW_INFO("Skipping event because click outside of search region"); } usImage *pImage = CurrentImage(); if (pImage->NPixels == 0) { mevent.Skip(); throw ERROR_INFO("Skipping event m_pCurrentImage->NPixels == 0"); } double scaleFactor = ScaleFactor(); double StarX = (double) mevent.m_x / scaleFactor; double StarY = (double) mevent.m_y / scaleFactor; SetCurrentPosition(pImage, PHD_Point(StarX, StarY)); if (!m_star.IsValid()) { pFrame->SetStatusText(wxString::Format(_("No star found"))); } else { SetLockPosition(m_star); pFrame->SetStatusText(wxString::Format(_("Selected star at (%.1f, %.1f)"), m_star.X, m_star.Y), 1); pFrame->SetStatusText(wxString::Format(_T("m=%.0f SNR=%.1f"), m_star.Mass, m_star.SNR)); EvtServer.NotifyStarSelected(CurrentPosition()); SetState(STATE_SELECTED); pFrame->UpdateButtonsStatus(); pFrame->pProfile->UpdateData(pImage, m_star.X, m_star.Y); } Refresh(); Update(); } } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); } }
bool GuiderOneStar::UpdateCurrentPosition(usImage *pImage, FrameDroppedInfo *errorInfo) { if (!m_star.IsValid() && m_star.X == 0.0 && m_star.Y == 0.0) { Debug.AddLine("UpdateCurrentPosition: no star selected"); errorInfo->starError = Star::STAR_ERROR; errorInfo->starMass = 0.0; errorInfo->starSNR = 0.0; errorInfo->status = _("No star selected"); return true; } bool bError = false; try { Star newStar(m_star); if (!newStar.Find(pImage, m_searchRegion, pFrame->GetStarFindMode())) { errorInfo->starError = newStar.GetError(); errorInfo->starMass = 0.0; errorInfo->starSNR = 0.0; errorInfo->status = StarStatusStr(newStar); m_star.SetError(newStar.GetError()); throw ERROR_INFO("UpdateCurrentPosition():newStar not found"); } // check to see if it seems like the star we just found was the // same as the original star. We do this by comparing the // mass m_massChecker->SetExposure(pFrame->RequestedExposureDuration()); double limits[3]; if (m_massChangeThresholdEnabled && m_massChecker->CheckMass(newStar.Mass, m_massChangeThreshold, limits)) { m_star.SetError(Star::STAR_MASSCHANGE); errorInfo->starError = Star::STAR_MASSCHANGE; errorInfo->starMass = newStar.Mass; errorInfo->starSNR = newStar.SNR; errorInfo->status = StarStatusStr(m_star); pFrame->SetStatusText(wxString::Format(_("Mass: %.0f vs %.0f"), newStar.Mass, limits[1]), 1); Debug.Write(wxString::Format("UpdateGuideState(): star mass new=%.1f exp=%.1f thresh=%.0f%% range=(%.1f, %.1f)\n", newStar.Mass, limits[1], m_massChangeThreshold * 100, limits[0], limits[2])); m_massChecker->AppendData(newStar.Mass); throw THROW_INFO("massChangeThreshold error"); } // update the star position, mass, etc. m_star = newStar; m_massChecker->AppendData(newStar.Mass); const PHD_Point& lockPos = LockPosition(); if (lockPos.IsValid()) { double distance = newStar.Distance(lockPos); UpdateCurrentDistance(distance); } pFrame->pProfile->UpdateData(pImage, m_star.X, m_star.Y); pFrame->AdjustAutoExposure(m_star.SNR); errorInfo->status.Printf(_T("m=%.0f SNR=%.1f"), m_star.Mass, m_star.SNR); } catch (wxString Msg) { POSSIBLY_UNUSED(Msg); bError = true; pFrame->ResetAutoExposure(); // use max exposure duration } return bError; }
double GuideAlgorithmResistSwitch::result(double input) { double dReturn = input; m_history.Add(input); m_history.RemoveAt(0); try { if (fabs(input) < m_minMove) { throw THROW_INFO("input < m_minMove"); } if (m_fastSwitchEnabled) { double thresh = 3.0 * m_minMove; if (sign(input) != m_currentSide && fabs(input) > thresh) { Debug.Write(wxString::Format("resist switch: large excursion: input %.2f thresh %.2f direction from %d to %d\n", input, thresh, m_currentSide, sign(input))); // force switch m_currentSide = 0; unsigned int i; for (i = 0; i < HISTORY_SIZE - 3; i++) m_history[i] = 0.0; for (; i < HISTORY_SIZE; i++) m_history[i] = input; } } int decHistory = 0; for (unsigned int i = 0; i < m_history.GetCount(); i++) { if (fabs(m_history[i]) > m_minMove) { decHistory += sign(m_history[i]); } } if (m_currentSide == 0 || sign(m_currentSide) == -sign(decHistory)) { if (abs(decHistory) < 3) { throw THROW_INFO("not compelling enough"); } double oldest = 0.0; double newest = 0.0; for (int i = 0; i < 3; i++) { oldest += m_history[i]; newest += m_history[m_history.GetCount() - (i + 1)]; } if (fabs(newest) <= fabs(oldest)) { throw THROW_INFO("Not getting worse"); } Debug.Write(wxString::Format("switching direction from %d to %d - decHistory=%d oldest=%.2f newest=%.2f\n", m_currentSide, sign(decHistory), decHistory, oldest, newest)); m_currentSide = sign(decHistory); } if (m_currentSide != sign(input)) { throw THROW_INFO("must have overshot -- vetoing move"); } } catch (const wxString& Msg) { POSSIBLY_UNUSED(Msg); dReturn = 0.0; } Debug.Write(wxString::Format("GuideAlgorithmResistSwitch::Result() returns %.2f from input %.2f\n", dReturn, input)); return dReturn * m_aggression; }