#include "MTracking.h" #include "macs.h" #include "shaftencoder.h" #include "MCosy.h" #include "SlaStars.h" #include "MDriveCom.h" ClassImp(MTracking); //#define EXPERT #undef EXPERT // -------------------------------------------------------------------------- // // Initializes Tracking mode // // Initializes the accelerations of both axes with 90% of the maximum // acceleration. Set the status for moving and tracking and starts thr // revolution mode. // bool MTracking::InitTracking() { // FIXME? Handling of Zombie OK? if (fCosy->fMac1->IsZombieNode() || fCosy->fMac2->IsZombieNode()) return false; // // Start revolution mode // if (!SetAccDec(fCosy->fMac2, fTrackAcc, fTrackDec)) return false; if (!SetAccDec(fCosy->fMac1, fTrackAcc, fTrackDec)) return false; fCosy->SetStatus(MDriveCom::kMoving | MDriveCom::kTracking); fCosy->fMac2->SetRpmMode(TRUE); if (fCosy->fMac2->IsZombieNode()) return false; fCosy->fMac1->SetRpmMode(TRUE); if (fCosy->fMac1->IsZombieNode()) return false; return true; } // -------------------------------------------------------------------------- // // Limits the speed. // // This function should work as a limiter. If a tracking error is too large // to be corrected fast enough we would get enormous velocities. These // velocities are limited to the maximum velocity. // Bool_t MTracking::LimitSpeed(ZdAz *vt, const ZdAz &vcalc) const { Bool_t rc = kFALSE; // // How to limit the speed. If the wind comes and blowes // we cannot forbid changing of the sign. But on the other hand // we don't want fast changes! // ULong_t vrzd = fCosy->fMac1->GetVelRes(); ULong_t vraz = fCosy->fMac2->GetVelRes(); #define sgn(x) (x<0?-1:1) // // When speed changes sign, the maximum allowed speed // is 25% of the |v| // //const Float_t limit = 0.25; // // The maximum allowed speed while tracking is 10% // const Float_t maxtrack = 0.1; if (fabs(vt->Az()) > maxtrack*vraz) { lout << "Warning: Azimuth speed limit (" << maxtrack*100 << "%) exceeded (" << fabs(vt->Az()) << " > " << maxtrack*vraz << ")... limited." << endl; vt->Az(maxtrack*vraz*sgn(vcalc.Az())); rc=kTRUE; } if (fabs(vt->Zd()) > maxtrack*vrzd) { lout << "Warning: Altitude speed limit (" << maxtrack*100 << "%) exceeded (" << fabs(vt->Zd()) <<" > " << maxtrack*vrzd << ")... limited." << endl; vt->Zd(maxtrack*vrzd*sgn(vcalc.Zd())); rc=kTRUE; } return rc; } // -------------------------------------------------------------------------- // // Sets the tracking velocity // // The velocities are given in a ZdAz object in re/min. Return kTRUE // in case of success, kFALSE in case of failure. // Bool_t MTracking::SetVelocity(const ZdAz &v) { // // Send the new velocities for both axes. // fCosy->fMac2->SendSDO(0x3006, 1, (LWORD_t)v.Zd()); // SetRpmVelocity [re/min] fCosy->fMac1->SendSDO(0x3006, 1, (LWORD_t)v.Az()); // SetRpmVelocity [re/min] // // Wait for the objects to be acknoledged. // fCosy->fMac2->WaitForSdo(0x3006, 1); fCosy->fMac1->WaitForSdo(0x3006, 1); // // If the waiting for the objects wasn't interrupted return kTRUE // if (!Break()) return kTRUE; // // print a message if the interruption was due to a Can-node Error // if (fCosy->HasError()) lout << "Error while setting tracking velocity (SDO #3006)" << endl; return kFALSE; } void MTracking::TrackPosition(const RaDec &dst) // ra, dec [rad] { SlaStars sla(fCosy->fObservatory); // // Position to actual position // sla.Now(); ZdAz dest = sla.CalcZdAz(dst); lout << sla.GetTime() << ": Track Position " << dst.Ra()*kRad2Deg/15 << "h, " << dst.Dec()*kRad2Deg <<"deg" << endl; // az between -180 and 180 if (dst.Dec()>sla.GetPhi() && dest.Az()<0) { // align az between (roughly) 60 and 320 lout << "Adding 360deg to Azimuth " << dest.Az()*kRad2Deg << endl; dest.Az(dest.Az() + TMath::Pi()*2); } /* // FIXME: Determin tracking start point by star culmination if (dest.Az()<-TMath::Pi()/2) { lout << "Adding 360deg to Azimuth " << dest.Az()*kRad2Deg << endl; dest.Az(dest.Az() + TMath::Pi()*2); } if (dest.Az()>3*TMath::Pi()/2) { lout << "Substracting 360deg to Azimuth " << dest.Az()*kRad2Deg << endl; dest.Az(dest.Az() -TMath::Pi()*2); } */ if (!SetPosition(dest, kTRUE)) //if (!SetPosition(dest, kFALSE)) { lout << "Error: Cannot start tracking, positioning failed." << endl; return; } // // calculate offset from present se position // const ZdAz sepos = fCosy->GetSePos()*fCosy->kGearRatio; if (!fCosy->RequestRePos()) return; // // Estimate Offset before starting to track // fCosy->fOffset = sepos-fCosy->GetRePos(); /* cout << "Sepos: " << sepos.Zd() << "re, " << sepos.Az() << "re" << endl; cout << "Repos: " << repos.Zd() << "re, " << repos.Az() << "re" << endl; cout << "Offset: " << fOffset.Zd() << "re, " << fOffset.Az() << "re" << endl; */ // // Init accelerations and Rpm Mode // if (!InitTracking()) { fCosy->StopMovement(); return; } XY xy(Rad2Deg(dst.Ra())*24/360, Rad2Deg(dst.Dec())); sla.Now(); // lout << sla.GetTime() << " - Start tracking:"; // lout << " Ra: " << xy.X() << "h " << "Dec: " << xy.Y() << "\xb0" << endl; /*#ifdef EXPERT ofstream fout("coordinates.txt"); fout << xy; fout.close(); #endif */ // // Initialize Tracker (slalib or starguider) // fCosy->fRaDec = dst; // StartThread Start(); ZdAz pos = sla.CalcZdAz(fCosy->fRaDec); lout << sla.GetTime() << " - Start Tracking: Ra=" <fRaDec); // soll pointing [rad] //lout << sla.GetTime() << pointing.Zd()*kRad2Deg << " " << pointing.Az()*kRad2Deg << endl; /* ZdAz dest; if (!AlignTrackingPos(pointing, dest)) break; */ ZdAz dest = fCosy->AlignTrackingPos(pointing); // lout << "DEST: " << dest.Zd()*kRad2Deg << " " <fRaDec) * fCosy->kGearRatio2*4./60.; //lout << "Vcalc: " << dest.Zd() << " " << dest.Az() << endl; vcalc *= fCosy->kGearRatio2*4./60.; // [re/min] float dtime = -1; //if (kFALSE /*fUseStarguider*/) // dtime = Starguider(sla.GetMjd(), dest); if (dtime<0) { dest = fCosy->fBending(dest); // [rad] //lout << "DEST-BEND: " << dest.Zd()*kRad2Deg << " " <CheckRange(dest)) break; dest *= 16384/TMath::Pi()/2; // [se] dest *= fCosy->kGearRatio; // [re] *fCosy->fOutRep << "> ReqRePos1 " << endl; // // Request absolute position of rotary encoder from Macs // if (!fCosy->RequestRePos()) break; *fCosy->fOutRep << "> ReqRePos2 " << endl; // // distance between (To+dt) and To [re] // position time difference < 5usec // fOffset does the synchronization between the // Shaft- and the rotary encoders dest -= fCosy->GetRePos() + fCosy->fOffset; dtime = dt; ZdAz repos = fCosy->GetRePos(); // lout << "Repos: " << repos.Zd()/kGearRatio.X() << " " << repos.Az()*kGearRatio.Y() << endl; // repos /= kGearRatio; repos /= 16384/TMath::Pi()/2; repos *= kRad2Deg; } // // Velocity to go [re/min] to reach the right position at time t+dt // correct for the duration of RaDec2AltAz // const ZdAz v = dest*60.0/(dtime/*-(fMac2->GetTime()-sla)*/); // // calculate real velocity of future [re/min] // believing the Macs manual '/4' shouldn't be necessary, but it is. // ZdAz vt = v/4; if (LimitSpeed(&vt, vcalc)) { lout << "Vcalc: " << vcalc.Zd() << " " << vcalc.Az() << "re/min" <.9*fCosy->fMac1->GetVelRes() || vt.Az()>.9*fCosy->fMac2->GetVelRes()) { lout << "Error: Tracking speed faster than 90% of possible maximum velocity." << endl; break; } // // Set theoretical velocity (as early after calculation as possible) // Maybe we should attenuate the changes // *fCosy->fOutRep << "> SetVelocity1 " << endl; if (!SetVelocity(vt)) break; *fCosy->fOutRep << "> SetVelocity2 " << endl; // // Now do 'unnecessary' things // fCosy->fVelocity = vt/fCosy->kGearRatio2*4; //--- const double mjd = fMac2->GetMjd(); //--- fout << setprecision(15) << setw(17) << mjd*60.*60.*24. << " "; //--- fout << setw(4) << vt.Zd() << " "; //--- fout << setw(4) << vt.Az() << endl; // // FIXME? Calculate an accuracy for the tracking system? // How good do we reach the calculated position in 'real' // re valus? // // // Update speed as often as possible. // make sure, that dt is around 10 times larger than the // update time // // // The loop should not be executed faster than the ramp of // a change in the velocity can be followed. // (This is important on fast machines >500MHz) // /* MTimeout t(1000); while (!t.HasTimedOut()) usleep(1); */ usleep(1000000); // 1s cout << "." << flush; //usleep(50000); // 0.05s } sla.Now(); // StopThread Stop(); fCosy->StopMovement(); lout << sla.GetTime() << " - Tracking stopped." << endl; } void *MTracking::Thread() { if (fCosy->fZd1->IsZombieNode() && fCosy->fZd2->IsZombieNode()) return (void*)1; if (fCosy->fAz->IsZombieNode()) return (void*)2; if (!fCosy->fMac1 || !fCosy->fMac2) return (void*)3; lout << "- Tracking Thread started..." << endl; SlaStars sla(fCosy->fObservatory); sla.Now(); ZdAz old; ZdAz ist = fCosy->GetSePos(); // [se] ZdAz time; ZdAz sollzd = sla.CalcZdAz(fCosy->fRaDec); // [rad] ZdAz sollaz = sollzd; // [rad] // // only update fTrackingError while tracking // bool phca1=false; bool phca2=false; bool phcaz=false; while (!HasStopFlag()) { // // Make changes (eg wind) smoother - attenuation of control function // const float weight = 1.; //0.3; // // This is the time constant which defines how fast // you correct for external influences (like wind) // *fCosy->fOutRep << "> ResetPosHasChanged" << endl; fCosy->fZd1->ResetPosHasChanged(); fCosy->fZd2->ResetPosHasChanged(); fCosy->fAz->ResetPosHasChanged(); *fCosy->fOutRep << "> Check for PosHasChanged" << endl; do { phca1 = fCosy->fZd1->PosHasChanged(); phca2 = fCosy->fZd2->PosHasChanged(); phcaz = fCosy->fAz->PosHasChanged(); usleep(1); } while (!phca1 && !phca2 && !phcaz && !HasStopFlag()); //---usleep(100000); // 0.1s *fCosy->fOutRep << "> Do Calculation" << endl; // // get position, where we are // old = ist; ist = fCosy->GetSePos(); // [se] // // if the position didn't change continue // /*--- if ((int)ist.Zd() == (int)old.Zd() && (int)ist.Az() == (int)old.Az()) continue; */ ZdAz istre = fCosy->GetRePosPdo(); // // Get time from last shaftencoder position change (position: ist) // FIXME: I cannot take the avarage // // FIXME //time.Zd(fZd1->GetMjd()); /* OLD* */ if (fCosy->fZd1->GetMjd()>fCosy->fZd2->GetMjd()) time.Zd(fCosy->fZd1->GetMjd()); else time.Zd(fCosy->fZd2->GetMjd()); //time.Zd((fZd1->GetMjd()+fZd2->GetMjd())/2.0); time.Az(fCosy->fAz->GetMjd()); // // if Shaftencoder changed position // calculate were we should be // if (phca1 || phca2 /*(int)ist.Zd() != (int)old.Zd()*/) { sollzd = sla.CalcZdAz(fCosy->fRaDec, time.Zd()); // [rad] /* ZdAz dummy = fBending(sla.CalcZdAz(fRaDec)); sollzd = CorrectTarget(ist, dummy); // [se] */ fCosy->fOffset.Zd(fCosy->fOffset.Zd()*(1.-weight)+(ist.Zd()*fCosy->kGearRatio.X()-istre.Zd())*weight); } if (phcaz /*(int)ist.Az() != (int)old.Az()*/) { sollaz = sla.CalcZdAz(fCosy->fRaDec, time.Az()); // [rad] /* ZdAz dummy = fBending(sla.CalcZdAz(fRaDec)); sollaz = CorrectTarget(ist, dummy); // [se] */ fCosy->fOffset.Az(fCosy->fOffset.Az()*(1.-weight)+(ist.Az()*fCosy->kGearRatio.Y()-istre.Az())*weight); } ZdAz soll(sollzd.Zd(), sollaz.Az()); // [rad] fCosy->fZdAzSoll = fCosy->AlignTrackingPos(soll); ist *= TMath::Pi()*2/16384; soll = fCosy->fBending(fCosy->fZdAzSoll); fCosy->fTrackingError.Set(ist.Zd()-soll.Zd(), ist.Az()-soll.Az()); //--- fout << setprecision(15) << setw(17) << time.Zd()*60.*60.*24. << " "; //--- fout << setprecision(5) << setw(7) << fTrackingError.Zd() << " "; //--- fout << setprecision(15) << setw(17) << time.Az()*60.*60.*24. << " "; //--- fout << setprecision(5) << setw(7) << fTrackingError.Az() << endl; } lout << "- Tracking Thread done." << endl; return 0; }