source: trunk/MagicSoft/Cosy/main/MTracking.cc@ 4103

Last change on this file since 4103 was 4076, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 15.9 KB
Line 
1#include "MTracking.h"
2
3#include "macs.h"
4#include "shaftencoder.h"
5
6#include "MCosy.h"
7#include "SlaStars.h"
8
9#include "MDriveCom.h"
10
11ClassImp(MTracking);
12
13//#define EXPERT
14#undef EXPERT
15
16// --------------------------------------------------------------------------
17//
18// request the current positions from the rotary encoders.
19// use GetRePos to get the psotions. If the request fails the function
20// returns kFALSE, otherwise kTRUE
21//
22bool MTracking::RequestRePos()
23{
24 //
25 // Send request
26 //
27 fCosy->fMac2->RequestSDO(0x6004);
28 fCosy->fMac1->RequestSDO(0x6004);
29
30 //
31 // Wait until the objects are received.
32 //
33 fCosy->fMac2->WaitForSdo(0x6004);
34 fCosy->fMac1->WaitForSdo(0x6004);
35
36 //
37 // If waiting was not interrupted everything is ok. return.
38 //
39 if (!Break())
40 return true;
41
42 //
43 // If the waiting was interrupted due to a network error,
44 // print some logging message.
45 //
46 if (fCosy->HasError())
47 lout << "Error while requesting re pos from Macs (SDO #6004)" << endl;
48
49 return false;
50}
51
52// --------------------------------------------------------------------------
53//
54// Initializes Tracking mode
55//
56// Initializes the accelerations of both axes with 90% of the maximum
57// acceleration. Set the status for moving and tracking and starts thr
58// revolution mode.
59//
60bool MTracking::InitTracking()
61{
62 // FIXME? Handling of Zombie OK?
63 if (fCosy->fMac1->IsZombieNode() || fCosy->fMac2->IsZombieNode())
64 return false;
65
66 //
67 // Start revolution mode
68 //
69 if (!SetAccDec(fCosy->fMac2, fTrackAcc, fTrackDec))
70 return false;
71
72 if (!SetAccDec(fCosy->fMac1, fTrackAcc, fTrackDec))
73 return false;
74
75 fCosy->SetStatus(MDriveCom::kMoving | MDriveCom::kTracking);
76
77 fCosy->fMac2->SetRpmMode(TRUE);
78 if (fCosy->fMac2->IsZombieNode())
79 return false;
80
81 fCosy->fMac1->SetRpmMode(TRUE);
82 if (fCosy->fMac1->IsZombieNode())
83 return false;
84
85 return true;
86}
87/*
88void MTracking::StopTracking()
89{
90 //
91 // Set status to Stopping
92 //
93 fCosy->SetStatus(MDriveCom::kStopping);
94
95 //
96 // set deceleration to 50%
97 //
98 cout << "Stopping tracking (dec=20%)..." << endl;
99 fCosy->fMac1->SetDeceleration(0.2*fMac1->GetVelRes());
100 fCosy->fMac2->SetDeceleration(0.2*fMac2->GetVelRes());
101
102 fCosy->fMac2->SendSDO(0x3006, 1, (LWORD_t)0); // SetRpmVelocity [re/min]
103 fCosy->fMac1->SendSDO(0x3006, 1, (LWORD_t)0); // SetRpmVelocity [re/min]
104 fCosy->fMac2->WaitForSdo(0x3006, 1);
105 fCosy->fMac1->WaitForSdo(0x3006, 1);
106
107 cout << "Waiting for end of movement..." << endl;
108 fCosy->WaitForEndMovement();
109
110 //
111 // Wait for the objects to be OKed.
112 //
113 fCosy->fMac1->SetRpmMode(FALSE);
114 fCosy->fMac2->SetRpmMode(FALSE);
115
116 //
117 // Wait for the movement to really be finished.
118 //
119 //cout << "Waiting for end of movement..." << endl;
120 //WaitForEndMovement();
121
122 //
123 // Check whether everything works fine.
124 //
125 fCosy->CheckForError();
126 cout << "Movement stopped." << endl;
127}
128*/
129// --------------------------------------------------------------------------
130//
131// Limits the speed.
132//
133// This function should work as a limiter. If a tracking error is too large
134// to be corrected fast enough we would get enormous velocities. These
135// velocities are limited to the maximum velocity.
136//
137Bool_t MTracking::LimitSpeed(ZdAz *vt, const SlaStars &sla) const
138{
139 // vt[re/min]
140
141 // Calculate approximate velocity of both axis
142 ZdAz vcalc = sla.GetApproxVel(fCosy->fRaDec); // [rad/rad]
143
144 //vcalc *= 1./(24*60); // [U_tel/min]
145 //vcalc *= fCosy->kGearTot; // [U_mot/min]
146 //vcalc *= fCosy->kResRE; // [re/min]
147
148 vcalc *= fCosy->kGearTot*fCosy->kResRE/(24*60); // [re/min]
149
150 // Set return code
151 Bool_t rc = kFALSE;
152
153 //
154 // How to limit the speed. If the wind comes and blowes
155 // we cannot forbid changing of the sign. But on the other hand
156 // we don't want fast changes!
157 //
158 ULong_t vrzd = fCosy->fMac1->GetVelRes();
159 ULong_t vraz = fCosy->fMac2->GetVelRes();
160
161#define sgn(x) (x<0?-1:1)
162
163 //
164 // When speed changes sign, the maximum allowed speed
165 // is 25% of the |v|
166 //
167 //const Float_t limit = 0.25;
168
169 //
170 // The maximum allowed speed while tracking is 10%
171 //
172 const Float_t maxtrack = 0.1;
173
174 if (fabs(vt->Az()) > maxtrack*vraz*4)
175 {
176 vt->Az(maxtrack*vraz*4*sgn(vcalc.Az()));
177 lout << "Warning: Azimuth speed limit (" << maxtrack*100 << "%) exceeded (" << fabs(vt->Az()) << " > " << maxtrack*vraz << ")... limited." << endl;
178 lout << "Vcalc: " << vcalc.Zd() << " " << vcalc.Az() << "re/min" <<endl;
179 rc=kTRUE;
180 }
181 if (fabs(vt->Zd()) > maxtrack*vrzd*4)
182 {
183 vt->Zd(maxtrack*vrzd*4*sgn(vcalc.Zd()));
184 lout << "Warning: Altitude speed limit (" << maxtrack*100 << "%) exceeded (" << fabs(vt->Zd()) <<" > " << maxtrack*vrzd << ")... limited." << endl;
185 lout << "Vcalc: " << vcalc.Zd() << " " << vcalc.Az() << "re/min" <<endl;
186 rc=kTRUE;
187 }
188 return rc;
189}
190
191// --------------------------------------------------------------------------
192//
193// Sets the tracking velocity
194//
195// The velocities are given in a ZdAz object in re/min. Return kTRUE
196// in case of success, kFALSE in case of failure.
197//
198Bool_t MTracking::SetVelocity(const ZdAz &v)
199{
200 //
201 // Send the new velocities for both axes.
202 //
203 fCosy->fMac2->SendSDO(0x3006, 1, (LWORD_t)v.Zd()); // SetRpmVelocity [re/min]
204 fCosy->fMac1->SendSDO(0x3006, 1, (LWORD_t)v.Az()); // SetRpmVelocity [re/min]
205
206 //
207 // Wait for the objects to be acknoledged.
208 //
209 fCosy->fMac2->WaitForSdo(0x3006, 1);
210 fCosy->fMac1->WaitForSdo(0x3006, 1);
211
212 //
213 // If the waiting for the objects wasn't interrupted return kTRUE
214 //
215 if (!Break())
216 return kTRUE;
217
218 //
219 // print a message if the interruption was due to a Can-node Error
220 //
221 if (fCosy->HasError())
222 lout << "Error while setting tracking velocity (SDO #3006)" << endl;
223
224 return kFALSE;
225}
226
227void MTracking::TrackPosition(const RaDec &dst) // ra, dec [rad]
228{
229 SlaStars sla(fCosy->fObservatory);
230
231 //
232 // Position to actual position
233 //
234 sla.Now();
235 ZdAz dest = sla.CalcZdAz(dst);
236
237 lout << sla.GetTime() << ": Track Position " << dst.Ra()*kRad2Deg/15 << "h, " << dst.Dec()*kRad2Deg <<"deg" << endl;
238
239 // If the star is culminating behind the zenith (South) we want to
240 // align the azimuth angle between -180 and 180deg. If the star is
241 // culminating before the zenith (north) we want the star to be
242 // aligned between -180 and 180deg (which is the default of CalcZdAz)
243 if (sla.GetPhi()>dst.Dec() && dest.Az()<0)
244 {
245 // align az from -180/180 to 0/360
246 lout << "Star culminating behind zenith: Adding 360deg to Azimuth " << dest.Az()*kRad2Deg << endl;
247 dest.Az(dest.Az() + TMath::TwoPi());
248 }
249
250 // Position the telescope to the current local position of the
251 // star. Do not reposition but start the tracking after the
252 // first positioning step
253 if (!SetPosition(dest, kTRUE))
254 {
255 lout << "Error: Cannot start tracking, positioning failed." << endl;
256 return;
257 }
258
259 //
260 // calculate offset from present se position
261 //
262 const ZdAz sepos = fCosy->GetSePos()*fCosy->kGearTot/fCosy->kResSE; //[re]
263 if (!RequestRePos())
264 return;
265
266 //
267 // Estimate Offset before starting to track
268 //
269 fOffset = sepos-fCosy->GetRePos();
270
271 /*
272 cout << "Sepos: " << sepos.Zd() << "re, " << sepos.Az() << "re" << endl;
273 cout << "Repos: " << repos.Zd() << "re, " << repos.Az() << "re" << endl;
274 cout << "Offset: " << fOffset.Zd() << "re, " << fOffset.Az() << "re" << endl;
275 */
276
277 //
278 // Init accelerations and Rpm Mode
279 //
280 if (!InitTracking())
281 {
282 fCosy->StopMovement();
283 return;
284 }
285
286 // Initialize Tracker (slalib or starguider)
287 fCosy->fRaDec = dst;
288
289 // StartThread
290 Start();
291
292 // Get current nominal local position
293 sla.Now();
294 ZdAz pos = sla.CalcZdAz(fCosy->fRaDec);
295
296 // Some output
297 XY xy(Rad2Deg(dst.Ra())*24/360, Rad2Deg(dst.Dec()));
298 lout << sla.GetTime() << " - Start Tracking: Ra=" <<xy.X() << "h Dec=";
299 lout << xy.Y() << "\xb0 @ Zd=" << pos.Zd()*kRad2Deg <<"deg Az=" << pos.Az()*kRad2Deg <<"deg" << endl;
300
301 //
302 // We want to reach the theoretical position exactly in about 0.5s
303 //
304 // *OLD*const float dt = 1; // 1 second
305 const float dt = 5;//3; // 2 second
306 while (!Break())
307 {
308 //
309 // Request Target position for Now+dt
310 //
311 sla.Now(dt);
312
313 //
314 // Request nominal position for this time in the future (To+dt)
315 //
316 const ZdAz pointing = sla.CalcZdAz(fCosy->fRaDec); // [rad]
317 ZdAz dest = fCosy->AlignTrackingPos(pointing); // fix ambiguity
318
319 //ZdAz vcalc = sla.GetApproxVel(fCosy->fRaDec);
320 //vcalc *= fCosy->kGearRatio2*4./60.; // [re/min]
321
322 float dtime = -1;
323 //if (kFALSE /*fUseStarguider*/)
324 // dtime = Starguider(sla.GetMjd(), dest);
325
326 ZdAz repos;
327 if (dtime<0)
328 {
329 dest = fCosy->fBending(dest); // [rad]
330 if (!fCosy->CheckRange(dest))
331 break;
332
333 dest *= fCosy->kGearTot/TMath::TwoPi(); // [re]
334
335 //*fCosy->fOutRep << "> ReqRePos1 " << endl;
336
337 //
338 // Request absolute position of rotary encoder from Macs
339 //
340 if (!RequestRePos())
341 break;
342
343 //*fCosy->fOutRep << "> ReqRePos2 " << fOffset.Zd() << " " << fOffset.Az() << endl;
344
345 //
346 // distance between (To+dt) and To [re]
347 // position time difference < 5usec
348 // fOffset does the synchronization between the
349 // Shaft- and the rotary encoders
350 repos = fCosy->GetRePos();
351 dest -= repos + fOffset; //[re]
352
353 dtime = dt;
354 }
355
356 //
357 // Velocity to go [re/min] to reach the right position at time t+dt
358 // correct for the duration of RaDec2AltAz
359 //
360 /* --- OLD --- */
361 ZdAz v = dest*60.0/dtime; //[re/min]
362 /* --- NEW --- seems to work worse! */
363 //const Double_t dtaz = sla.GetTime() - fCosy->fMac1->GetPosTime();
364 //const Double_t dtzd = sla.GetTime() - fCosy->fMac2->GetPosTime();
365 //
366 //ZdAz v = dest*60.0;
367 //v.Zd(v.Zd()/dtzd);
368 //v.Az(v.Az()/dtaz);
369 /* --- END --- */
370
371 //*fCosy->fOutRep << "> Dt: " << dtaz << " " << dtzd << endl;
372
373 if (LimitSpeed(&v, sla))
374 {
375 lout << "vt: " << v.Zd() << " " << v.Az() << "re/min" << endl;
376 lout << "Dest: " << dest.Zd() << " " << dest.Az() << endl;
377 }
378
379 //
380 // calculate real velocity of future [re/min]
381 // believing the Macs manual '/4' shouldn't be necessary, but it is.
382 //
383 ZdAz vt = v/4; //[re'/min]
384 //lout << " " << vt.Zd() << " " << vt.Az() << " ";
385 vt.Round();
386 //lout << " " << vt.Zd() << " " << vt.Az() << endl;
387
388 //
389 // check if the drive is fast enough to follow the star
390 //
391 if (vt.Zd()>.9*fCosy->fMac1->GetVelRes() || vt.Az()>.9*fCosy->fMac2->GetVelRes())
392 {
393 lout << "Error: Tracking speed faster than 90% of possible maximum velocity." << endl;
394 break;
395 }
396
397 //
398 // Set theoretical velocity (as early after calculation as possible)
399 // Maybe we should attenuate the changes
400 //
401 //*fCosy->fOutRep << "> SetVelocity1: " << vt.Zd() << " " << vt.Az() << endl;
402 if (!SetVelocity(vt))
403 break;
404 //*fCosy->fOutRep << "> SetVelocity2 " << endl;
405
406 //
407 // Now do 'unnecessary' things (timing)
408 //
409 fCosy->fVelocity = vt*4/fCosy->kGear; // [U_mot/min]
410 // *OLD* fVelocity = vt/kGearRatio2*4;
411
412 if (fOut)
413 {
414 fOut->Lock();
415 *fOut << "RE-REPORT " << MTime(-1) << " " << repos.Zd() << " " << repos.Az() <<" " << vt.Zd() << " " << vt.Az() << endl;
416 fOut->UnLock();
417 }
418
419 //
420 // Update speed as often as possible.
421 // make sure, that dt is around 10 times larger than the
422 // update time
423 //
424 // The loop should not be executed faster than the ramp of
425 // a change in the velocity can be followed.
426 // (This is important on fast machines >500MHz)
427 //
428 usleep(1000000); // 1s
429// *****FIXME**** cout << "." << flush;
430 }
431
432 sla.Now();
433
434 // StopThread
435 Stop();
436
437 fCosy->StopMovement();
438
439 lout << sla.GetTime() << " - Tracking stopped @ Zd=";
440 lout << fCosy->fZdAzSoll.Zd()*TMath::RadToDeg() <<"deg Az=";
441 lout << fCosy->fZdAzSoll.Az()*TMath::RadToDeg() <<"deg" << endl;
442}
443
444void *MTracking::Thread()
445{
446 if (fCosy->fZd1->IsZombieNode() && fCosy->fZd2->IsZombieNode())
447 return (void*)1;
448
449 if (fCosy->fAz->IsZombieNode())
450 return (void*)2;
451
452 if (!fCosy->fMac1 || !fCosy->fMac2)
453 return (void*)3;
454
455 lout << "- Tracking Thread started..." << endl;
456
457 const XY re2se = fCosy->kGearTot/fCosy->kResSE; //[re/se]
458
459 SlaStars sla(fCosy->fObservatory);
460 sla.Now();
461
462 ZdAz time;
463
464 ZdAz soll = sla.CalcZdAz(fCosy->fRaDec); // [rad]
465
466 //
467 // only update fTrackingError while tracking
468 //
469 bool phca1=false;
470 bool phca2=false;
471 bool phcaz=false;
472
473 while (!HasStopFlag())
474 {
475 // Make changes (eg wind) smoother - attenuation of control function
476 // This is the time constant which defines how fast
477 // you correct for external influences (like wind)
478 const float weight = 1.; //0.3;
479
480 // Check for changes of the shaftencoder values
481 //*fCosy->fOutRep << "> ResetPosHasChanged" << endl;
482 fCosy->fZd1->ResetPosHasChanged();
483 fCosy->fZd2->ResetPosHasChanged();
484 fCosy->fAz->ResetPosHasChanged();
485 //*fCosy->fOutRep << "> Check for PosHasChanged" << endl;
486 do
487 {
488 phca1 = fCosy->fZd1->PosHasChanged();
489 phca2 = fCosy->fZd2->PosHasChanged();
490 phcaz = fCosy->fAz->PosHasChanged();
491 usleep(1);
492 } while (!phca1 && !phca2 && !phcaz && !HasStopFlag());
493
494 //*fCosy->fOutRep << "> Do Calculation" << endl;
495
496 // Get current position of motors (use last automatically sent
497 // position (PDO) - requesting the position results in problems
498 // with thread safty)
499 ZdAz istre = fCosy->GetRePosPdo();
500
501 // get current position of shaftencoders
502 ZdAz istse = fCosy->GetSePos(); // [se]
503
504 // Get time from last shaftencoder position change (position: ist)
505 // FIXME: Is this correct?
506 if (fCosy->fZd1->GetMjd()>fCosy->fZd2->GetMjd())
507 time.Zd(fCosy->fZd1->GetMjd());
508 else
509 time.Zd(fCosy->fZd2->GetMjd());
510
511 time.Az(fCosy->fAz->GetMjd());
512
513 // calculate offset for both axis (only one is needed)
514 const ZdAz offset = (istse*re2se - istre)*weight + fOffset*(weight-1);
515
516 // if Shaftencoder changed position, calculate nominal position
517 if (phca1 || phca2)
518 {
519 const ZdAz dummy = sla.CalcZdAz(fCosy->fRaDec, time.Zd());
520 soll.Zd(dummy.Zd()); // [rad]
521 fOffset.Zd(offset.Zd());
522 }
523 if (phcaz)
524 {
525 const ZdAz dummy = sla.CalcZdAz(fCosy->fRaDec, time.Az());
526 soll.Az(dummy.Az()); // [rad]
527 fOffset.Az(offset.Az());
528 }
529
530 // After calculation of fOffset is done we need 'ist' in rad
531 istse /= fCosy->kResSE/TMath::TwoPi(); // [rad]
532
533 // Calculate the aligned tracking posotion from 'soll'-position
534 fCosy->fZdAzSoll = fCosy->AlignTrackingPos(soll);
535
536 /* --- OLD --- */
537 //fCosy->fTrackingError = istse-fCosy->fBending(fCosy->fZdAzSoll);
538 /* --- NEW --- */
539 fCosy->fTrackingError = fCosy->fBending.CorrectBack(istse)-fCosy->fZdAzSoll;
540 /* --- END --- */
541 }
542
543 lout << "- Tracking Thread done." << endl;
544
545 return 0;
546}
Note: See TracBrowser for help on using the repository browser.