source: trunk/MagicSoft/Cosy/main/MCosy.cc@ 2282

Last change on this file since 2282 was 2278, checked in by tbretz, 23 years ago
*** empty log message ***
File size: 57.0 KB
Line 
1#include "MCosy.h"
2#include "MCosy.h"
3
4#include <iomanip.h>
5#include <fstream.h>
6#include <iostream.h>
7
8#include <TROOT.h>
9#include <TEnv.h>
10#include <TSystem.h>
11#include <TApplication.h>
12#include <TTimer.h>
13
14#include <TH2.h>
15#include <TH3.h>
16#include <TProfile.h>
17#include <TCanvas.h>
18
19#include "MGCosy.h"
20#include "MStarguider.h"
21#include "SlaStars.h"
22
23#include "slalib/slalib.h" // FIXME: REMOVE
24
25#include "macs.h"
26#include "base/timer.h"
27#include "shaftencoder.h"
28
29ClassImp(MCosy);
30
31typedef struct tm tm_t;
32
33/*
34#define GEAR_RATIO_ALT 2475.6 // [U_mot/U_tel(360deg)]
35#define GEAR_RATIO_AZ 5891.7 // [U_mot/U_tel(360deg)]
36
37#define RES_RE 500 // [re/U_mot]
38#define RES_SE 16384 // [se/U_tel(360deg)]
39*/
40/*
41 #define GEAR_RATIO_ALT (75.55*16384/1500) // 75.25 VERY IMPORTANT! unit=U_mot/U_tel
42 #define GEAR_RATIO_AZ (179.8*16384/1500) // VERY IMPORTANT! unit=U_mot/U_tel
43*/
44
45//const XY kGearRatio (GEAR_RATIO_ALT*RES_RE/RES_SE, GEAR_RATIO_AZ*RES_RE/RES_SE); //[re/se]
46//const XY kGearRatio2(GEAR_RATIO_ALT*RES_RE/360.0, GEAR_RATIO_AZ*RES_RE/360.0); //[re/deg]
47
48/* +===================================+
49 FIXME: What if fMac3 (Sync) died?
50 +===================================+
51*/
52
53#define EXPERT
54
55double MCosy::Rad2SE(double rad) const
56{
57 return 16384.0/k2Pi*rad;
58}
59
60double MCosy::Rad2ZdRE(double rad) const
61{
62 return 16384.0/k2Pi*rad*kGearRatio.X();
63}
64
65double MCosy::Rad2AzRE(double rad) const
66{
67 return 16384.0/k2Pi*rad*kGearRatio.Y();
68}
69
70double MCosy::Deg2ZdRE(double rad) const
71{
72 return rad*kGearRatio2.X();
73}
74
75double MCosy::Deg2AzRE(double rad) const
76{
77 return rad*kGearRatio2.Y();
78}
79
80/*
81ZdAz MCosy::CorrectTarget(const ZdAz &src, const ZdAz &dst)
82{
83 // CorrectTarget [se]
84
85 // src [se]
86 // dst [rad]
87
88 // fAltMax = 70
89 // fAltMin = -105/110
90 // fAzMin = -355
91 // fAzMax = 355
92
93 ZdAz source = src * 360.0/16384.0;
94 ZdAz dest = dst * kRad2Deg;
95
96 if (dest.Zd()>-3 && dest.Zd()<3)
97 dest.Zd(dest.Zd()<0?-3:3);
98
99 if (dest.Zd()>-1e-6 && dest.Zd()<1e-6)
100 return dst*(16384.0/k2Pi);
101
102 const float fZdMin = -67;
103 const float fZdMax = 67;
104 const float fAzMin = -29;
105 const float fAzMax = 423;
106
107 //
108 // This corrects to target for the shortest distance, not for the fastest move!
109 //
110 ZdAz s = source-dest;
111
112 float min = s.Sqr();
113
114 //
115 // Is it enought to search inside one revolution?
116 //
117 ZdAz ret = dest;
118
119 for (int i=-5; i<5+1; i++)
120 {
121 const ZdAz p(i%2 ? -dest.Zd() : dest.Zd(), dest.Az() - i*180);
122
123 //
124 // Range Check
125 //
126 if (p.Zd()<fZdMin || p.Zd()>fZdMax)
127 continue;
128
129 if (p.Az()<fAzMin || p.Az()>fAzMax)
130 continue;
131
132 //
133 // Calculate distance
134 //
135 s = source-p;
136
137 const float dist = s.Sqr();
138
139 if (dist > min)
140 continue;
141
142 //
143 // New shortest distance
144 //
145 ret = p;
146 min = dist;
147 }
148 return ret*(16384.0/360.0);
149}
150*/
151
152// --------------------------------------------------------------------------
153//
154// GetSePos, reads the Shaftencoder positions from the Can-drivers
155// for the shaftencoders. The two shaft encoders at the elevation axis
156// are avaraged. The values are returned as a ZdAz object.
157//
158// If one of the two shaftencoders on the elevation axis is missing
159// the other one's position is returned.
160//
161// The positions are alway up-to-date because the shaftencoders are
162// sending all changes immediatly.
163//
164ZdAz MCosy::GetSePos() const
165{
166 const int pa = fAz->GetPos();
167 if (fZd1->IsZombieNode() && fZd2->IsZombieNode())
168 return ZdAz(0, pa);
169
170 //
171 // Get the values
172 //
173 int p1 = (fZd1->GetPos()+8192)%16384;
174 int p2 = -(fZd2->GetPos()+8192)%16384;
175
176 if (fZd1->IsZombieNode())
177 return ZdAz(p2, pa);
178 if (fZd2->IsZombieNode())
179 return ZdAz(p1, pa);
180
181 //
182 // interpolate shaft encoder positions
183 //
184 float p = (float)(p1+p2)/2;
185
186 return ZdAz(p, pa);
187}
188
189// --------------------------------------------------------------------------
190//
191// request the current positions from the rotary encoders.
192// use GetRePos to get the psotions. If the request fails the function
193// returns kFALSE, otherwise kTRUE
194//
195Bool_t MCosy::RequestRePos()
196{
197 //
198 // Send request
199 //
200 fMac2->RequestSDO(0x6004);
201 fMac1->RequestSDO(0x6004);
202
203 //
204 // Wait until the objects are received.
205 //
206 fMac2->WaitForSdo(0x6004);
207 fMac1->WaitForSdo(0x6004);
208
209 //
210 // If waiting was not interrupted everything is ok. return.
211 //
212 if (!(Break() || HasError() || HasZombie()))
213 return kTRUE;
214
215 //
216 // If the waiting was interrupted due to a network error,
217 // print some logging message.
218 //
219 if (HasError())
220 lout << "Error while requesting re pos from Macs (SDO #6004)" << endl;
221
222 return kFALSE;
223}
224
225// --------------------------------------------------------------------------
226//
227// reads the Rotary encoder positions from the last request of the Macs.
228//
229// The positions are returned as a ZdAz object. Use RequestRePos to request
230// the current positions first.
231//
232ZdAz MCosy::GetRePos()
233{
234 return ZdAz(fMac2->GetPos(), fMac1->GetPos());
235}
236
237// --------------------------------------------------------------------------
238//
239// reads the Rotary encoder positions from the Macs.
240//
241// The positions are returned as a ZdAz object. The positions are the ones
242// which are send as PDOs to the computer. This is done at a given
243// frequency. Which means, that this positions are not ought to be
244// up-to-date.
245//
246ZdAz MCosy::GetRePosPdo()
247{
248 return ZdAz(fMac2->GetPdoPos(), fMac1->GetPdoPos());
249}
250
251
252
253// --------------------------------------------------------------------------
254//
255// set the velocity and accelerations for position maneuvers.
256//
257// The acceleratin is set as given (in percent of maximum).
258// The velocity is given in percent, depending on the ratio (<1 or >1)
259// one of the axis becomes a slower velocity. This is used for maneuvers
260// in which both axis are moved synchromously and should reach their
261// target position at the same time.
262//
263void MCosy::SetPosVelocity(const Float_t ratio, Float_t vel)
264{
265 //
266 // Set velocities
267 //
268 const int vr = fMac1->GetVelRes();
269
270 vel *= vr;
271
272 if (ratio <1)
273 {
274 fMac1->SetVelocity(vel);
275 fMac2->SetVelocity(vel*ratio);
276 }
277 else
278 {
279 fMac1->SetVelocity(vel/ratio);
280 fMac2->SetVelocity(vel);
281 }
282}
283
284// --------------------------------------------------------------------------
285//
286// Does a relative positioning.
287//
288// The steps to move are given in a ZdAz object relative to the current
289// position. The coordinates are given in Roteryencoder steps.
290// Axis 1 is moved only if axe1==kTRUE, Axis 2 is moved only
291// if Axis 2==kTRUE. The function waits for the movement to be finished.
292//
293void MCosy::DoRelPos(const ZdAz &rd, const Bool_t axe1, const Bool_t axe2)
294{
295 if (HasZombie())
296 return;
297
298 SetStatus(MCosy::kMoving);
299
300 if (axe1) fMac2->StartRelPos(rd.Zd());
301 if (axe2) fMac1->StartRelPos(rd.Az());
302#ifdef EXPERT
303 cout << "Waiting for positioning..." << flush;
304#endif
305 if (axe1) fMac2->WaitForSdo(0x6004, 1);
306 if (axe2) fMac1->WaitForSdo(0x6004, 1);
307
308 WaitForEndMovement();
309#ifdef EXPERT
310 cout << "done." << endl;
311#endif
312}
313
314// --------------------------------------------------------------------------
315//
316// check for a break-signal (from the msgqueue) and errors.
317//
318int MCosy::StopWaitingForSDO() const
319{
320 return 0/*Break() || HasError()*/;
321}
322
323// --------------------------------------------------------------------------
324//
325// Waits for a movement to become finished.
326//
327// First waits for all peding Sdos, then waits until both motors are stopped
328// or waiting for SDOs was stopped (either by an error or by Break)
329//
330void MCosy::WaitForEndMovement()
331{
332 // FIXME, what when waiting times out (Zombie)
333 if (!fMac1 || !fMac2)
334 return;
335
336 while ((fMac1->IsPositioning() || fMac2->IsPositioning()) &&
337 !(Break() || HasError() || HasZombie()))
338 usleep(1);
339
340 if (Break() || HasError() || HasZombie())
341 {
342 lout << "WaitForEndMovement aborted... ";
343 if (Break())
344 lout << "Break signal." << endl;
345 if (HasError())
346 lout << "Network has error." << endl;
347 if (HasZombie())
348 lout << "Network has zombie." << endl;
349 }
350}
351
352// --------------------------------------------------------------------------
353//
354// Check for an error...
355//
356// This is ment for usage after the Action: All Motors Stop.
357//
358void MCosy::CheckForError()
359{
360 //
361 // Check all Can-Nodes for an Error. If there is no error the motor
362 // status is set to stopped.
363 //
364 if (!HasError())
365 {
366 SetStatus(MCosy::kStopped);
367 return;
368 }
369
370 //
371 // If there is an error, the error status is set to Error.
372 //
373 SetStatus(MCosy::kError);
374
375 /*
376 FIXME: HANDLINGE ERROR
377
378 //
379 // Now try to handle the error.
380 //
381 fMac1->HandleError();
382 fMac2->HandleError();
383
384 //
385 // If the error couldn't get solved return
386 //
387 if (HasError())
388 return;
389
390 //
391 // Set motor status to stopped
392 //
393 SetStatus(MCosy::kStopped);
394 */
395}
396
397Bool_t MCosy::CheckRange(const ZdAz &d) const
398{
399 // d [deg]
400
401 if (d.Zd()<fMin.Zd() || d.Zd()>fMax.Zd())
402 {
403 lout << "ERROR: Requested Zenith Angle (" << d.Zd() << "deg, Az=";
404 lout << d.Az() << ") not inside allowed range." << endl;
405 return kFALSE;
406 }
407
408 if (d.Az()<fMin.Az() || d.Az()>fMax.Az())
409 {
410 lout << "ERROR: Requested Azimuth Angle (" << d.Az() << "deg, Zd=";
411 lout << d.Zd() << ") not inside allowed range." << endl;
412 return kFALSE;
413 }
414
415 return kTRUE;
416}
417
418// --------------------------------------------------------------------------
419//
420// Move the telescope to the given position. The position must be given in
421// a ZdAz object in rad.
422//
423// The first positioning is done absolutely. If we didn't reach the
424// correct psotion we try to correct for this by 10 relative position
425// maneuvers. If this doesn't help positioning failed.
426//
427// As a reference the shaftencoder values are used.
428//
429int MCosy::SetPosition(const ZdAz &dst, Bool_t track) // [rad]
430{
431 const ZdAz d = dst*kRad2Deg;
432
433 Timer t;
434 t.Now();
435 lout << t << " - Target Position: " << d.Zd() << "deg, " << d.Az() << "deg (Zd/Az)" << endl;
436
437 if (!CheckRange(d))
438 return kFALSE;
439
440 //
441 // Calculate new target position (shortest distance to go)
442 //
443 const ZdAz src = GetSePos(); // [se]
444
445 //
446 // Make sure that the motors are in sync mode (necessary if the
447 // MACS has been rebooted from a Zombie state.
448 //
449 //InitSync();
450 //if (fMac3->IsZombieNode())
451 // return false;
452
453 //
454 // Because we agreed on I don't search for the shortest move
455 // anymore
456 //
457 // const ZdAz dest = CorrectTarget(src, dst);
458 //
459 const ZdAz dest = fBending(dst)*16384/2/TMath::Pi(); // [se]
460 fZdAzSoll = dst;
461
462 cout << "Source Zd: " << src.Zd() << "se Az:" << src.Az() << "se" << endl;
463 cout << "Destination Zd: " << Rad2SE(dst.Zd()) << "se Az:" << Rad2SE(dst.Az()) << "se" << endl;
464 cout << "Bend'd Dest Zd: " << Rad2SE(fZdAzSoll.Zd()) << "se Az:" << Rad2SE(fZdAzSoll.Az()) << "se" << endl;
465 cout << "Shortest Dest Zd: " << dest.Zd() << "se Az:" << dest.Az() << "se" << endl;
466
467 //
468 // Set velocities
469 //
470 const int vr = fMac1->GetVelRes();
471
472 int i;
473 for (i=0; i<10 && !(Break() || HasError() || HasZombie()); i++)
474 {
475
476 lout << "Step #" << i << endl;
477 //
478 // Get Shaft Encoder Positions
479 //
480 const ZdAz p=GetSePos();
481
482 //
483 // calculate control deviation and rounded cd
484 //
485 ZdAz rd = dest-p; // [se]
486
487 // ===========================================
488 const ZdAz ist = dst-rd*TMath::Pi()/8192;
489
490 const double p1 = ist.Zd()-19.0605/kRad2Deg;
491 const double p2 = dst.Zd()-19.0605/kRad2Deg;
492
493 const double f1 = (-26.0101*sin(p1)+443.761*ist.Zd())*8192/TMath::Pi();
494 const double f2 = (-26.0101*sin(p2)+443.761*dst.Zd())*8192/TMath::Pi();
495 // ===========================================
496
497 ZdAz cd = rd; // [se]
498 cd.Round();
499
500 //
501 // Check if there is a control deviation on the axis
502 //
503 const Bool_t cdzd = (int)cd.Zd() ? kTRUE : kFALSE;
504 const Bool_t cdaz = (int)cd.Az() ? kTRUE : kFALSE;
505
506 //
507 // check if we reached the correct position already
508 //
509 if (!cdzd && !cdaz)
510 {
511 t.Now();
512 lout << t << " - Positioning done in " << i << (i==1?" step.":" steps.") << endl;
513 SetStatus(MCosy::kStopped);
514 return TRUE;
515 }
516
517 //
518 // change units from se to re
519 //
520 rd *= kGearRatio; // [re]
521 rd.Zd(f2-f1);
522
523 //
524 // Initialize Velocities so that we reach both positions
525 // at the same time
526 //
527 if (i)
528 {
529 fMac1->SetAcceleration(0.1*vr);
530 fMac2->SetAcceleration(0.1*vr);
531
532 fMac1->SetDeceleration(0.1*vr);
533 fMac2->SetDeceleration(0.1*vr);
534
535 SetPosVelocity(1.0, 0.05);
536 }
537 else
538 {
539 if (rd.Az()>-15*kGearRatio.Y() && rd.Az()<15*kGearRatio.Y())
540 {
541#ifdef EXPERT
542 cout << " -------------- LO ---------------- " << endl;
543#endif
544 fMac1->SetAcceleration(0.05*vr);
545 fMac1->SetDeceleration(0.05*vr);
546 }
547 else
548 {
549#ifdef EXPERT
550 cout << " -------------- HI ---------------- " << endl;
551 fMac1->SetAcceleration(0.4*vr);// 0.4
552 fMac1->SetDeceleration(0.4*vr);// 0.4
553#else
554 fMac1->SetAcceleration(0.2*vr);
555 fMac1->SetDeceleration(0.1*vr);
556#endif
557 }
558
559#ifdef EXPERT
560 fMac2->SetAcceleration(0.4*vr);// 0.4
561 fMac2->SetDeceleration(0.4*vr);// 0.4
562 SetPosVelocity(fabs(rd.Ratio()), 0.2); // 0.175
563#else
564 fMac2->SetAcceleration(0.2*vr);
565 fMac2->SetDeceleration(0.1*vr);
566 SetPosVelocity(fabs(rd.Ratio()), 0.1);
567#endif
568 }
569
570 rd.Round();
571
572 // FIXME? Check for Error or Zombie?
573
574 /*
575 cout << " + " << (int)cdzd << " " << (int)cdaz << endl;
576 cout << " + APOS: Zd=" << setw(6) << p.Zd() << "se Az=" << setw(6) << p.Az() << "se" << endl;
577 cout << " + dZd=" << setw(6) << cd.Zd() << "se dAz=" << setw(6) << cd.Az() << "se" << endl;
578 cout << " + dZd=" << setw(6) << rd.Zd() << "re dAz=" << setw(6) << rd.Az() << "re" << endl;
579 cout << " + Ratio: Zd=" << setw(6) << kGearRatio.X() << "se Az=" << setw(6) << kGearRatio.Y() << "se" << endl;
580 */
581
582 //
583 // repositioning (relative)
584 //
585
586 lout << "Do Relative Positioning..." << endl;
587 DoRelPos(rd, cdzd, cdaz);
588 lout << "Relative Positioning Done" << endl;
589 }
590
591 if (i<10)
592 StopMovement();
593 else
594 SetStatus(MCosy::kStopped);
595
596 t.Now();
597 lout << t << " - Warning: Requested position not reached (i=" << i << ")" << endl;
598 return FALSE;
599}
600
601// --------------------------------------------------------------------------
602//
603// Sets the tracking velocity
604//
605// The velocities are given in a ZdAz object in re/min. Return kTRUE
606// in case of success, kFALSE in case of failure.
607//
608Bool_t MCosy::SetVelocity(const ZdAz &v)
609{
610 //
611 // Send the new velocities for both axes.
612 //
613 fMac2->SendSDO(0x3006, 1, (LWORD_t)v.Zd()); // SetRpmVelocity [re/min]
614 fMac1->SendSDO(0x3006, 1, (LWORD_t)v.Az()); // SetRpmVelocity [re/min]
615
616 //
617 // Wait for the objects to be acknoledged.
618 //
619 fMac2->WaitForSdo(0x3006, 1);
620 fMac1->WaitForSdo(0x3006, 1);
621
622 //
623 // If the waiting for the objects wasn't interrupted return kTRUE
624 //
625 if (!(Break() || HasError() || HasZombie()))
626 return kTRUE;
627
628 //
629 // print a message if the interruption was due to a Can-node Error
630 //
631 if (HasError())
632 lout << "Error while setting velocity (SDO #3006)" << endl;
633
634 return kFALSE;
635}
636
637// --------------------------------------------------------------------------
638//
639// Initializes Tracking mode
640//
641// Initializes the accelerations of both axes with 90% of the maximum
642// acceleration. Set the status for moving and tracking and starts thr
643// revolution mode.
644//
645bool MCosy::InitTracking()
646{
647 // FIXME? Handling of Zombie OK?
648 if (fMac1->IsZombieNode() || fMac2->IsZombieNode())
649 return false;
650
651 //
652 // Start revolution mode
653 //
654 fMac2->SetAcceleration(0.1*fMac2->GetVelRes());
655 fMac2->SetDeceleration(0.1*fMac2->GetVelRes());
656 if (fMac2->IsZombieNode())
657 return false;
658
659 fMac1->SetAcceleration(0.1*fMac1->GetVelRes());
660 fMac1->SetDeceleration(0.1*fMac1->GetVelRes());
661 if (fMac1->IsZombieNode())
662 return false;
663
664 SetStatus(MCosy::kMoving | MCosy::kTracking);
665
666 fMac2->SetRpmMode(TRUE);
667 if (fMac2->IsZombieNode())
668 return false;
669
670 fMac1->SetRpmMode(TRUE);
671 if (fMac1->IsZombieNode())
672 return false;
673
674 return true;
675}
676
677// --------------------------------------------------------------------------
678//
679// Limits the speed.
680//
681// This function should work as a limiter. If a tracking error is too large
682// to be corrected fast enough we would get enormous velocities. These
683// velocities are limited to the maximum velocity.
684//
685void MCosy::LimitSpeed(ZdAz *vt, const ZdAz &vcalc) const
686{
687 //
688 // How to limit the speed. If the wind comes and blowes
689 // we cannot forbid changing of the sign. But on the other hand
690 // we don't want fast changes!
691 //
692 ULong_t vrzd = fMac1->GetVelRes();
693 ULong_t vraz = fMac2->GetVelRes();
694
695#define sgn(x) (x<0?-1:1)
696
697 //
698 // When speed changes sign, the maximum allowed speed
699 // is 25% of the |v|
700 //
701 //const Float_t limit = 0.25;
702
703 //
704 // The maximum allowed speed while tracking is 10%
705 //
706 const Float_t maxtrack = 0.1;
707/*
708 if (sgn(vt->Az()) != sgn(vcalc.Az()))
709 vt->Az(0);
710// else
711 {
712 if (fabs(vt->Az()) < fabs(vcalc.Az()) *0.5)
713 vt->Az(0.5*vcalc.Az());
714
715 if (fabs(vt->Az()) > fabs(vcalc.Az()) *1.5)
716 vt->Az(1.5*vcalc.Az());
717 }
718
719 if (sgn(vt->Zd()) != sgn(vcalc.Zd()))
720 vt->Zd(0);
721// else
722 {
723 if (fabs(vt->Zd()) > fabs(vcalc.Az()) *1.5)
724 vt->Zd(1.5*vcalc.Zd());
725
726 if (fabs(vt->Zd()) < fabs(vcalc.Az()) *0.5)
727 vt->Zd(0.5*vcalc.Zd());
728 }
729 */
730 /*
731 if (sgn(vt->Az()) != sgn(vcalc.Az())
732 && fabs(vt->Az()) < limit*fabs(vcalc.Az())
733 )
734 {
735 lout << "Warning: Negative Azimuth speed limit (" << limit*100 << "%) exceeded... set to 0." << endl;
736 vt->Az(0);
737 }
738 else*/
739 if (fabs(vt->Az()) > maxtrack*vraz)
740 {
741 lout << "Warning: Azimuth speed limit (" << maxtrack*100 << "%) exceeded... limited." << endl;
742 vt->Az(maxtrack*vraz*sgn(vcalc.Az()));
743 }
744/*
745 if (sgn(vt->Zd()) != sgn(vcalc.Zd())
746 && fabs(vt->Zd()) < limit*fabs(vcalc.Zd())
747 )
748 {
749 lout << "Warning: Negative Altitude speed limit (" << limit*100 << "%) exceeded... set to 0." << endl;
750 vt->Zd(0);
751 }
752 else
753 */ if (fabs(vt->Zd()) > maxtrack*vrzd)
754 {
755 lout << "Warning: Altitude speed limit (" << maxtrack*100 << "%) exceeded... limited." << endl;
756 vt->Zd(maxtrack*vrzd*sgn(vcalc.Zd()));
757 }
758}
759
760Bool_t MCosy::AlignTrackingPos(ZdAz pointing, ZdAz &za) const
761{
762 // pointing [deg]
763 if (pointing.Zd()<0)
764 {
765 pointing.Zd(-pointing.Zd());
766 pointing.Az(pointing.Az()+180);
767 }
768
769 const ZdAz se = GetSePos()*2*TMath::Pi()/16384; // [rad]
770 const ZdAz unbendedse = fBending.CorrectBack(se)*kRad2Deg; // ist pointing
771
772 do
773 {
774 const Double_t d = unbendedse.Az() - pointing.Az();
775 if (d>-180 && d<=180)
776 break;
777
778 pointing.Az(pointing.Az()+TMath::Sign(360., d));
779 } while (1);
780
781 const Bool_t rc = CheckRange(pointing);
782 za = pointing/kRad2Deg; // [rad]
783
784 if (!rc)
785 lout << "Error: Aligned position out of Range." << endl;
786
787 return rc;
788}
789
790Double_t MCosy::Starguider(Double_t mjd, ZdAz &dest) const
791{
792 ifstream fin("pointingpos.txt");
793 if (!fin)
794 return -1;
795
796 Double_t mjd0, zd, az;
797 fin >> mjd0 >> zd >> az;
798
799 mjd0 += 52000;
800
801 if (mjd0+1./24/60 <mjd)
802 return -1;
803
804 ZdAz point;
805 if (!AlignTrackingPos(ZdAz(zd, az), point))
806 {
807 cout << "Starguider position couldn't be aligned..." << endl;
808 return -1;
809 }
810
811 const ZdAz diff = (dest-point)*kRad2Deg;
812
813 if (diff.Zd()>5 || diff.Az()>5)
814 {
815 cout << "Starguider deviation too large... dZd=" << diff.Zd() <<" dAz="<<diff.Az() << endl;
816 return -1;
817 }
818
819 dest -= point;
820 dest *= 16384/TMath::Pi()/2; // [se]
821 dest *= -kGearRatio; // [re]
822
823 cout << "Using Starguider... dZd=" << dest.Zd() << " dAz=" << dest.Az() << endl;
824
825 return (mjd-mjd0) * (24*60*60); // [s]
826}
827
828void MCosy::TrackPosition(const RaDec &dst) // ra, dec [rad]
829{
830 lout << "Track Position: " << dst.Ra()*kRad2Deg/15 << "h, " << dst.Dec()*kRad2Deg << "deg (Ra/Dec)" << endl;
831
832 SlaStars sla(fObservatory);
833
834 //
835 // Position to actual position
836 //
837 sla.Now();
838 ZdAz dest = sla.CalcZdAz(dst);
839
840 // FIXME: Determin tracking start point by star culmination
841 if (dest.Az()<-TMath::Pi()/2)
842 {
843 lout << "Adding 360deg to Azimuth " << dest.Az()*kRad2Deg << endl;
844 dest.Az(dest.Az() + TMath::Pi()*2);
845 }
846
847 if (dest.Az()>3*TMath::Pi()/2)
848 {
849 lout << "Substracting 360deg to Azimuth " << dest.Az()*kRad2Deg << endl;
850 dest.Az(dest.Az() -TMath::Pi()*2);
851 }
852
853 if (!SetPosition(dest, kTRUE))
854 {
855 lout << "Error: Cannot start tracking, positioning failed." << endl;
856 return;
857 }
858
859 //
860 // calculate offset from present se position
861 //
862 const ZdAz sepos = GetSePos()*kGearRatio;
863
864 if (!RequestRePos())
865 return;
866
867 //
868 // Estimate Offset before starting to track
869 //
870 fOffset = sepos-GetRePos();
871
872 /*
873 cout << "Sepos: " << sepos.Zd() << "re, " << sepos.Az() << "re" << endl;
874 cout << "Repos: " << repos.Zd() << "re, " << repos.Az() << "re" << endl;
875 cout << "Offset: " << fOffset.Zd() << "re, " << fOffset.Az() << "re" << endl;
876 */
877
878 //
879 // Init accelerations and Rpm Mode
880 //
881 if (!InitTracking())
882 {
883 StopMovement();
884 return;
885 }
886
887 XY xy(Rad2Deg(dst.Ra())*24/360, Rad2Deg(dst.Dec()));
888
889 sla.Now();
890 lout << sla << " - Start tracking:";
891 lout << " Ra: " << xy.X() << "h " << "Dec: " << xy.Y() << "\xb0" << endl;
892/*#ifdef EXPERT
893 ofstream fout("coordinates.txt");
894 fout << xy;
895 fout.close();
896#endif
897*/ //
898 // Initialize Tracker (slalib or starguider)
899 //
900 fRaDec = dst;
901 fBackground = kBgdTracking;
902
903//--- ofstream fout("log/cosy.pos");
904//--- fout << "Tracking:";
905//--- fout << " Ra: " << Rad2Deg(dst.Ra()) << "\x9c ";
906//--- fout << "Dec: " << Rad2Deg(dst.Dec()) << "\x9c" << endl << endl;
907//--- fout << " Mjd/10ms V/re/min/4" << endl;
908
909 //
910 // We want to reach the theoretical position exactly in about 0.5s
911 //
912 // *OLD*const float dt = 1; // 1 second
913 const float dt = 5;//3; // 2 second
914 while (!(Break() || HasError() || HasZombie()))
915 {
916 //
917 // Request Target position for this moment
918 //
919 sla.Now();
920
921 //
922 // Request theoretical Position for a time in the future (To+dt) from CPU
923 //
924 const Double_t mjd = sla.GetMjd()+dt/(60*60*24);
925 const ZdAz pointing = sla.CalcZdAz(fRaDec, mjd)*kRad2Deg; // soll pointing [deg]
926
927 ZdAz dest;
928 if (!AlignTrackingPos(pointing, dest))
929 break;
930
931 ZdAz vcalc = sla.GetApproxVel(fRaDec) * kGearRatio2*4./60.; // [re/min]
932
933 float dtime = -1;
934 if (kFALSE /*fUseStarguider*/)
935 dtime = Starguider(mjd, dest);
936
937 if (dtime<0)
938 {
939 dest = fBending(dest); // [rad]
940 dest *= 16384/TMath::Pi()/2; // [se]
941 dest *= kGearRatio; // [re]
942
943 //
944 // Request absolute position of rotary encoder from Macs
945 //
946 if (!RequestRePos())
947 break;
948
949 //
950 // distance between (To+dt) and To [re]
951 // position time difference < 5usec
952 // fOffset does the synchronization between the
953 // Shaft- and the rotary encoders
954 dest -= GetRePos() + fOffset;
955
956 dtime = dt;
957 }
958
959 //
960 // Velocity to go [re/min] to reach the right position at time t+dt
961 // correct for the duration of RaDec2AltAz
962 //
963 const ZdAz v = dest*60.0/(dtime/*-(fMac2->GetTime()-sla)*/);
964
965 //
966 // calculate real velocity of future [re/min]
967 // believing the Macs manual '/4' shouldn't be necessary, but it is.
968 //
969 ZdAz vt = v/4;
970 LimitSpeed(&vt, vcalc);
971 vt.Round();
972
973 //
974 // check if the drive is fast enough to follow the star
975 //
976 if (vt.Zd()>.9*fMac1->GetVelRes() || vt.Az()>.9*fMac2->GetVelRes())
977 {
978 lout << "Error: Tracking speed faster than 90% of possible maximum velocity." << endl;
979 break;
980 }
981
982 //
983 // Set theoretical velocity (as early after calculation as possible)
984 // Maybe we should attenuate the changes
985 //
986 if (!SetVelocity(vt))
987 break;
988
989 //
990 // Now do 'unnecessary' things
991 //
992 fVelocity = vt/kGearRatio2*4;
993
994//--- const double mjd = fMac2->GetMjd();
995//--- fout << setprecision(15) << setw(17) << mjd*60.*60.*24. << " ";
996//--- fout << setw(4) << vt.Zd() << " ";
997//--- fout << setw(4) << vt.Az() << endl;
998 //
999 // FIXME? Calculate an accuracy for the tracking system?
1000 // How good do we reach the calculated position in 'real'
1001 // re valus?
1002 //
1003
1004
1005 //
1006 // Update speed as often as possible.
1007 // make sure, that dt is around 10 times larger than the
1008 // update time
1009 //
1010 //
1011 // The loop should not be executed faster than the ramp of
1012 // a change in the velocity can be followed.
1013 // (This is important on fast machines >500MHz)
1014 //
1015 /*
1016 MTimeout t(1000);
1017 while (!t.HasTimedOut())
1018 usleep(1);
1019 */
1020 usleep(1000000); // 1s
1021 //usleep(50000); // 0.05s
1022 }
1023
1024 sla.Now();
1025
1026 fBackground = kBgdNone;
1027 StopMovement();
1028
1029 lout << sla << " - Tracking stopped." << endl;
1030}
1031
1032// --------------------------------------------------------------------------
1033//
1034// Stops the movement of both motors.
1035//
1036// Sets the status to stopping. Sets the deceleration to 50% of the maximum.
1037// stops. Quits the revolution mode and wait for the end of the movement.
1038//
1039void MCosy::StopMovement()
1040{
1041 //
1042 // Set status to Stopping
1043 //
1044 SetStatus(MCosy::kStopping);
1045
1046 //
1047 // set deceleration to 50%
1048 //
1049 cout << "Stopping movement (dec=30%)..." << endl;
1050 if (fMac1 && fMac2)
1051 {
1052#ifdef EXPERT
1053 fMac1->SetDeceleration(0.5*fMac1->GetVelRes());
1054 fMac2->SetDeceleration(0.5*fMac2->GetVelRes());
1055#else
1056 fMac1->SetDeceleration(0.3*fMac1->GetVelRes());
1057 fMac2->SetDeceleration(0.3*fMac2->GetVelRes());
1058#endif
1059 fMac1->SetRpmMode(FALSE);
1060 fMac2->SetRpmMode(FALSE);
1061 }
1062
1063/*
1064 fMac1->SetDeceleration(0.3*fMac1->GetVelRes());
1065 fMac2->SetDeceleration(0.3*fMac2->GetVelRes());
1066
1067 fMac2->SendSDO(0x3000, Macs::string('s','t','o','p'));
1068 fMac1->SendSDO(0x3000, Macs::string('s','t','o','p'));
1069 fMac2->WaitForSdo(0x3000, 0);
1070 fMac1->WaitForSdo(0x3000, 0);
1071 fMac1->SetRpmMode(FALSE);
1072 fMac2->SetRpmMode(FALSE);
1073 */
1074
1075 //
1076 // Wait for the movement to really be finished.
1077 //
1078#ifdef EXPERT
1079 cout << "Waiting for end of movement..." << endl;
1080#endif
1081 WaitForEndMovement();
1082
1083 //
1084 // Check whether everything works fine.
1085 //
1086 CheckForError();
1087#ifdef EXPERT
1088 cout << "Movement stopped." << endl;
1089#endif
1090}
1091
1092void MCosy::StopTracking()
1093{
1094 //
1095 // Set status to Stopping
1096 //
1097 SetStatus(MCosy::kStopping);
1098
1099 //
1100 // set deceleration to 50%
1101 //
1102 cout << "Stopping tracking (dec=20%)..." << endl;
1103 fMac1->SetDeceleration(0.2*fMac1->GetVelRes());
1104 fMac2->SetDeceleration(0.2*fMac2->GetVelRes());
1105
1106 fMac2->SendSDO(0x3006, 1, (LWORD_t)0); // SetRpmVelocity [re/min]
1107 fMac1->SendSDO(0x3006, 1, (LWORD_t)0); // SetRpmVelocity [re/min]
1108 fMac2->WaitForSdo(0x3006, 1);
1109 fMac1->WaitForSdo(0x3006, 1);
1110
1111 cout << "Waiting for end of movement..." << endl;
1112 WaitForEndMovement();
1113
1114 //
1115 // Wait for the objects to be OKed.
1116 //
1117 fMac1->SetRpmMode(FALSE);
1118 fMac2->SetRpmMode(FALSE);
1119
1120 //
1121 // Wait for the movement to really be finished.
1122 //
1123 //cout << "Waiting for end of movement..." << endl;
1124 //WaitForEndMovement();
1125
1126 //
1127 // Check whether everything works fine.
1128 //
1129 CheckForError();
1130 cout << "Movement stopped." << endl;
1131}
1132
1133bool MCosy::CheckNetwork()
1134{
1135 //return kTRUE;
1136 //CheckConnections();
1137
1138 if (HasZombie())
1139 {
1140 lout << "- Found Zombies in Network..." << endl;
1141 if (!RebootZombies())
1142 return false;
1143 }
1144
1145 /*
1146 FIXME HANDLING ERROR
1147 */
1148 if (HasError())
1149 {
1150 fMac1->HandleError();
1151 fMac2->HandleError();
1152 fMac3->HandleError();
1153 if (HasError() || HasZombie())
1154 return false;
1155 }
1156
1157 return true;
1158}
1159
1160void *MCosy::Proc(int msg, void *mp)
1161{
1162 switch (msg)
1163 {
1164 case WM_WAIT:
1165 cout << "Wait for execution of Proc(WM_*, ): done." << endl;
1166 return NULL;
1167
1168 case WM_STOP:
1169 cout << "MCosy::Proc: Stop." << endl;
1170 if (!CheckNetwork())
1171 return (void*)0xebb0;
1172 StopMovement();
1173 return NULL;
1174/*
1175 case WM_PRESET:
1176 cout << "WM_Preset: start." << endl;
1177 if (!CheckNetwork())
1178 return (void*)0xebb0;
1179 fZd1->SetPreset();
1180 fZd2->SetPreset();
1181 fAz->SetPreset();
1182 cout << "WM_Preset: done. (return 0xaffe)" << endl;
1183 return (void*)0xaffe;
1184*/
1185 /*
1186 case WM_CALIB:
1187 {
1188 cout << "WM_Calib: start." << endl;
1189 if (!CheckNetwork())
1190 return (void*)0xebb0;
1191
1192 SlaStars sla(fObservatory);
1193 sla.Now();
1194
1195 RaDec rd = *((RaDec*)mp);
1196
1197 //RaDec rd(37.94, 89.2644); // POLARIS
1198 //RaDec rd(213.915417, 19.1825); // ARCTURUS
1199
1200 cout << "Calibrating to: " << rd.Ra()*24/360 << "h " << rd.Dec() << "°" << endl;
1201
1202 ZdAz za=sla.CalcZdAz(rd*kDeg2Rad)*16384.0/k2Pi;
1203
1204 cout << "Calc Zd: " << za.Zd() << " Az: " << za.Az() << endl;
1205
1206 ZdAz sepos = GetSePos();
1207 cout << "Got Zd: " << sepos.Zd() << " Az: " << sepos.Az() << endl;
1208
1209 fZd1->SetPreset(za.Zd());
1210 fZd2->SetPreset(-za.Zd());
1211 fAz->SetPreset(za.Az());
1212
1213 cout << "WM_Calib: done. (return 0xaffe)" << endl;
1214 }
1215 return (void*)0xaffe;
1216 */
1217 case WM_TPOINT:
1218 {
1219 cout << "WM_TPoint: start." << endl;
1220 SlaStars sla(fObservatory);
1221 sla.Now();
1222
1223 RaDec rd = *((RaDec*)mp);
1224 cout << "TPoint Star: " << rd.Ra()/15 << "h " << rd.Dec() << "°" << endl;
1225
1226 AltAz za=sla.CalcAltAz(rd*kDeg2Rad)*kRad2Deg;
1227
1228 cout << " Alt/Az: " << za.Alt() << "° " << za.Az() << "°" << endl;
1229 *tpout << setprecision(7) << za.Az() << " " << za.Alt() << " ";
1230
1231 ZdAz sepos = GetSePos()*TMath::Pi()*2/16384;;
1232 za.Set(TMath::Pi()/2-sepos.Zd(), sepos.Az());
1233 za *= kRad2Deg;
1234
1235 cout << " SE-Pos: " << za.Alt() << "° " << za.Az() << "°" << endl;
1236 *tpout << fmod(za.Az()+360, 360) << " " << za.Alt() << " ";
1237
1238 if (fStarguider)
1239 {
1240 XY tp = fStarguider->GetCoordinates();
1241 *tpout << 90-tp.X() << " " << tp.Y() << " ";
1242 }
1243
1244 *tpout << rd.Ra()/15 << " " << rd.Dec() << " " << setprecision(11) << sla.GetMjd() << endl;
1245
1246 cout << "WM_TPoint: done. (return 0xaffe)" << endl;
1247 }
1248 return (void*)0xca1b;
1249
1250 case WM_TRACKPOS:
1251 cout << "WM_TrackPosition: start." << endl;
1252 {
1253 if (!CheckNetwork())
1254 return (void*)0xebb0;
1255
1256 ZdAz dest = *((ZdAz*)mp) * kDeg2Rad;
1257 //if (!SetPosition(dest))
1258 // return (void*)0x1234;
1259
1260 SlaStars sla(fObservatory);
1261 sla.Now();
1262
1263 RaDec rd = sla.CalcRaDec(dest);
1264 cout << dest.Zd()*180/3.1415 << " " << dest.Az()*180/3.1415 << endl;
1265 cout << rd.Ra()*12/3.1415 << " " << rd.Dec()*180/3.1415 << endl;
1266 TrackPosition(rd);
1267 }
1268 cout << "WM_TrackPosition: done. (return 0xabcd)" << endl;
1269 return (void*)0xabcd;
1270
1271 case WM_POSITION:
1272 cout << "WM_Position: start." << endl;
1273 {
1274 if (!CheckNetwork())
1275 return (void*)0xebb0;
1276
1277 ZdAz dest = *((ZdAz*)mp);
1278 SetPosition(dest*kDeg2Rad);
1279 }
1280 cout << "WM_Position: done. (return 0x7777)" << endl;
1281 return (void*)0x7777;
1282
1283 case WM_TESTSE:
1284 cout << "WM_TestSe: start." << endl;
1285 fBackground = mp ? kBgdSeTest : kBgdNone;
1286 cout << "WM_TestSe: done. (return 0x1e51)" << endl;
1287 return (void*)0x1e51;
1288
1289 case WM_GEAR:
1290 cout << "WM_Gear: start." << endl;
1291 fBackground = mp ? kBgdGear : kBgdNone;
1292 cout << "WM_Gear: done. (return 0xfeaf)" << endl;
1293 return (void*)0xfeaf;
1294
1295 case WM_DISPLAY:
1296 cout << "WM_Display: start." << endl;
1297 fTriggerDisplay = kTRUE;
1298 cout << "WM_Disply: done. (return 0xd1e1)" << endl;
1299 return (void*)0xd1e1;
1300
1301 case WM_TRACK:
1302 cout << "WM_Track: START" << endl;
1303 {
1304 RaDec dest = ((RaDec*)mp)[0];
1305 if (fStarguider)
1306 fStarguider->SetPointingPosition(((RaDec*)mp)[1]);
1307 if (!CheckNetwork())
1308 return (void*)0xebb0;
1309 TrackPosition(dest*kDeg2Rad);
1310 }
1311 cout << "WM_Track: done. (return 0x8888)" << endl;
1312 return (void*)0x8888;
1313
1314 case WM_NEWTRACK:
1315 cout << "WM_NewTrack: START" << endl;
1316 fRaDec = *((RaDec*)mp);
1317 cout << "WM_NewTrack: done. (return 0x9999)" << endl;
1318 return (void*)0x9999;
1319
1320 case WM_LOADBENDING:
1321 cout << "WM_LoadBending: START" << endl;
1322 fBending.Load("bending.txt");
1323 cout << "WM_LoadBending: done. (return 0xbe0d)" << endl;
1324 return (void*)0xbe0d;
1325
1326 case WM_RESETBENDING:
1327 cout << "WM_ResetBending: START" << endl;
1328 fBending.Reset();
1329 cout << "WM_ResetBending: done. (return 0xbe0e)" << endl;
1330 return (void*)0xbe0e;
1331
1332 case WM_HOME:
1333 cout << "WM_Home: START" << endl;
1334 if (!CheckNetwork())
1335 return (void*)0xebb0;
1336 else
1337 {
1338 cout << "HOME NOT ALLOWED... for Magic." << endl;
1339 /*
1340 cout << "Going Home..." << endl;
1341 TEnv env(".cosyrc");
1342
1343 SetStatus(MCosy::kMoving);
1344
1345 fMac1->SetHome(250000, env.GetValue("Az_MaxTime2ReachHome[s]", 100));
1346 fMac2->SetHome(250000, env.GetValue("Zd_MaxTime2ReachHome[s]", 100));
1347
1348 lout << "SETHOME DONE" << endl;
1349
1350 SetStatus(HasError() ? MCosy::kError : MCosy::kStopped);
1351
1352 fAz->SetPreset();
1353 fZd1->SetPreset();
1354 fZd2->SetPreset();
1355
1356 fMac1->ReqPos();
1357 fMac2->ReqPos();
1358 fMac3->StopMotor();
1359 */
1360 }
1361 cout << "WM_Home: done. (return 0x403e)" << endl;
1362 return (void*)0x403e;
1363
1364 case WM_CALCALTAZ:
1365 {
1366 cout << endl;
1367
1368 SlaStars sla(fObservatory);
1369 sla.Now();
1370
1371 XY xy = *((XY*)mp);
1372 RaDec rd(xy.X()*15., xy.Y()); // [deg]
1373
1374 ZdAz a1 = sla.CalcZdAz(rd*kDeg2Rad); // [rad]
1375 const ZdAz a0 = a1*kRad2Deg; // [deg]
1376
1377 cout << "Ra/Dec source: " << xy.X() << "h " << xy.Y() << "°" << endl;
1378 cout << "Zd/Az target: " << a0.Zd() << "° " << a0.Az() << "°" << endl;
1379
1380 if (fZd1 && fZd2 && fAz)
1381 AlignTrackingPos(a0, a1);
1382
1383 a1 = fBending(a1)*kRad2Deg;
1384
1385 const ZdAz a2 = a1*16384/360;
1386
1387 cout << "Zd/Az bended: " << a1.Zd() << "° " << a1.Az() << "°" << endl;
1388 cout << "SE bended: " << a2.Zd() << " " << a2.Az() << endl;
1389 }
1390 return (void*)0xa17a;
1391
1392 case WM_QUIT:
1393 cout << "WM_Quit: now." << endl;
1394 if (!CheckNetwork())
1395 {
1396 lout << "ERROR: Cannot shutdown CANbus network." << endl;
1397 return (void*)0xebb0;
1398 }
1399 TerminateApp();
1400 cout << "WM_Quit: done." << endl;
1401 return (void*)0xaaaa;
1402 }
1403 cout << "MCosy::Proc: Unknown message 0x" << msg << endl;
1404 return (void*)0xffffffff;
1405}
1406
1407void *MTTalk::Thread()
1408{
1409 fCosy->TalkThread();
1410 return NULL;
1411}
1412
1413void MCosy::ReadConfig()
1414{
1415 cout << "Reading configuration file..." << flush;
1416 TEnv env(".cosyrc");
1417 cout << "done." << endl;
1418
1419 cout << "Reading telescope range..." << flush;
1420 const Double_t amin = env.GetValue("Az_Min[deg]", -95.0);
1421 const Double_t zmin = env.GetValue("Zd_Min[deg]", -75.0);
1422 fMin.Set(zmin, amin);
1423
1424 cout << " Min: " << zmin << "deg " << amin << "deg" << endl;
1425
1426 const Double_t amax = env.GetValue("Az_Max[deg]", 305.0);
1427 const Double_t zmax = env.GetValue("Zd_Max[deg]", 98.25);
1428 fMax.Set(zmax, amax);
1429
1430 cout << " Max: " << zmax << "deg " << amax << "deg" << endl;
1431
1432 cout << "Reading gear ratios..." << flush;
1433 const Double_t gaz = env.GetValue("Az_GearRatio[U_mot/U_tel]", 1000.0);
1434 const Double_t gzd = env.GetValue("Zd_GearRatio[U_mot/U_tel]", 1000.0);
1435
1436 Double_t resreaz = 0;
1437 if (fMac1 && !fMac1->IsZombieNode())
1438 resreaz = fMac1->GetRes();
1439 else
1440 if (fMac3 && !fMac3->IsZombieNode())
1441 resreaz = fMac3->GetRes();
1442 else
1443 resreaz = env.GetValue("Az_ResRE[re/U_mot]", 1500);
1444
1445 Double_t resrezd = 0;
1446 if (fMac2 && !fMac2->IsZombieNode())
1447 resrezd = fMac2->GetRes();
1448 else
1449 resrezd = env.GetValue("Zd_ResRE[re/U_mot]", 1500);
1450
1451 Double_t ressezd = 0;
1452 if (fZd1 && !fZd1->IsZombieNode())
1453 ressezd = fZd1->GetPhysRes();
1454 else
1455 if (fZd2 && !fZd2->IsZombieNode())
1456 ressezd = fZd2->GetPhysRes();
1457 else
1458 ressezd = env.GetValue("Zd_ResSE[se/U_mot]", 16384);
1459
1460 Double_t resseaz = 0;
1461 if (fAz && !fAz->IsZombieNode())
1462 resseaz = fAz->GetPhysRes();
1463 else
1464 resseaz = env.GetValue("Az_ResSE[se/U_mot]", 16384);
1465
1466 kGearRatio.Set (gzd*resrezd*4/ressezd, gaz*resreaz*4/resseaz); //[re/se]
1467 kGearRatio2.Set(gzd*resrezd*4/360.0, gaz*resreaz*4/360.0); //[re/deg]
1468 cout << "done." << endl;
1469
1470 cout << " * Setting Gear Ratios:" << endl;
1471 cout << " --------------------" << endl;
1472 cout << " * X: " << gzd << "*" << resrezd << "/" << ressezd << "=4*" << kGearRatio.X() << endl;
1473 cout << " * Y: " << gaz << "*" << resreaz << "/" << resseaz << "=4*" << kGearRatio.Y() << endl;
1474}
1475
1476void MCosy::InitSync()
1477{
1478 if (!fMac3)
1479 {
1480 lout << "Unable to Init Sync! Mac3 not available." << endl;
1481 return;
1482 }
1483
1484 const int res = fMac3->GetVelRes();
1485
1486 fMac3->SetVelocity(0.3*res);
1487 fMac3->SetAcceleration(0.2*res);
1488 fMac3->SetDeceleration(0.2*res);
1489 fMac3->StartPosSync();
1490}
1491
1492void MCosy::TalkThreadTracking()
1493{
1494 if (fZd1->IsZombieNode() && fZd2->IsZombieNode())
1495 return;
1496
1497 if (fAz->IsZombieNode())
1498 return;
1499
1500 if (!fMac1 || !fMac2)
1501 return;
1502
1503 lout << "Tracking Thread started..." << endl;
1504
1505 SlaStars sla(fObservatory);
1506 sla.Now();
1507
1508 ZdAz old;
1509 ZdAz ist = GetSePos(); // [se]
1510
1511 ZdAz time;
1512
1513 ZdAz sollzd = sla.CalcZdAz(fRaDec); // [rad]
1514 ZdAz sollaz = sollzd; // [rad]
1515
1516 //
1517 // only update fTrackingError while tracking
1518 //
1519 bool phca1=false;
1520 bool phca2=false;
1521 bool phcaz=false;
1522
1523 while (fBackground==kBgdTracking)
1524 {
1525 //
1526 // Make changes (eg wind) smoother - attenuation of control function
1527 //
1528 const float weight = 1.; //0.3;
1529
1530 //
1531 // This is the time constant which defines how fast
1532 // you correct for external influences (like wind)
1533 //
1534 fZd1->ResetPosHasChanged();
1535 fZd2->ResetPosHasChanged();
1536 fAz->ResetPosHasChanged();
1537 do
1538 {
1539 phca1 = fZd1->PosHasChanged();
1540 phca2 = fZd2->PosHasChanged();
1541 phcaz = fAz->PosHasChanged();
1542 usleep(1);
1543 } while (!phca1 && !phca2 && !phcaz && fBackground==kBgdTracking);
1544
1545 //---usleep(100000); // 0.1s
1546
1547 //
1548 // get position, where we are
1549 //
1550 old = ist;
1551 ist = GetSePos(); // [se]
1552
1553 //
1554 // if the position didn't change continue
1555 //
1556 /*---
1557 if ((int)ist.Zd() == (int)old.Zd() &&
1558 (int)ist.Az() == (int)old.Az())
1559 continue;
1560 */
1561 ZdAz istre = GetRePosPdo();
1562
1563 //
1564 // Get time from last shaftencoder position change (position: ist)
1565 // FIXME: I cannot take the avarage
1566 //
1567 // FIXME
1568 //time.Zd(fZd1->GetMjd());
1569 /* OLD* */
1570 if (fZd1->GetMjd()>fZd2->GetMjd())
1571 time.Zd(fZd1->GetMjd());
1572 else
1573 time.Zd(fZd2->GetMjd());
1574
1575 //time.Zd((fZd1->GetMjd()+fZd2->GetMjd())/2.0);
1576 time.Az(fAz->GetMjd());
1577
1578 //
1579 // if Shaftencoder changed position
1580 // calculate were we should be
1581 //
1582 if (phca1 || phca2 /*(int)ist.Zd() != (int)old.Zd()*/)
1583 {
1584 sollzd = sla.CalcZdAz(fRaDec, time.Zd()); // [rad]
1585 /*
1586 ZdAz dummy = fBending(sla.CalcZdAz(fRaDec));
1587 sollzd = CorrectTarget(ist, dummy); // [se]
1588 */
1589 fOffset.Zd(fOffset.Zd()*(1.-weight)+(ist.Zd()*kGearRatio.X()-istre.Zd())*weight);
1590 }
1591
1592 if (phcaz /*(int)ist.Az() != (int)old.Az()*/)
1593 {
1594 sollaz = sla.CalcZdAz(fRaDec, time.Az()); // [rad]
1595 /*
1596 ZdAz dummy = fBending(sla.CalcZdAz(fRaDec));
1597 sollaz = CorrectTarget(ist, dummy); // [se]
1598 */
1599 fOffset.Az(fOffset.Az()*(1.-weight)+(ist.Az()*kGearRatio.Y()-istre.Az())*weight);
1600 }
1601
1602 ZdAz soll(sollzd.Zd(), sollaz.Az()); // [rad]
1603
1604 AlignTrackingPos(soll*kRad2Deg, fZdAzSoll);
1605
1606 ist *= TMath::Pi()*2/16384;
1607 soll = fBending(fZdAzSoll);
1608 fTrackingError.Set(ist.Zd()-soll.Zd(), ist.Az()-soll.Az());
1609
1610 //--- fout << setprecision(15) << setw(17) << time.Zd()*60.*60.*24. << " ";
1611 //--- fout << setprecision(5) << setw(7) << fTrackingError.Zd() << " ";
1612 //--- fout << setprecision(15) << setw(17) << time.Az()*60.*60.*24. << " ";
1613 //--- fout << setprecision(5) << setw(7) << fTrackingError.Az() << endl;
1614 }
1615
1616 lout << "Tracking Thread done." << endl;
1617
1618 //--- fout << endl << endl;
1619}
1620
1621void MCosy::TalkThreadSeTest()
1622{
1623// if (fZd1->IsZombieNode() || fZd2->IsZombieNode())
1624 // return;
1625
1626 if (fHist)
1627 {
1628 lout << "You are much too fast... try again." << endl;
1629 return;
1630 }
1631
1632 fHist = new TH2F("Diff", "Difference of SE values",
1633 201, fMin.Zd(), fMax.Zd(), 41, -10.5, 10.5);
1634 fHist->SetXTitle("ZA [\\circ]");
1635 fHist->SetYTitle("\\Delta SE");
1636
1637 Double_t offset = 0;
1638
1639 int cnt = 0;
1640
1641 lout << "Starting Shaftencoder Test..." << endl;
1642
1643 while (fBackground==kBgdSeTest)
1644 {
1645 fZd1->ResetPosHasChanged();
1646 fZd2->ResetPosHasChanged();
1647
1648 while (!fZd1->PosHasChanged() && !fZd2->PosHasChanged() &&
1649 fBackground==kBgdSeTest)
1650 usleep(1);
1651
1652 const Double_t pos[3] = {
1653 (fZd1->GetPos()+8192)%16384,
1654 (fZd2->GetPos()+8192)%16384,
1655 fAz->GetPos() };
1656
1657 //
1658 // Estimate Offset from the first ten positions
1659 //
1660 if (cnt++<10)
1661 {
1662 offset += pos[0]+pos[1];
1663 continue;
1664 }
1665 if (cnt==11)
1666 {
1667 offset /= 10;
1668 cnt++;
1669 }
1670
1671 Double_t apos = (pos[0]-pos[1])/2 * TMath::Pi()*2 / 16384;
1672
1673 ZdAz bend = fBending.CorrectBack(ZdAz(apos, pos[2]))*kRad2Deg;
1674 fHist->Fill(bend.Zd(), pos[0]+pos[1]-offset);
1675 }
1676
1677 lout << "Shaftencoder Test Stopped... displaying Histogram." << endl;
1678
1679 fBackground=kBgdSeTestDispl;
1680}
1681
1682void MCosy::TalkThreadGear()
1683{
1684// if (fZd1->IsZombieNode() || fZd2->IsZombieNode())
1685 // return;
1686
1687 if (fHist)
1688 {
1689 lout << "You are much too fast... try again." << endl;
1690 return;
1691 }
1692
1693 fHist = new TH3F("Gear", "Gear Ratio Re/Se",
1694 (int)((fMax.Zd()-fMin.Zd())/2.5+1), fMin.Zd(), fMax.Zd(),
1695 (int)((fMax.Az()-fMin.Az())/2.5+1), fMin.Az(), fMax.Az(),
1696 61, 349.5, 500.5);
1697
1698 fHist->SetXTitle("Zd [\\circ]");
1699 fHist->SetYTitle("Az [\\circ]");
1700 fHist->SetZTitle("Re/Se");
1701
1702 lout << "Starting Gear determination..." << endl;
1703
1704 ZdAz se0 = GetSePos();
1705 ZdAz re0 = GetRePosPdo();
1706
1707 while (fBackground==kBgdGear)
1708 {
1709 fZd1->ResetPosHasChanged();
1710 fZd2->ResetPosHasChanged();
1711 fAz->ResetPosHasChanged();
1712
1713 while (!fZd1->PosHasChanged() && !fZd2->PosHasChanged() &&
1714 !fAz->PosHasChanged() && fBackground==kBgdGear)
1715 usleep(1);
1716
1717 ZdAz se = GetSePos();
1718 ZdAz re = GetRePosPdo();
1719
1720 ZdAz dse = se-se0;
1721 ZdAz dre = re-re0;
1722
1723 if (fabs(dse.Zd())*144>16384) // Each 2.5deg (144)
1724 {
1725 se0.Zd(se.Zd());
1726 re0.Zd(re.Zd());
1727
1728 se -= dse/2;
1729
1730 ZdAz bend = fBending.CorrectBack(se*2*TMath::Pi()/16384)*kRad2Deg;
1731 ((TH3*)fHist)->Fill(bend.Zd(), bend.Az(), dre.Zd()/dse.Zd());
1732 }
1733
1734 if (fabs(dse.Az())*144>16384) // Each 2.5deg (144)
1735 {
1736 se0.Az(se.Az());
1737 re0.Az(re.Az());
1738
1739 se -= dse/2;
1740
1741 ZdAz bend = fBending.CorrectBack(se*2*TMath::Pi()/16384)*kRad2Deg;
1742 ((TH3*)fHist)->Fill(bend.Az(), bend.Az(), dre.Az()/dse.Az());
1743 }
1744 }
1745 lout << "Gear Test Stopped... displaying Histogram." << endl;
1746
1747 fBackground=kBgdGearDispl;
1748}
1749
1750void MCosy::TalkThread()
1751{
1752 /* ========== FIXME? =============
1753 if (fMac1->IsZombieNode() || fMac2->IsZombieNode())
1754 return;
1755 */
1756
1757 if (fMac1 && fMac2)
1758 {
1759 fMac1->ReqPos();
1760 fMac2->ReqPos();
1761 }
1762
1763 InitSync();
1764
1765 /*** FOR DEMO MODE ***/
1766 if (!fZd1 || !fZd2 || !fAz)
1767 return;
1768 /*** FOR DEMO MODE ***/
1769
1770 //
1771 // Start the Network
1772 //
1773 while (1)
1774 {
1775 //
1776 // wait until a tracking session is started
1777 //
1778 while (fBackground==kBgdNone)
1779 usleep(1);
1780
1781 switch (fBackground)
1782 {
1783 case kBgdNone:
1784 continue;
1785
1786 case kBgdTracking:
1787 TalkThreadTracking();
1788 continue;
1789
1790 case kBgdSeTest:
1791 TalkThreadSeTest();
1792 continue;
1793
1794 case kBgdGear:
1795 TalkThreadGear();
1796 continue;
1797
1798 default:
1799 continue;
1800 }
1801 }
1802}
1803
1804ZdAz MCosy::GetPointingPos() const
1805{
1806 // GetPointingPos [deg]
1807 const ZdAz seist = GetSePos()*2*TMath::Pi()/16384; // [se]
1808 return fBending.CorrectBack(seist)*180/TMath::Pi();
1809}
1810
1811Bool_t MCosy::HandleTimer(TTimer *t)
1812{
1813 //
1814 // Update Gui, foremer MTGui.
1815 //
1816 if (fZd1)
1817 fZd1->DisplayVal();
1818 if (fZd2)
1819 fZd2->DisplayVal();
1820 if (fAz)
1821 fAz->DisplayVal();
1822
1823 ZdAz bendist = GetPointingPos();
1824
1825 Byte_t avail = 0;
1826
1827 avail |= (fMac1 && !fMac1->IsZombieNode()) ? 0x01 : 0;
1828 avail |= (fMac2 && !fMac2->IsZombieNode()) ? 0x02 : 0;
1829 avail |= (fMac3 && !fMac3->IsZombieNode()) ? 0x04 : 0;
1830 avail |= (fZd1 && !fZd1->IsZombieNode()) ? 0x08 : 0;
1831 avail |= (fZd2 && !fZd2->IsZombieNode()) ? 0x10 : 0;
1832 avail |= (fAz && !fAz->IsZombieNode()) ? 0x20 : 0;
1833
1834 if (HasError())
1835 SetStatus(MCosy::kError);
1836
1837 lout.UpdateGui();
1838
1839 fWin->Update(bendist, fTrackingError, fVelocity, /*fOffset,*/
1840 fRaDec, fZdAzSoll, fStatus, avail);
1841
1842 const Bool_t trigger = fTriggerDisplay;
1843 fTriggerDisplay = kFALSE;
1844
1845 if (fBackground==kBgdSeTestDispl || (trigger&&fBackground==kBgdSeTest))
1846 DisplayHistTestSe(!trigger);
1847
1848 if (fBackground==kBgdGearDispl || (trigger&&fBackground==kBgdGear))
1849 DisplayHistGear(!trigger);
1850
1851 return kTRUE;
1852}
1853
1854void MCosy::DisplayHistTestSe(Bool_t del)
1855{
1856 lout << "Displaying histogram..." << endl;
1857
1858 TH2F &hist = *(TH2F*)fHist;
1859
1860 if (del)
1861 {
1862 fHist = NULL;
1863 fBackground = kBgdNone;
1864 }
1865
1866 TCanvas *c=new TCanvas("c1", "", 1000, 1000);
1867 c->Divide(1,2);
1868
1869 c->cd(1);
1870 TH2 *h=(TH2*)hist.DrawCopy();
1871
1872 TProfile *p = h->ProfileX("_pfx", -1, 9999, "s");
1873 p->SetLineColor(kBlue);
1874 p->Draw("same");
1875 p->SetBit(kCanDelete);
1876
1877 c->cd(2);
1878
1879 TH1F p2("spread", "Spread of the differences", hist.GetNbinsX(), hist.GetBinLowEdge(1),
1880 hist.GetBinLowEdge(hist.GetNbinsX()+1));
1881 p2.SetXTitle("Zd [\\circ]");
1882 for (int i=0; i<hist.GetNbinsX(); i++)
1883 p2.SetBinError(i, p->GetBinError(i));
1884 p2.SetLineColor(kRed);
1885 p2.SetStats(0);
1886 p2.DrawCopy();
1887
1888 if (del)
1889 delete &hist;
1890}
1891
1892void MCosy::DisplayHistGear(Bool_t del)
1893{
1894 lout << "Displaying histogram..." << endl;
1895
1896 TH3F &hist = *(TH3F*)fHist;
1897
1898 if (del)
1899 {
1900 fHist = NULL;
1901 fBackground = kBgdNone;
1902 }
1903
1904 TCanvas *c=new TCanvas("c1", "", 1000, 1000);
1905 c->Divide(2,2);
1906
1907 // ----------
1908
1909 c->cd(1);
1910 TH2D &h1=*(TH2D*)hist.Project3D("zx"); // Zd
1911 h1.SetTitle(" Gear Ratio Zenith Distance [re/se] ");
1912 h1.SetXTitle("Zd [\\circ]");
1913 h1.Draw();
1914 h1.SetBit(kCanDelete);
1915
1916 TProfile *p1 = h1.ProfileX("_pfx", -1, 9999, "s");
1917 p1->SetLineColor(kBlue);
1918 p1->Draw("same");
1919 p1->SetBit(kCanDelete);
1920
1921 // ----------
1922
1923 c->cd(2);
1924 TH2D &h2=*(TH2D*)hist.Project3D("zy"); // Az
1925 h2.SetTitle(" Gear Ratio Azimuth [re/se] ");
1926 h2.SetXTitle("Zd [\\circ]");
1927 h2.Draw();
1928 h2.SetBit(kCanDelete);
1929
1930 TProfile *p2 = h2.ProfileX("_pfx", -1, 9999, "s");
1931 p2->SetLineColor(kBlue);
1932 p2->Draw("same");
1933 p2->SetBit(kCanDelete);
1934
1935 // ----------
1936
1937 c->cd(3);
1938
1939 TAxis &axe1 = *h1.GetXaxis();
1940
1941 TH1F f1("spreadzd", " Spread Zenith Distance ",
1942 axe1.GetNbins(), axe1.GetXmin(), axe1.GetXmax());
1943 f1.SetXTitle("Zd [\\circ]");
1944 for (int i=0; i<axe1.GetNbins(); i++)
1945 f1.SetBinError(i, p1->GetBinError(i));
1946 f1.SetLineColor(kRed);
1947 f1.SetStats(0);
1948 f1.DrawCopy();
1949
1950 c->cd(4);
1951
1952 // ----------
1953
1954 TAxis &axe2 = *h2.GetXaxis();
1955
1956 TH1F f2("spreadaz", " Spread Azimuth ",
1957 axe2.GetNbins(), axe2.GetXmin(), axe2.GetXmax());
1958 f2.SetXTitle("Az [\\circ]");
1959 for (int i=0; i<axe2.GetNbins(); i++)
1960 f2.SetBinError(i, p2->GetBinError(i));
1961 f2.SetLineColor(kRed);
1962 f2.SetStats(0);
1963 f2.DrawCopy();
1964
1965 // ----------
1966
1967 if (del)
1968 delete &hist;
1969}
1970
1971// --------------------------------------------------------------------------
1972//
1973// Start the work of the application:
1974//
1975// Start the Can-Network.
1976// Start the MCosy::TalkThread thread.
1977// turn on the gui update
1978//
1979void MCosy::Start()
1980{
1981 // Don't call this function twice!
1982 Network::Start();
1983
1984 ReadConfig();
1985
1986 lout << "- Starting TX Thread." << endl;
1987 fTTalk = new MTTalk(this);
1988
1989 lout << "- Starting GUI update." << endl;
1990 fUpdateGui->TurnOn();
1991}
1992
1993// --------------------------------------------------------------------------
1994//
1995// Start the work of the application:
1996//
1997// Turn of the gui update
1998// stop the MCosy::TalkThread thread.
1999// Stop the network
2000//
2001void MCosy::Stop()
2002{
2003 lout << "- Stopping GUI update." << endl;
2004 fUpdateGui->TurnOff();
2005 lout << "- GUI Update stopped." << endl;
2006
2007 delete fTTalk;
2008 lout << "- TX Thread stopped." << endl;
2009
2010 Network::Stop();
2011}
2012
2013// --------------------------------------------------------------------------
2014//
2015// Disable the synchronization by using a negative CAN Id for id2.
2016//
2017void MCosy::Constructor(Int_t id1, Int_t id2, Int_t id3,
2018 Int_t id4, Int_t id5, Int_t id6)
2019{
2020 //
2021 // Create Nodes
2022 //
2023 lout << "- Setting up network." << endl;
2024
2025 fMac1=new Macs(id1, "Mac/Az", lout);
2026 fMac2=new Macs(id3, "Mac/Zd", lout);
2027 if (id2>=0)
2028 fMac3=new Macs(id2, "Mac/Az-Sync", lout);
2029
2030 fZd1=new ShaftEncoder(id4, "SE/Zd1", lout);
2031 fZd2=new ShaftEncoder(id5, "SE/Zd2", lout);
2032 fAz =new ShaftEncoder(id6, "SE/Az", lout);
2033
2034 lout << "- Connecting devices to network." << endl;
2035
2036 //
2037 // Connect the devices to the network
2038 //
2039 SetNode(fMac1);
2040 SetNode(fMac2);
2041 if (id2>=0)
2042 SetNode(fMac3);
2043 SetNode(fZd1);
2044 SetNode(fZd2);
2045 SetNode(fAz);
2046
2047 //
2048 // Create Gui Event timer and Gui
2049 //
2050 lout << "- Initializing GUI Timer." << endl;
2051 fUpdateGui = new TTimer(this, 100); // 100ms
2052
2053 lout << "- Starting GUI." << endl;
2054 fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1);
2055}
2056
2057void MCosy::ConstructorSE(Int_t id4, Int_t id5, Int_t id6)
2058{
2059 //
2060 // Create Nodes
2061 //
2062 lout << "- Setting up network." << endl;
2063
2064 fZd1=new ShaftEncoder(id4, "SE/Zd1", lout);
2065 fZd2=new ShaftEncoder(id5, "SE/Zd2", lout);
2066 fAz =new ShaftEncoder(id6, "SE/Az", lout);
2067
2068 lout << "- Connecting devices to network." << endl;
2069
2070 //
2071 // Connect the devices to the network
2072 //
2073 SetNode(fZd1);
2074 SetNode(fZd2);
2075 SetNode(fAz);
2076
2077 //
2078 // Create Gui Event timer and Gui
2079 //
2080 lout << "- Initializing GUI Timer." << endl;
2081 fUpdateGui = new TTimer(this, 100); // 100ms
2082
2083 lout << "- Starting GUI." << endl;
2084 fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1);
2085}
2086
2087void MCosy::ConstructorDemo()
2088{
2089 //
2090 // Create Nodes
2091 //
2092 lout << "- Setting up network." << endl;
2093
2094 //
2095 // Create Gui Event timer and Gui
2096 //
2097 lout << "- Initializing GUI Timer." << endl;
2098 fUpdateGui = new TTimer(this, 100); // 100ms
2099
2100 lout << "- Starting GUI." << endl;
2101 fWin=new MGCosy(fObservatory, this, gClient->GetRoot(), 1, 1);
2102}
2103
2104MCosy::MCosy(int mode, const char *dev, const int baud, MLog &out)
2105: Network(dev, baud, out), fObservatory(MObservatory::kMagic1), fStarguider(NULL), fZd1(0), fZd2(0), fAz(0), fMac1(0), fMac2(0), fMac3(0), fBackground(kBgdNone), fStatus(kStopped)
2106{
2107 TEnv env(".cosyrc");
2108 const Int_t id1 = env.GetValue("Az_Id-MAC1", 1); //1
2109 const Int_t id2 = env.GetValue("Az_Id-MAC2", 2); //2
2110 const Int_t id3 = env.GetValue("Zd_Id-MAC", 3); //3
2111 const Int_t id4 = env.GetValue("Zd_Id-SE1", 4); //4
2112 const Int_t id5 = env.GetValue("Zd_Id-SE2", 5); //5
2113 const Int_t id6 = env.GetValue("Az_Id-SE", 6); //6
2114
2115 lout << "- Program in ";
2116 switch (mode)
2117 {
2118 case 0:
2119 lout << "<<Stanard mode>>" << endl;
2120 fBending.Load("bending.txt");
2121 Constructor(id1, id2, id3, id4, id5, id6);
2122 break;
2123 case 1:
2124 lout << "<<SE mode>>" << endl;
2125 fBending.Load("bending.txt");
2126 ConstructorSE(id4, id5, id6);
2127 break;
2128 default:
2129 lout << "<<Demo mode>>" << endl;
2130 ConstructorDemo();
2131 }
2132
2133 lout.SetOutputGui(fWin->GetLog(), kTRUE);
2134
2135 fZd1->SetDisplay(fWin->GetLabel2());
2136 fZd2->SetDisplay(fWin->GetLabel3());
2137 fAz->SetDisplay(fWin->GetLabel1());
2138
2139 int i=0;
2140 char name[100];
2141 while (1)
2142 {
2143 sprintf(name, "tpoint/tpoint%03d.txt", i++);
2144 if (gSystem->AccessPathName(name, kFileExists))
2145 break;
2146 }
2147
2148 Timer time;
2149 time.Now();
2150
2151 cout << "TPoint File ********* " << name << " ********** " << endl;
2152
2153 tpout = new ofstream(name);
2154 *tpout << "Magic Model TPOINT data file" << endl;
2155 *tpout << ": ALTAZ" << endl;
2156 *tpout << "49 48 0 ";
2157 *tpout << time.Year() << " " << time.Month() << " " << time.Day() << " ";
2158 *tpout << /*"20 1013.25 300 0.5 0.55 0.0065" <<*/ endl;
2159 // temp(°C) pressure(mB) height(m) humidity(1) wavelength(microm) troplapserate(K/m)
2160}
2161
2162void MCosy::TerminateApp()
2163{
2164 cout << "MCosy::TerminateApp()" << endl;
2165/*
2166 Int_t rc;
2167 TGMessageBox msg(this, gClient->GetRoot(),
2168 "Information",
2169 "Cosy is shutting down the system - this may take wa while!",
2170 kMBIconExclamation,
2171 kMBOK, //kMBClose
2172 &rc, 0);
2173*/
2174
2175 lout.DisableOutputDevice(MLog::eGui);
2176 // FIXME: WHY DOES THIS CRASH THE APPLICATIOn WHILE TRAKING?
2177 // lout.SetOutputGui(NULL, kFALSE);
2178
2179 gApplication->Terminate(0);
2180}
2181
2182MCosy::~MCosy()
2183{
2184 *tpout << "END" << endl;
2185 //streampos size = tpout.tellp();
2186 delete tpout;
2187
2188 cout << "Deleting GUI timer." << endl;
2189
2190 delete fUpdateGui;
2191
2192 cout << "Deleting Nodes." << endl;
2193
2194 delete fAz;
2195 delete fZd1;
2196 delete fZd2;
2197 delete fMac1;
2198 delete fMac2;
2199 if (fMac3)
2200 delete fMac3;
2201
2202 cout << "Deleting MGCosy." << endl;
2203
2204 lout.DisableOutputDevice(MLog::eGui);
2205
2206 delete fWin;
2207
2208 cout << "MGCosy destructed." << endl;
2209}
Note: See TracBrowser for help on using the repository browser.