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

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