#include "MCosy.h" #include "MCosy.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "MGCosy.h" #include "MDriveCom.h" #include "MStarguider.h" #include "SlaStars.h" #include "slalib/slalib.h" // FIXME: REMOVE #include "macs.h" #include "base/timer.h" #include "shaftencoder.h" ClassImp(MCosy); typedef struct tm tm_t; /* #define GEAR_RATIO_ALT 2475.6 // [U_mot/U_tel(360deg)] #define GEAR_RATIO_AZ 5891.7 // [U_mot/U_tel(360deg)] #define RES_RE 500 // [re/U_mot] #define RES_SE 16384 // [se/U_tel(360deg)] */ /* #define GEAR_RATIO_ALT (75.55*16384/1500) // 75.25 VERY IMPORTANT! unit=U_mot/U_tel #define GEAR_RATIO_AZ (179.8*16384/1500) // VERY IMPORTANT! unit=U_mot/U_tel */ //const XY kGearRatio (GEAR_RATIO_ALT*RES_RE/RES_SE, GEAR_RATIO_AZ*RES_RE/RES_SE); //[re/se] //const XY kGearRatio2(GEAR_RATIO_ALT*RES_RE/360.0, GEAR_RATIO_AZ*RES_RE/360.0); //[re/deg] /* +===================================+ FIXME: What if fMac3 (Sync) died? +===================================+ */ #define EXPERT //#undef EXPERT double MCosy::Rad2SE(double rad) const { return 16384.0/k2Pi*rad; } double MCosy::Rad2ZdRE(double rad) const { return 16384.0/k2Pi*rad*kGearRatio.X(); } double MCosy::Rad2AzRE(double rad) const { return 16384.0/k2Pi*rad*kGearRatio.Y(); } double MCosy::Deg2ZdRE(double rad) const { return rad*kGearRatio2.X(); } double MCosy::Deg2AzRE(double rad) const { return rad*kGearRatio2.Y(); } /* ZdAz MCosy::CorrectTarget(const ZdAz &src, const ZdAz &dst) { // CorrectTarget [se] // src [se] // dst [rad] // fAltMax = 70 // fAltMin = -105/110 // fAzMin = -355 // fAzMax = 355 ZdAz source = src * 360.0/16384.0; ZdAz dest = dst * kRad2Deg; if (dest.Zd()>-3 && dest.Zd()<3) dest.Zd(dest.Zd()<0?-3:3); if (dest.Zd()>-1e-6 && dest.Zd()<1e-6) return dst*(16384.0/k2Pi); const float fZdMin = -67; const float fZdMax = 67; const float fAzMin = -29; const float fAzMax = 423; // // This corrects to target for the shortest distance, not for the fastest move! // ZdAz s = source-dest; float min = s.Sqr(); // // Is it enought to search inside one revolution? // ZdAz ret = dest; for (int i=-5; i<5+1; i++) { const ZdAz p(i%2 ? -dest.Zd() : dest.Zd(), dest.Az() - i*180); // // Range Check // if (p.Zd()fZdMax) continue; if (p.Az()fAzMax) continue; // // Calculate distance // s = source-p; const float dist = s.Sqr(); if (dist > min) continue; // // New shortest distance // ret = p; min = dist; } return ret*(16384.0/360.0); } */ // -------------------------------------------------------------------------- // // GetSePos, reads the Shaftencoder positions from the Can-drivers // for the shaftencoders. The two shaft encoders at the elevation axis // are avaraged. The values are returned as a ZdAz object. // // If one of the two shaftencoders on the elevation axis is missing // the other one's position is returned. // // The positions are alway up-to-date because the shaftencoders are // sending all changes immediatly. // ZdAz MCosy::GetSePos() const { const int pa = fAz->GetPos(); if (fZd1->IsZombieNode() && fZd2->IsZombieNode()) return ZdAz(0, pa); // // Get the values // int p1 = (fZd1->GetPos()+8192)%16384; int p2 = -(fZd2->GetPos()+8192)%16384; if (fZd1->IsZombieNode()) return ZdAz(p2, pa); if (fZd2->IsZombieNode()) return ZdAz(p1, pa); // // interpolate shaft encoder positions // float p = (float)(p1+p2)/2; return ZdAz(p, pa); } // -------------------------------------------------------------------------- // // request the current positions from the rotary encoders. // use GetRePos to get the psotions. If the request fails the function // returns kFALSE, otherwise kTRUE // Bool_t MCosy::RequestRePos() { // // Send request // fMac2->RequestSDO(0x6004); fMac1->RequestSDO(0x6004); // // Wait until the objects are received. // fMac2->WaitForSdo(0x6004); fMac1->WaitForSdo(0x6004); // // If waiting was not interrupted everything is ok. return. // if (!(Break() || HasError() || HasZombie())) return kTRUE; // // If the waiting was interrupted due to a network error, // print some logging message. // if (HasError()) lout << "Error while requesting re pos from Macs (SDO #6004)" << endl; return kFALSE; } // -------------------------------------------------------------------------- // // reads the Rotary encoder positions from the last request of the Macs. // // The positions are returned as a ZdAz object. Use RequestRePos to request // the current positions first. // ZdAz MCosy::GetRePos() { return ZdAz(fMac2->GetPos(), fMac1->GetPos()); } // -------------------------------------------------------------------------- // // reads the Rotary encoder positions from the Macs. // // The positions are returned as a ZdAz object. The positions are the ones // which are send as PDOs to the computer. This is done at a given // frequency. Which means, that this positions are not ought to be // up-to-date. // ZdAz MCosy::GetRePosPdo() { return ZdAz(fMac2->GetPdoPos(), fMac1->GetPdoPos()); } // -------------------------------------------------------------------------- // // set the velocity and accelerations for position maneuvers. // // The acceleratin is set as given (in percent of maximum). // The velocity is given in percent, depending on the ratio (<1 or >1) // one of the axis becomes a slower velocity. This is used for maneuvers // in which both axis are moved synchromously and should reach their // target position at the same time. // void MCosy::SetPosVelocity(const Float_t ratio, Float_t vel) { // // Set velocities // const int vr = fMac1->GetVelRes(); vel *= vr; if (ratio <1) { fMac1->SetVelocity(vel); fMac2->SetVelocity(vel*ratio); } else { fMac1->SetVelocity(vel/ratio); fMac2->SetVelocity(vel); } } // -------------------------------------------------------------------------- // // Does a relative positioning. // // The steps to move are given in a ZdAz object relative to the current // position. The coordinates are given in Roteryencoder steps. // Axis 1 is moved only if axe1==kTRUE, Axis 2 is moved only // if Axis 2==kTRUE. The function waits for the movement to be finished. // void MCosy::DoRelPos(const ZdAz &rd, const Bool_t axe1, const Bool_t axe2) { if (HasZombie()) return; SetStatus(MDriveCom::kMoving); if (axe1) fMac2->StartRelPos(rd.Zd()); if (axe2) fMac1->StartRelPos(rd.Az()); #ifdef EXPERT cout << "Waiting for positioning..." << flush; #endif if (axe1) fMac2->WaitForSdo(0x6004, 1); if (axe2) fMac1->WaitForSdo(0x6004, 1); WaitForEndMovement(); #ifdef EXPERT cout << "done." << endl; #endif } // -------------------------------------------------------------------------- // // check for a break-signal (from the msgqueue) and errors. // int MCosy::StopWaitingForSDO() const { return 0/*Break() || HasError()*/; } // -------------------------------------------------------------------------- // // Waits for a movement to become finished. // // First waits for all peding Sdos, then waits until both motors are stopped // or waiting for SDOs was stopped (either by an error or by Break) // void MCosy::WaitForEndMovement() { // FIXME, what when waiting times out (Zombie) if (!fMac1 || !fMac2) return; while ((fMac1->IsPositioning() || fMac2->IsPositioning()) && !(Break() || HasError() || HasZombie())) usleep(1); if (!Break() && !HasError() && !HasZombie()) return; Timer t; t.Now(); lout << t << " - MCosy::WaitForEndMovement aborted..."; if (Break()) lout << " Break signal..."; if (HasError()) lout << " Network has error..."; if (HasZombie()) lout << " Network has zombie..."; lout << endl; } // -------------------------------------------------------------------------- // // Check for an error... // // This is ment for usage after the Action: All Motors Stop. // void MCosy::CheckForError() { // // Check all Can-Nodes for an Error. If there is no error the motor // status is set to stopped. // if (HasError() || HasZombie()) { SetStatus(MDriveCom::kError); return; } if (fMac1->IsPositioning() || fMac2->IsPositioning()) SetStatus(MDriveCom::kMoving); else SetStatus(MDriveCom::kStopped); // // If there is an error, the error status is set to Error. // /* FIXME: HANDLINGE ERROR // // Now try to handle the error. // fMac1->HandleError(); fMac2->HandleError(); // // If the error couldn't get solved return // if (HasError()) return; // // Set motor status to stopped // SetStatus(MDriveCom::kStopped); */ } Bool_t MCosy::CheckRange(const ZdAz &d) const { // d [rad] if (d.Zd()fMax.Zd()) { lout << "ERROR: Requested Zenith Angle behind positive endswitch." << endl; return kFALSE; } if (d.Az()fMax.Az()) { lout << "ERROR: Requested Azimuth Angle behind positive endswitch." << endl; return kFALSE; } return kTRUE; } // -------------------------------------------------------------------------- // // Move the telescope to the given position. The position must be given in // a ZdAz object in rad. // // The first positioning is done absolutely. If we didn't reach the // correct psotion we try to correct for this by 10 relative position // maneuvers. If this doesn't help positioning failed. // // As a reference the shaftencoder values are used. // int MCosy::SetPosition(const ZdAz &dst, Bool_t track) // [rad] { const ZdAz d = dst*kRad2Deg; Timer t; t.Now(); lout << t << " - Target Position: " << d.Zd() << "deg, " << d.Az() << "deg (Zd/Az)" << endl; // // Calculate new target position (shortest distance to go) // const ZdAz src = GetSePos(); // [se] // // Make sure that the motors are in sync mode (necessary if the // MACS has been rebooted from a Zombie state. // //InitSync(); //if (fMac3->IsZombieNode()) // return false; // // Because we agreed on I don't search for the shortest move // anymore // // const ZdAz dest = CorrectTarget(src, dst); // ZdAz bend = fBending(dst); // [rad] const ZdAz dest = bend*16384/2/TMath::Pi(); // [se] if (!CheckRange(bend)) return kFALSE; bend *= kRad2Deg; fZdAzSoll = dst; cout << "Source Zd: " << src.Zd() << "se Az:" << src.Az() << "se" << endl; cout << "Destination Zd: " << Rad2SE(dst.Zd()) << "se Az:" << Rad2SE(dst.Az()) << "se" << endl; cout << "Bend'd Dest Zd: " << dest.Zd() << "se Az:" << dest.Az() << "se" << endl; cout << "Bend'd Dest Zd: " << bend.Zd() << "deg Az:" << bend.Az() << "deg" << endl; // // Set velocities // const int vr = fMac1->GetVelRes(); int i; for (i=0; i<(track?1:10) && !(Break() || HasError() || HasZombie()); i++) { lout << "- Step #" << i << endl; // // Get Shaft Encoder Positions // const ZdAz p=GetSePos(); // // calculate control deviation and rounded cd // ZdAz rd = dest-p; // [se] // =========================================== const ZdAz ist = dst-rd*TMath::Pi()/8192; const double p1 = ist.Zd()-19.0605/kRad2Deg; const double p2 = dst.Zd()-19.0605/kRad2Deg; const double f1 = (-26.0101*sin(p1)+443.761*ist.Zd())*8192/TMath::Pi(); const double f2 = (-26.0101*sin(p2)+443.761*dst.Zd())*8192/TMath::Pi(); // =========================================== ZdAz cd = rd; // [se] cd.Round(); // // Check if there is a control deviation on the axis // const Bool_t cdzd = (int)cd.Zd() ? kTRUE : kFALSE; const Bool_t cdaz = (int)cd.Az() ? kTRUE : kFALSE; // // check if we reached the correct position already // if (!cdzd && !cdaz) { t.Now(); lout << t << " - Positioning done in " << i << (i==1?" step.":" steps.") << endl; SetStatus(MDriveCom::kStopped); return TRUE; } // // change units from se to re // rd *= kGearRatio; // [re] rd.Zd(f2-f1); // // Initialize Velocities so that we reach both positions // at the same time // if (i) { fMac1->SetAcceleration(0.1*vr); fMac2->SetAcceleration(0.1*vr); fMac1->SetDeceleration(0.1*vr); fMac2->SetDeceleration(0.1*vr); SetPosVelocity(1.0, 0.05); } else { if (rd.Az()>-15*kGearRatio.Y() && rd.Az()<15*kGearRatio.Y()) { #ifdef EXPERT cout << " -------------- LO ---------------- " << endl; #endif fMac1->SetAcceleration(0.05*vr); fMac1->SetDeceleration(0.05*vr); } else { #ifdef EXPERT cout << " -------------- HI ---------------- " << endl; fMac1->SetAcceleration(0.4*vr);// 0.4 fMac1->SetDeceleration(0.4*vr);// 0.4 #else fMac1->SetAcceleration(0.2*vr); fMac1->SetDeceleration(0.1*vr); #endif } #ifdef EXPERT fMac2->SetAcceleration(0.4*vr);// 0.4 fMac2->SetDeceleration(0.4*vr);// 0.4 SetPosVelocity(fabs(rd.Ratio()), 0.2); // fast: 0.6, slow: 0.2 #else fMac2->SetAcceleration(0.2*vr); fMac2->SetDeceleration(0.1*vr); SetPosVelocity(fabs(rd.Ratio()), 0.1); #endif } rd.Round(); // FIXME? Check for Error or Zombie? /* cout << " + " << (int)cdzd << " " << (int)cdaz << endl; cout << " + APOS: Zd=" << setw(6) << p.Zd() << "se Az=" << setw(6) << p.Az() << "se" << endl; cout << " + dZd=" << setw(6) << cd.Zd() << "se dAz=" << setw(6) << cd.Az() << "se" << endl; cout << " + dZd=" << setw(6) << rd.Zd() << "re dAz=" << setw(6) << rd.Az() << "re" << endl; cout << " + Ratio: Zd=" << setw(6) << kGearRatio.X() << "se Az=" << setw(6) << kGearRatio.Y() << "se" << endl; */ // // repositioning (relative) // lout << "- Do Relative Positioning..." << endl; DoRelPos(rd, cdzd, cdaz); lout << "- Relative Positioning Done" << endl; } if (i==1 && track && !(Break() || HasError() || HasZombie())) { t.Now(); lout << t << " - Positioning done." << endl; SetStatus(MDriveCom::kStopped); return TRUE; } if (i<10) StopMovement(); else SetStatus(MDriveCom::kStopped); t.Now(); lout << t << " - Warning: Requested position not reached (i=" << dec << i << ")" << endl; return FALSE; } // -------------------------------------------------------------------------- // // 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 MCosy::SetVelocity(const ZdAz &v) { // // Send the new velocities for both axes. // fMac2->SendSDO(0x3006, 1, (LWORD_t)v.Zd()); // SetRpmVelocity [re/min] fMac1->SendSDO(0x3006, 1, (LWORD_t)v.Az()); // SetRpmVelocity [re/min] // // Wait for the objects to be acknoledged. // fMac2->WaitForSdo(0x3006, 1); fMac1->WaitForSdo(0x3006, 1); // // If the waiting for the objects wasn't interrupted return kTRUE // if (!(Break() || HasError() || HasZombie())) return kTRUE; // // print a message if the interruption was due to a Can-node Error // if (HasError()) lout << "Error while setting velocity (SDO #3006)" << endl; return kFALSE; } // -------------------------------------------------------------------------- // // 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 MCosy::InitTracking() { // FIXME? Handling of Zombie OK? if (fMac1->IsZombieNode() || fMac2->IsZombieNode()) return false; // // Start revolution mode // fMac2->SetAcceleration(0.1*fMac2->GetVelRes()); fMac2->SetDeceleration(0.1*fMac2->GetVelRes()); if (fMac2->IsZombieNode()) return false; fMac1->SetAcceleration(0.1*fMac1->GetVelRes()); fMac1->SetDeceleration(0.1*fMac1->GetVelRes()); if (fMac1->IsZombieNode()) return false; SetStatus(MDriveCom::kMoving | MDriveCom::kTracking); fMac2->SetRpmMode(TRUE); if (fMac2->IsZombieNode()) return false; fMac1->SetRpmMode(TRUE); if (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. // void MCosy::LimitSpeed(ZdAz *vt, const ZdAz &vcalc) const { // // 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 = fMac1->GetVelRes(); ULong_t vraz = 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 (sgn(vt->Az()) != sgn(vcalc.Az())) vt->Az(0); // else { if (fabs(vt->Az()) < fabs(vcalc.Az()) *0.5) vt->Az(0.5*vcalc.Az()); if (fabs(vt->Az()) > fabs(vcalc.Az()) *1.5) vt->Az(1.5*vcalc.Az()); } if (sgn(vt->Zd()) != sgn(vcalc.Zd())) vt->Zd(0); // else { if (fabs(vt->Zd()) > fabs(vcalc.Az()) *1.5) vt->Zd(1.5*vcalc.Zd()); if (fabs(vt->Zd()) < fabs(vcalc.Az()) *0.5) vt->Zd(0.5*vcalc.Zd()); } */ /* if (sgn(vt->Az()) != sgn(vcalc.Az()) && fabs(vt->Az()) < limit*fabs(vcalc.Az()) ) { lout << "Warning: Negative Azimuth speed limit (" << limit*100 << "%) exceeded... set to 0." << endl; vt->Az(0); } else*/ if (fabs(vt->Az()) > maxtrack*vraz) { lout << "Warning: Azimuth speed limit (" << maxtrack*100 << "%) exceeded... limited." << endl; vt->Az(maxtrack*vraz*sgn(vcalc.Az())); } /* if (sgn(vt->Zd()) != sgn(vcalc.Zd()) && fabs(vt->Zd()) < limit*fabs(vcalc.Zd()) ) { lout << "Warning: Negative Altitude speed limit (" << limit*100 << "%) exceeded... set to 0." << endl; vt->Zd(0); } else */ if (fabs(vt->Zd()) > maxtrack*vrzd) { lout << "Warning: Altitude speed limit (" << maxtrack*100 << "%) exceeded... limited." << endl; vt->Zd(maxtrack*vrzd*sgn(vcalc.Zd())); } } /* Bool_t MCosy::AlignTrackingPos(ZdAz pointing, ZdAz &za) const { // pointing [deg] if (pointing.Zd()<0) { pointing.Zd(-pointing.Zd()); pointing.Az(pointing.Az()+180); } const ZdAz se = GetSePos()*2*TMath::Pi()/16384; // [rad] const ZdAz unbendedse = fBending.CorrectBack(se)*kRad2Deg; // ist pointing do { const Double_t d = unbendedse.Az() - pointing.Az(); if (d>-180 && d<=180) break; pointing.Az(pointing.Az()+TMath::Sign(360., d)); } while (1); const Bool_t rc = CheckRange(pointing); za = pointing/kRad2Deg; // [rad] if (!rc) lout << "Error: Aligned position out of Range." << endl; return rc; } */ ZdAz MCosy::AlignTrackingPos(ZdAz pointing) const { // pointing [rad] // AlignTrackingPos [deg] pointing *= kRad2Deg; if (pointing.Zd()<0) { pointing.Zd(-pointing.Zd()); pointing.Az(pointing.Az()+180); } const ZdAz se = GetSePos()*2*TMath::Pi()/16384; // [rad] const ZdAz unbendedse = fBending.CorrectBack(se)*kRad2Deg; // ist pointing do { const Double_t d = unbendedse.Az() - pointing.Az(); if (d>-180 && d<=180) break; pointing.Az(pointing.Az()+TMath::Sign(360., d)); } while (1); return pointing/kRad2Deg; /* const Bool_t rc = CheckRange(pointing); za = pointing/kRad2Deg; // [rad] if (!rc) lout << "Error: Aligned position out of Range." << endl; return rc;*/ } Double_t MCosy::Starguider(Double_t mjd, ZdAz &dest) const { ifstream fin("pointingpos.txt"); if (!fin) return -1; Double_t mjd0, zd, az; fin >> mjd0 >> zd >> az; mjd0 += 52000; if (mjd0+1./24/60 5 || diff.Az()>5) { cout << "Starguider deviation too large... dZd=" << diff.Zd() <<" dAz="<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 = GetSePos()*kGearRatio; if (!RequestRePos()) return; // // Estimate Offset before starting to track // fOffset = sepos-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()) { StopMovement(); return; } XY xy(Rad2Deg(dst.Ra())*24/360, Rad2Deg(dst.Dec())); sla.Now(); lout << sla << " - 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) // fRaDec = dst; fBackground = kBgdTracking; //--- ofstream fout("log/cosy.pos"); //--- fout << "Tracking:"; //--- fout << " Ra: " << Rad2Deg(dst.Ra()) << "\x9c "; //--- fout << "Dec: " << Rad2Deg(dst.Dec()) << "\x9c" << endl << endl; //--- fout << " Mjd/10ms V/re/min/4" << endl; // // We want to reach the theoretical position exactly in about 0.5s // // *OLD*const float dt = 1; // 1 second const float dt = 5;//3; // 2 second while (!(Break() || HasError() || HasZombie())) { // // Request Target position for this moment // sla.Now(); // // Request theoretical Position for a time in the future (To+dt) from CPU // const Double_t mjd = sla.GetMjd()+dt/(60*60*24); const ZdAz pointing = sla.CalcZdAz(fRaDec, mjd); // soll pointing [deg] /* ZdAz dest; if (!AlignTrackingPos(pointing, dest)) break; */ ZdAz dest = AlignTrackingPos(pointing); ZdAz vcalc = sla.GetApproxVel(fRaDec) * kGearRatio2*4./60.; // [re/min] float dtime = -1; if (kFALSE /*fUseStarguider*/) dtime = Starguider(mjd, dest); if (dtime<0) { dest = fBending(dest); // [rad] if (!CheckRange(dest)) break; dest *= 16384/TMath::Pi()/2; // [se] dest *= kGearRatio; // [re] // // Request absolute position of rotary encoder from Macs // if (!RequestRePos()) break; // // distance between (To+dt) and To [re] // position time difference < 5usec // fOffset does the synchronization between the // Shaft- and the rotary encoders dest -= GetRePos() + fOffset; dtime = dt; } // // 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; LimitSpeed(&vt, vcalc); vt.Round(); // // check if the drive is fast enough to follow the star // if (vt.Zd()>.9*fMac1->GetVelRes() || vt.Az()>.9*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 // if (!SetVelocity(vt)) break; // // Now do 'unnecessary' things // fVelocity = vt/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(); fBackground = kBgdNone; StopMovement(); lout << sla << " - Tracking stopped." << endl; } // -------------------------------------------------------------------------- // // Stops the movement of both motors. // // Sets the status to stopping. Sets the deceleration to 50% of the maximum. // stops. Quits the revolution mode and wait for the end of the movement. // void MCosy::StopMovement() { // // Set status to Stopping // SetStatus(MDriveCom::kStopping); // // set deceleration to 50% // cout << "Stopping movement (dec=30%)..." << endl; if (fMac1 && fMac2) { #ifdef EXPERT fMac1->SetDeceleration(0.5*fMac1->GetVelRes()); fMac2->SetDeceleration(0.5*fMac2->GetVelRes()); #else fMac1->SetDeceleration(0.3*fMac1->GetVelRes()); fMac2->SetDeceleration(0.3*fMac2->GetVelRes()); #endif fMac1->SetRpmMode(FALSE); fMac2->SetRpmMode(FALSE); } /* fMac1->SetDeceleration(0.3*fMac1->GetVelRes()); fMac2->SetDeceleration(0.3*fMac2->GetVelRes()); fMac2->SendSDO(0x3000, Macs::string('s','t','o','p')); fMac1->SendSDO(0x3000, Macs::string('s','t','o','p')); fMac2->WaitForSdo(0x3000, 0); fMac1->WaitForSdo(0x3000, 0); fMac1->SetRpmMode(FALSE); fMac2->SetRpmMode(FALSE); */ // // Wait for the movement to really be finished. // #ifdef EXPERT cout << "Waiting for end of movement..." << endl; #endif WaitForEndMovement(); // // Check whether everything works fine. // CheckForError(); #ifdef EXPERT cout << "Movement stopped." << endl; #endif } void MCosy::StopTracking() { // // Set status to Stopping // SetStatus(MDriveCom::kStopping); // // set deceleration to 50% // cout << "Stopping tracking (dec=20%)..." << endl; fMac1->SetDeceleration(0.2*fMac1->GetVelRes()); fMac2->SetDeceleration(0.2*fMac2->GetVelRes()); fMac2->SendSDO(0x3006, 1, (LWORD_t)0); // SetRpmVelocity [re/min] fMac1->SendSDO(0x3006, 1, (LWORD_t)0); // SetRpmVelocity [re/min] fMac2->WaitForSdo(0x3006, 1); fMac1->WaitForSdo(0x3006, 1); cout << "Waiting for end of movement..." << endl; WaitForEndMovement(); // // Wait for the objects to be OKed. // fMac1->SetRpmMode(FALSE); fMac2->SetRpmMode(FALSE); // // Wait for the movement to really be finished. // //cout << "Waiting for end of movement..." << endl; //WaitForEndMovement(); // // Check whether everything works fine. // CheckForError(); cout << "Movement stopped." << endl; } bool MCosy::CheckNetwork() { //return kTRUE; //CheckConnections(); CheckForError(); if (HasZombie()) { lout << "- Found Zombies in Network..." << endl; if (!RebootZombies()) return false; } /* FIXME HANDLING ERROR */ if (HasError()) { fMac1->HandleError(); fMac2->HandleError(); fMac3->HandleError(); if (HasError() || HasZombie()) return false; } CheckForError(); return true; } void *MCosy::Proc(int msg, void *mp) { switch (msg) { case WM_WAIT: cout << "Wait for execution of Proc(WM_*, ): done." << endl; return NULL; case WM_STOP: cout << "MCosy::Proc: Stop." << endl; if (!CheckNetwork()) return (void*)0xebb0; StopMovement(); return NULL; /* case WM_PRESET: cout << "WM_Preset: start." << endl; if (!CheckNetwork()) return (void*)0xebb0; fZd1->SetPreset(); fZd2->SetPreset(); fAz->SetPreset(); cout << "WM_Preset: done. (return 0xaffe)" << endl; return (void*)0xaffe; */ /* case WM_CALIB: { cout << "WM_Calib: start." << endl; if (!CheckNetwork()) return (void*)0xebb0; SlaStars sla(fObservatory); sla.Now(); RaDec rd = *((RaDec*)mp); //RaDec rd(37.94, 89.2644); // POLARIS //RaDec rd(213.915417, 19.1825); // ARCTURUS cout << "Calibrating to: " << rd.Ra()*24/360 << "h " << rd.Dec() << "°" << endl; ZdAz za=sla.CalcZdAz(rd*kDeg2Rad)*16384.0/k2Pi; cout << "Calc Zd: " << za.Zd() << " Az: " << za.Az() << endl; ZdAz sepos = GetSePos(); cout << "Got Zd: " << sepos.Zd() << " Az: " << sepos.Az() << endl; fZd1->SetPreset(za.Zd()); fZd2->SetPreset(-za.Zd()); fAz->SetPreset(za.Az()); cout << "WM_Calib: done. (return 0xaffe)" << endl; } return (void*)0xaffe; */ case WM_TPOINT: { cout << "WM_TPoint: start." << endl; SlaStars sla(fObservatory); sla.Now(); RaDec rd = *((RaDec*)mp); cout << "TPoint Star: " << rd.Ra()/15 << "h " << rd.Dec() << "°" << endl; AltAz za=sla.CalcAltAz(rd*kDeg2Rad)*kRad2Deg; cout << " Alt/Az: " << za.Alt() << "° " << za.Az() << "°" << endl; *tpout << setprecision(7) << za.Az() << " " << za.Alt() << " "; ZdAz sepos = GetSePos()*TMath::Pi()*2/16384;; za.Set(TMath::Pi()/2-sepos.Zd(), sepos.Az()); za *= kRad2Deg; cout << " SE-Pos: " << za.Alt() << "° " << za.Az() << "°" << endl; *tpout << fmod(za.Az()+360, 360) << " " << za.Alt() << " "; if (fStarguider) { XY tp = fStarguider->GetCoordinates(); *tpout << 90-tp.X() << " " << tp.Y() << " "; } *tpout << rd.Ra()/15 << " " << rd.Dec() << " " << setprecision(11) << sla.GetMjd() << endl; cout << "WM_TPoint: done. (return 0xaffe)" << endl; } return (void*)0xca1b; case WM_TRACKPOS: cout << "WM_TrackPosition: start." << endl; { if (!CheckNetwork()) return (void*)0xebb0; ZdAz dest = *((ZdAz*)mp) * kDeg2Rad; //if (!SetPosition(dest)) // return (void*)0x1234; SlaStars sla(fObservatory); sla.Now(); RaDec rd = sla.CalcRaDec(dest); cout << dest.Zd()*180/3.1415 << " " << dest.Az()*180/3.1415 << endl; cout << rd.Ra()*12/3.1415 << " " << rd.Dec()*180/3.1415 << endl; TrackPosition(rd); } cout << "WM_TrackPosition: done. (return 0xabcd)" << endl; return (void*)0xabcd; case WM_POSITION: cout << "WM_Position: start." << endl; { //if (!CheckNetwork()) // return (void*)0xebb0; ZdAz dest = *((ZdAz*)mp); SetPosition(dest*kDeg2Rad); } cout << "WM_Position: done. (return 0x7777)" << endl; return (void*)0x7777; case WM_POSITION1: cout << "WM_Position1: start." << endl; { if (!CheckNetwork()) return (void*)0xebb0; ZdAz dest = *((ZdAz*)mp); SetPosition(dest*kDeg2Rad, kTRUE); } cout << "WM_Position: done. (return 0x7777)" << endl; return (void*)0x7777; case WM_TESTSE: cout << "WM_TestSe: start." << endl; fBackground = mp ? kBgdSeTest : kBgdNone; cout << "WM_TestSe: done. (return 0x1e51)" << endl; return (void*)0x1e51; case WM_GEAR: cout << "WM_Gear: start." << endl; fBackground = mp ? kBgdGear : kBgdNone; cout << "WM_Gear: done. (return 0xfeaf)" << endl; return (void*)0xfeaf; case WM_DISPLAY: cout << "WM_Display: start." << endl; fTriggerDisplay = kTRUE; cout << "WM_Disply: done. (return 0xd1e1)" << endl; return (void*)0xd1e1; case WM_TRACK: cout << "WM_Track: START" << endl; { RaDec dest = ((RaDec*)mp)[0]; if (fStarguider) fStarguider->SetPointingPosition(((RaDec*)mp)[1]); if (!CheckNetwork()) return (void*)0xebb0; TrackPosition(dest*kDeg2Rad); } cout << "WM_Track: done. (return 0x8888)" << endl; return (void*)0x8888; case WM_NEWTRACK: cout << "WM_NewTrack: START" << endl; fRaDec = *((RaDec*)mp); cout << "WM_NewTrack: done. (return 0x9999)" << endl; return (void*)0x9999; case WM_LOADBENDING: cout << "WM_LoadBending: START" << endl; fBending.Load("bending.txt"); cout << "WM_LoadBending: done. (return 0xbe0d)" << endl; return (void*)0xbe0d; case WM_RESETBENDING: cout << "WM_ResetBending: START" << endl; fBending.Reset(); cout << "WM_ResetBending: done. (return 0xbe0e)" << endl; return (void*)0xbe0e; case WM_HOME: cout << "WM_Home: START" << endl; if (!CheckNetwork()) return (void*)0xebb0; else { cout << "HOME NOT ALLOWED... for Magic." << endl; /* cout << "Going Home..." << endl; TEnv env(".cosyrc"); SetStatus(MDriveCom::kMoving); fMac1->SetHome(250000, env.GetValue("Az_MaxTime2ReachHome[s]", 100)); fMac2->SetHome(250000, env.GetValue("Zd_MaxTime2ReachHome[s]", 100)); lout << "SETHOME DONE" << endl; SetStatus(HasError() ? MDriveCom::kError : MDriveCom::kStopped); fAz->SetPreset(); fZd1->SetPreset(); fZd2->SetPreset(); fMac1->ReqPos(); fMac2->ReqPos(); fMac3->StopMotor(); */ } cout << "WM_Home: done. (return 0x403e)" << endl; return (void*)0x403e; case WM_CALCALTAZ: { cout << endl; SlaStars sla(fObservatory); sla.Now(); XY xy = *((XY*)mp); RaDec rd(xy.X()*15., xy.Y()); // [deg] ZdAz a1 = sla.CalcZdAz(rd*kDeg2Rad); // [rad] cout << "Ra/Dec source: " << xy.X() << "h " << xy.Y() << "°" << endl; cout << "Zd/Az target: " << a1.Zd()*kRad2Deg << "° " << a1.Az()*kRad2Deg << "°" << endl; if (fZd1 && fZd2 && fAz) a1 = AlignTrackingPos(a1); a1 = fBending(a1); CheckRange(a1); a1 *= kRad2Deg; const ZdAz a2 = a1*16384/360; cout << "Zd/Az bended: " << a1.Zd() << "° " << a1.Az() << "°" << endl; cout << "SE bended: " << a2.Zd() << " " << a2.Az() << endl; } return (void*)0xa17a; case WM_ENDSWITCH: { ZdAz pos = GetSePos()*TMath::Pi()*2/16384; pos = fBending.SubtractOffsets(pos)*kRad2Deg; cout << "Endswitch Position: Zd=" << pos.Zd() << "° Az="; cout << pos.Az() << "°" << endl; } return (void*)0x1010; case WM_QUIT: cout << "WM_Quit: now." << endl; if (!CheckNetwork()) { lout << "ERROR: Cannot shutdown CANbus network." << endl; return (void*)0xebb0; } TerminateApp(); cout << "WM_Quit: done." << endl; return (void*)0xaaaa; } cout << "MCosy::Proc: Unknown message 0x" << msg << endl; return (void*)0xffffffff; } void *MTTalk::Thread() { fCosy->TalkThread(); return NULL; } void MCosy::ReadConfig() { cout << "Reading configuration file..." << flush; TEnv env(".cosyrc"); cout << "done." << endl; cout << "Reading telescope range..." << flush; const Double_t amin = env.GetValue("Az_Min[deg]", -95.0); const Double_t zmin = env.GetValue("Zd_Min[deg]", -75.0); fMin.Set(zmin, amin); const Double_t amax = env.GetValue("Az_Max[deg]", 305.0); const Double_t zmax = env.GetValue("Zd_Max[deg]", 98.25); fMax.Set(zmax, amax); cout << "done." << endl; cout << " * Min: " << zmin << "deg " << amin << "deg" << endl; cout << " * Max: " << zmax << "deg " << amax << "deg" << endl; fMin = fBending.AddOffsets(fMin/kRad2Deg); fMax = fBending.AddOffsets(fMax/kRad2Deg); cout << " * Min': " << fMin.Zd()*kRad2Deg << "deg " << fMin.Az()*kRad2Deg << "deg" << endl; cout << " * Max': " << fMax.Zd()*kRad2Deg << "deg " << fMax.Az()*kRad2Deg << "deg" << endl; cout << "Reading gear ratios..." << flush; const Double_t gaz = env.GetValue("Az_GearRatio[U_mot/U_tel]", 1000.0); const Double_t gzd = env.GetValue("Zd_GearRatio[U_mot/U_tel]", 1000.0); Double_t resreaz = 0; if (fMac1 && !fMac1->IsZombieNode()) resreaz = fMac1->GetRes(); else if (fMac3 && !fMac3->IsZombieNode()) resreaz = fMac3->GetRes(); else resreaz = env.GetValue("Az_ResRE[re/U_mot]", 1500); Double_t resrezd = 0; if (fMac2 && !fMac2->IsZombieNode()) resrezd = fMac2->GetRes(); else resrezd = env.GetValue("Zd_ResRE[re/U_mot]", 1500); Double_t ressezd = 0; if (fZd1 && !fZd1->IsZombieNode()) ressezd = fZd1->GetPhysRes(); else if (fZd2 && !fZd2->IsZombieNode()) ressezd = fZd2->GetPhysRes(); else ressezd = env.GetValue("Zd_ResSE[se/U_mot]", 16384); Double_t resseaz = 0; if (fAz && !fAz->IsZombieNode()) resseaz = fAz->GetPhysRes(); else resseaz = env.GetValue("Az_ResSE[se/U_mot]", 16384); kGearRatio.Set (gzd*resrezd*4/ressezd, gaz*resreaz*4/resseaz); //[re/se] kGearRatio2.Set(gzd*resrezd*4/360.0, gaz*resreaz*4/360.0); //[re/deg] cout << "done." << endl; cout << " * Setting Gear Ratios:" << endl; cout << " --------------------" << endl; cout << " * X: " << gzd << "*" << resrezd << "/" << ressezd << "=4*" << kGearRatio.X() << endl; cout << " * Y: " << gaz << "*" << resreaz << "/" << resseaz << "=4*" << kGearRatio.Y() << endl; } void MCosy::InitSync() { if (!fMac3) { lout << "Unable to Init Sync! Mac3 not available." << endl; return; } const int res = fMac3->GetVelRes(); fMac3->SetVelocity(0.3*res); fMac3->SetAcceleration(0.2*res); fMac3->SetDeceleration(0.2*res); fMac3->StartPosSync(); } void MCosy::TalkThreadTracking() { if (fZd1->IsZombieNode() && fZd2->IsZombieNode()) return; if (fAz->IsZombieNode()) return; if (!fMac1 || !fMac2) return; lout << "- Tracking Thread started..." << endl; SlaStars sla(fObservatory); sla.Now(); ZdAz old; ZdAz ist = GetSePos(); // [se] ZdAz time; ZdAz sollzd = sla.CalcZdAz(fRaDec); // [rad] ZdAz sollaz = sollzd; // [rad] // // only update fTrackingError while tracking // bool phca1=false; bool phca2=false; bool phcaz=false; while (fBackground==kBgdTracking) { // // 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) // fZd1->ResetPosHasChanged(); fZd2->ResetPosHasChanged(); fAz->ResetPosHasChanged(); do { phca1 = fZd1->PosHasChanged(); phca2 = fZd2->PosHasChanged(); phcaz = fAz->PosHasChanged(); usleep(1); } while (!phca1 && !phca2 && !phcaz && fBackground==kBgdTracking); //---usleep(100000); // 0.1s // // get position, where we are // old = ist; ist = 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 = GetRePosPdo(); // // Get time from last shaftencoder position change (position: ist) // FIXME: I cannot take the avarage // // FIXME //time.Zd(fZd1->GetMjd()); /* OLD* */ if (fZd1->GetMjd()>fZd2->GetMjd()) time.Zd(fZd1->GetMjd()); else time.Zd(fZd2->GetMjd()); //time.Zd((fZd1->GetMjd()+fZd2->GetMjd())/2.0); time.Az(fAz->GetMjd()); // // if Shaftencoder changed position // calculate were we should be // if (phca1 || phca2 /*(int)ist.Zd() != (int)old.Zd()*/) { sollzd = sla.CalcZdAz(fRaDec, time.Zd()); // [rad] /* ZdAz dummy = fBending(sla.CalcZdAz(fRaDec)); sollzd = CorrectTarget(ist, dummy); // [se] */ fOffset.Zd(fOffset.Zd()*(1.-weight)+(ist.Zd()*kGearRatio.X()-istre.Zd())*weight); } if (phcaz /*(int)ist.Az() != (int)old.Az()*/) { sollaz = sla.CalcZdAz(fRaDec, time.Az()); // [rad] /* ZdAz dummy = fBending(sla.CalcZdAz(fRaDec)); sollaz = CorrectTarget(ist, dummy); // [se] */ fOffset.Az(fOffset.Az()*(1.-weight)+(ist.Az()*kGearRatio.Y()-istre.Az())*weight); } ZdAz soll(sollzd.Zd(), sollaz.Az()); // [rad] fZdAzSoll = AlignTrackingPos(soll); ist *= TMath::Pi()*2/16384; soll = fBending(fZdAzSoll); 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; //--- fout << endl << endl; } void MCosy::TalkThreadSeTest() { // if (fZd1->IsZombieNode() || fZd2->IsZombieNode()) // return; if (fHist) { lout << "You are much too fast... try again." << endl; return; } fHist = new TH2F("Diff", "Difference of SE values", 201, fMin.Zd(), fMax.Zd(), 41, -10.5, 10.5); fHist->SetXTitle("ZA [\\circ]"); fHist->SetYTitle("\\Delta SE"); Double_t offset = 0; int cnt = 0; lout << "Starting Shaftencoder Test..." << endl; while (fBackground==kBgdSeTest) { fZd1->ResetPosHasChanged(); fZd2->ResetPosHasChanged(); while (!fZd1->PosHasChanged() && !fZd2->PosHasChanged() && fBackground==kBgdSeTest) usleep(1); const Double_t pos[3] = { (fZd1->GetPos()+8192)%16384, (fZd2->GetPos()+8192)%16384, fAz->GetPos() }; // // Estimate Offset from the first ten positions // if (cnt++<10) { offset += pos[0]+pos[1]; continue; } if (cnt==11) { offset /= 10; cnt++; } Double_t apos = (pos[0]-pos[1])/2 * TMath::Pi()*2 / 16384; ZdAz bend = fBending.CorrectBack(ZdAz(apos, pos[2]))*kRad2Deg; fHist->Fill(bend.Zd(), pos[0]+pos[1]-offset); } lout << "Shaftencoder Test Stopped... displaying Histogram." << endl; fBackground=kBgdSeTestDispl; } void MCosy::TalkThreadGear() { // if (fZd1->IsZombieNode() || fZd2->IsZombieNode()) // return; if (fHist) { lout << "You are much too fast... try again." << endl; return; } fHist = new TH3F("Gear", "Gear Ratio Re/Se", (int)((fMax.Zd()-fMin.Zd())/2.5+1), fMin.Zd(), fMax.Zd(), (int)((fMax.Az()-fMin.Az())/2.5+1), fMin.Az(), fMax.Az(), 61, 349.5, 500.5); fHist->SetXTitle("Zd [\\circ]"); fHist->SetYTitle("Az [\\circ]"); fHist->SetZTitle("Re/Se"); lout << "Starting Gear determination..." << endl; ZdAz se0 = GetSePos(); ZdAz re0 = GetRePosPdo(); while (fBackground==kBgdGear) { fZd1->ResetPosHasChanged(); fZd2->ResetPosHasChanged(); fAz->ResetPosHasChanged(); while (!fZd1->PosHasChanged() && !fZd2->PosHasChanged() && !fAz->PosHasChanged() && fBackground==kBgdGear) usleep(1); ZdAz se = GetSePos(); ZdAz re = GetRePosPdo(); ZdAz dse = se-se0; ZdAz dre = re-re0; if (fabs(dse.Zd())*144>16384) // Each 2.5deg (144) { se0.Zd(se.Zd()); re0.Zd(re.Zd()); se -= dse/2; ZdAz bend = fBending.CorrectBack(se*2*TMath::Pi()/16384)*kRad2Deg; ((TH3*)fHist)->Fill(bend.Zd(), bend.Az(), dre.Zd()/dse.Zd()); } if (fabs(dse.Az())*144>16384) // Each 2.5deg (144) { se0.Az(se.Az()); re0.Az(re.Az()); se -= dse/2; ZdAz bend = fBending.CorrectBack(se*2*TMath::Pi()/16384)*kRad2Deg; ((TH3*)fHist)->Fill(bend.Az(), bend.Az(), dre.Az()/dse.Az()); } } lout << "Gear Test Stopped... displaying Histogram." << endl; fBackground=kBgdGearDispl; } void MCosy::TalkThread() { /* ========== FIXME? ============= if (fMac1->IsZombieNode() || fMac2->IsZombieNode()) return; */ if (fMac1 && fMac2) { fMac1->ReqPos(); fMac2->ReqPos(); } InitSync(); /*** FOR DEMO MODE ***/ if (!fZd1 || !fZd2 || !fAz) return; /*** FOR DEMO MODE ***/ // // Start the Network // while (1) { // // wait until a tracking session is started // while (fBackground==kBgdNone) usleep(1); switch (fBackground) { case kBgdNone: continue; case kBgdTracking: TalkThreadTracking(); continue; case kBgdSeTest: TalkThreadSeTest(); continue; case kBgdGear: TalkThreadGear(); continue; default: continue; } } } ZdAz MCosy::GetPointingPos() const { if (fZd1->IsZombieNode() || fZd2->IsZombieNode() || fAz->IsZombieNode()) return ZdAz(0, 0); // GetPointingPos [deg] const ZdAz seist = GetSePos()*2*TMath::Pi()/16384; // [se] cout << seist.Zd()*kRad2Deg << " " << seist.Az()*kRad2Deg << endl; ZdAz back = fBending.CorrectBack(seist)*180/TMath::Pi(); cout << back.Zd() << " " << back.Az() << endl; return back; } Bool_t MCosy::HandleTimer(TTimer *t) { // // Update Gui, foremer MTGui. // if (fZd1) fZd1->DisplayVal(); if (fZd2) fZd2->DisplayVal(); if (fAz) fAz->DisplayVal(); ZdAz bendist = GetPointingPos(); Byte_t avail = 0; avail |= (fMac1 && !fMac1->IsZombieNode()) ? 0x01 : 0; avail |= (fMac2 && !fMac2->IsZombieNode()) ? 0x02 : 0; avail |= (fMac3 && !fMac3->IsZombieNode()) ? 0x04 : 0; avail |= (fZd1 && !fZd1->IsZombieNode()) ? 0x08 : 0; avail |= (fZd2 && !fZd2->IsZombieNode()) ? 0x10 : 0; avail |= (fAz && !fAz->IsZombieNode()) ? 0x20 : 0; if (HasError()) SetStatus(MDriveCom::kError); lout.UpdateGui(); fWin->Update(bendist, fTrackingError, fVelocity, /*fOffset,*/ fRaDec, fZdAzSoll, fStatus, avail); const Bool_t trigger = fTriggerDisplay; fTriggerDisplay = kFALSE; if (fBackground==kBgdSeTestDispl || (trigger&&fBackground==kBgdSeTest)) DisplayHistTestSe(!trigger); if (fBackground==kBgdGearDispl || (trigger&&fBackground==kBgdGear)) DisplayHistGear(!trigger); // FIXME: Not thread safe! static int i=0; if (i++==7) { fCom->SendReport(fStatus, fRaDec, fZdAzSoll, bendist, fTrackingError); i=0; } return kTRUE; } void MCosy::DisplayHistTestSe(Bool_t del) { lout << "Displaying histogram..." << endl; TH2F &hist = *(TH2F*)fHist; if (del) { fHist = NULL; fBackground = kBgdNone; } TCanvas *c=new TCanvas("c1", "", 1000, 1000); c->Divide(1,2); c->cd(1); TH2 *h=(TH2*)hist.DrawCopy(); TProfile *p = h->ProfileX("_pfx", -1, 9999, "s"); p->SetLineColor(kBlue); p->Draw("same"); p->SetBit(kCanDelete); c->cd(2); TH1F p2("spread", "Spread of the differences", hist.GetNbinsX(), hist.GetBinLowEdge(1), hist.GetBinLowEdge(hist.GetNbinsX()+1)); p2.SetXTitle("Zd [\\circ]"); for (int i=0; iGetBinError(i)); p2.SetLineColor(kRed); p2.SetStats(0); p2.DrawCopy(); if (del) delete &hist; } void MCosy::DisplayHistGear(Bool_t del) { lout << "Displaying histogram..." << endl; TH3F &hist = *(TH3F*)fHist; if (del) { fHist = NULL; fBackground = kBgdNone; } TCanvas *c=new TCanvas("c1", "", 1000, 1000); c->Divide(2,2); // ---------- c->cd(1); TH2D &h1=*(TH2D*)hist.Project3D("zx"); // Zd h1.SetTitle(" Gear Ratio Zenith Distance [re/se] "); h1.SetXTitle("Zd [\\circ]"); h1.Draw(); h1.SetBit(kCanDelete); TProfile *p1 = h1.ProfileX("_pfx", -1, 9999, "s"); p1->SetLineColor(kBlue); p1->Draw("same"); p1->SetBit(kCanDelete); // ---------- c->cd(2); TH2D &h2=*(TH2D*)hist.Project3D("zy"); // Az h2.SetTitle(" Gear Ratio Azimuth [re/se] "); h2.SetXTitle("Zd [\\circ]"); h2.Draw(); h2.SetBit(kCanDelete); TProfile *p2 = h2.ProfileX("_pfx", -1, 9999, "s"); p2->SetLineColor(kBlue); p2->Draw("same"); p2->SetBit(kCanDelete); // ---------- c->cd(3); TAxis &axe1 = *h1.GetXaxis(); TH1F f1("spreadzd", " Spread Zenith Distance ", axe1.GetNbins(), axe1.GetXmin(), axe1.GetXmax()); f1.SetXTitle("Zd [\\circ]"); for (int i=0; iGetBinError(i)); f1.SetLineColor(kRed); f1.SetStats(0); f1.DrawCopy(); c->cd(4); // ---------- TAxis &axe2 = *h2.GetXaxis(); TH1F f2("spreadaz", " Spread Azimuth ", axe2.GetNbins(), axe2.GetXmin(), axe2.GetXmax()); f2.SetXTitle("Az [\\circ]"); for (int i=0; iGetBinError(i)); f2.SetLineColor(kRed); f2.SetStats(0); f2.DrawCopy(); // ---------- if (del) delete &hist; } // -------------------------------------------------------------------------- // // Start the work of the application: // // Start the Can-Network. // Start the MCosy::TalkThread thread. // turn on the gui update // void MCosy::Start() { // Don't call this function twice! Network::Start(); CheckForError(); ReadConfig(); lout << "- Starting TX Thread." << endl; fTTalk = new MTTalk(this); lout << "- Starting GUI update." << endl; fUpdateGui->TurnOn(); } // -------------------------------------------------------------------------- // // Start the work of the application: // // Turn of the gui update // stop the MCosy::TalkThread thread. // Stop the network // void MCosy::Stop() { lout << "- Stopping GUI update." << endl; fUpdateGui->TurnOff(); lout << "- GUI Update stopped." << endl; delete fTTalk; lout << "- TX Thread stopped." << endl; Network::Stop(); } // -------------------------------------------------------------------------- // // Disable the synchronization by using a negative CAN Id for id2. // void MCosy::Constructor(Int_t id1, Int_t id2, Int_t id3, Int_t id4, Int_t id5, Int_t id6) { // // Create Nodes // lout << "- Setting up network." << endl; fMac1=new Macs(id1, "Mac/Az", lout); fMac2=new Macs(id3, "Mac/Zd", lout); if (id2>=0) fMac3=new Macs(id2, "Mac/Az-Sync", lout); fZd1=new ShaftEncoder(id4, "SE/Zd1", lout); fZd2=new ShaftEncoder(id5, "SE/Zd2", lout); fAz =new ShaftEncoder(id6, "SE/Az", lout); lout << "- Connecting devices to network." << endl; // // Connect the devices to the network // SetNode(fMac1); SetNode(fMac2); if (id2>=0) SetNode(fMac3); SetNode(fZd1); SetNode(fZd2); SetNode(fAz); // // Create Gui Event timer and Gui // lout << "- Initializing GUI Timer." << endl; fUpdateGui = new TTimer(this, 100); // 100ms lout << "- Starting GUI." << endl; fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1); } void MCosy::ConstructorSE(Int_t id4, Int_t id5, Int_t id6) { // // Create Nodes // lout << "- Setting up network." << endl; fZd1=new ShaftEncoder(id4, "SE/Zd1", lout); fZd2=new ShaftEncoder(id5, "SE/Zd2", lout); fAz =new ShaftEncoder(id6, "SE/Az", lout); lout << "- Connecting devices to network." << endl; // // Connect the devices to the network // SetNode(fZd1); SetNode(fZd2); SetNode(fAz); // // Create Gui Event timer and Gui // lout << "- Initializing GUI Timer." << endl; fUpdateGui = new TTimer(this, 100); // 100ms lout << "- Starting GUI." << endl; fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1); } void MCosy::ConstructorDemo() { // // Create Nodes // lout << "- Setting up network." << endl; // // Create Gui Event timer and Gui // lout << "- Initializing GUI Timer." << endl; fUpdateGui = new TTimer(this, 100); // 100ms lout << "- Starting GUI." << endl; fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1); } MCosy::MCosy(int mode, const char *dev, const int baud, MLog &out) : Network(dev, baud, out), fObservatory(MObservatory::kMagic1), fStarguider(NULL), fZd1(0), fZd2(0), fAz(0), fMac1(0), fMac2(0), fMac3(0), fBackground(kBgdNone), fStatus(MDriveCom::kStopped) { TEnv env(".cosyrc"); const Int_t id1 = env.GetValue("Az_Id-MAC1", 1); //1 const Int_t id2 = env.GetValue("Az_Id-MAC2", 2); //2 const Int_t id3 = env.GetValue("Zd_Id-MAC", 3); //3 const Int_t id4 = env.GetValue("Zd_Id-SE1", 4); //4 const Int_t id5 = env.GetValue("Zd_Id-SE2", 5); //5 const Int_t id6 = env.GetValue("Az_Id-SE", 6); //6 lout << "- Program in "; switch (mode) { case 0: lout << "<>" << endl; fBending.Load("bending.txt"); Constructor(id1, id2, id3, id4, id5, id6); break; case 1: lout << "<>" << endl; fBending.Load("bending.txt"); ConstructorSE(id4, id5, id6); break; default: lout << "<>" << endl; ConstructorDemo(); } lout.SetOutputGui(fWin->GetLog(), kTRUE); fZd1->SetDisplay(fWin->GetLabel2()); fZd2->SetDisplay(fWin->GetLabel3()); fAz->SetDisplay(fWin->GetLabel1()); int i=0; char name[100]; while (1) { sprintf(name, "tpoint/tpoint%03d.txt", i++); if (gSystem->AccessPathName(name, kFileExists)) break; } Timer time; time.Now(); cout << "TPoint File ********* " << name << " ********** " << endl; tpout = new ofstream(name); *tpout << "Magic Model TPOINT data file" << endl; *tpout << ": ALTAZ" << endl; *tpout << "49 48 0 "; *tpout << time.Year() << " " << time.Month() << " " << time.Day() << " "; *tpout << /*"20 1013.25 300 0.5 0.55 0.0065" <<*/ endl; // temp(°C) pressure(mB) height(m) humidity(1) wavelength(microm) troplapserate(K/m) fCom = new MDriveCom(this, out); fCom->Start(); } void MCosy::TerminateApp() { cout << "MCosy::TerminateApp()" << endl; /* Int_t rc; TGMessageBox msg(this, gClient->GetRoot(), "Information", "Cosy is shutting down the system - this may take wa while!", kMBIconExclamation, kMBOK, //kMBClose &rc, 0); */ lout.DisableOutputDevice(MLog::eGui); // FIXME: WHY DOES THIS CRASH THE APPLICATIOn WHILE TRAKING? // lout.SetOutputGui(NULL, kFALSE); gApplication->Terminate(0); } MCosy::~MCosy() { *tpout << "END" << endl; //streampos size = tpout.tellp(); delete tpout; cout << "Deleting GUI timer." << endl; delete fUpdateGui; delete fCom; cout << "Deleting Nodes." << endl; delete fAz; delete fZd1; delete fZd2; delete fMac1; delete fMac2; if (fMac3) delete fMac3; cout << "Deleting MGCosy." << endl; lout.DisableOutputDevice(MLog::eGui); delete fWin; cout << "MGCosy destructed." << endl; }