1 #include <boost/regex.hpp> 2 #include <boost/algorithm/string.hpp> 25 namespace ba = boost::asio;
26 namespace bs = boost::system;
29 using namespace Drive;
39 RaDec(
double _ra,
double _dec) : ra(_ra), dec(_dec) { }
46 RaDecHa(
double _ra,
double _dec,
double _ha) :
RaDec(_ra, _dec), ha(_ha) { }
54 Local(
double _zd=0,
double _az=0) : zd(_zd), az(_az) { }
77 ZdAz(
double _zd=0,
double _az=0) :
Local(_zd, _az) { }
86 return zd>a.
zd || az>a.
az;
213 throw runtime_error(
"Cannot open file "+name+
": "+strerror(errno));
215 map<string,double> coeff;
218 while (getline(fin, buf))
223 boost::split(vec, buf, boost::is_any_of(
" "), boost::token_compress_on);
227 coeff[vec[0]] = atof(vec[1].c_str()) * M_PI/180;
232 fFlop = coeff[
"FLOP"];
233 fNpae = coeff[
"NPAE"];
245 fEces = coeff[
"ECES"];
246 fAces = coeff[
"ACES"];
247 fEcec = coeff[
"ECEC"];
248 fAcec = coeff[
"ACEC"];
256 AltAz(
double _alt,
double _az) : alt(_alt), az(_az) { }
257 AltAz(
const ZdAz &za) : alt(M_PI/2-za.zd), az(za.az) { }
263 double Sign(
double val,
double alt)
const 268 return (M_PI/2-alt < 0 ? -val : val);
278 const AltAz NRX(fNrx*sin(p.
alt), -fNrx);
279 const AltAz NRY(fNry*cos(p.
alt), -fNry*tan(p.
alt));
283 const AltAz CES(-fEces*sin(p.
alt), -fAces*sin(p.
az));
284 const AltAz CEC(-fEcec*cos(p.
alt), -fAcec*cos(p.
az));
296 const AltAz NPAE(0, -fNpae*tan(p.
alt));
299 const AltAz AW2( fAw2*sin(p.
az*2), -fAw2*cos(p.
az*2)*tan(p.
alt));
300 const AltAz AN2(-fAn2*cos(p.
az*2), -fAn2*sin(p.
az*2)*tan(p.
alt));
301 const AltAz AW1( fAw *sin(p.
az), -fAw *cos(p.
az) *tan(p.
alt));
302 const AltAz AN1(-fAn *cos(p.
az), -fAn *sin(p.
az) *tan(p.
alt));
308 const AltAz FLOP(Sign(fFlop, p.
alt), 0);
311 const AltAz I(fIe, fIa);
319 AltAz p(M_PI/2-mnt.
zd*M_PI/180, mnt.
az*M_PI/180);
321 const AltAz I(fIe, fIa);
324 const AltAz FLOP(Sign(fFlop, p.
alt), 0);
327 const AltAz AW1( fAw *sin(p.
az), -fAw *cos(p.
az) *tan(p.
alt));
328 const AltAz AN1(-fAn *cos(p.
az), -fAn *sin(p.
az) *tan(p.
alt));
329 const AltAz AW2( fAw2*sin(p.
az*2), -fAw2*cos(p.
az*2)*tan(p.
alt));
330 const AltAz AN2(-fAn2*cos(p.
az*2), -fAn2*sin(p.
az*2)*tan(p.
alt));
336 const AltAz NPAE(0, -fNpae*tan(p.
alt));
347 const AltAz CEC(-fEcec*cos(p.
alt), -fAcec*cos(p.
az));
348 const AltAz CES(-fEces*sin(p.
alt), -fAces*sin(p.
az));
352 const AltAz NRY(fNry*cos(p.
alt), -fNry*tan(p.
alt));
353 const AltAz NRX(fNrx*sin(p.
alt), -fNrx);
370 const double elong =
Nova::ORM().lng * M_PI/180;
372 const double height = 2200;
374 const bool valid = weather.
time+boost::posix_time::seconds(timeout) >
Time();
376 const double temp = valid ? weather.
temp : 10;
377 const double hum = valid ? weather.
hum : 0.25;
378 const double press = valid ? weather.
press : 780;
380 const double dtt =
palDtt(_mjd);
382 const double tdb = _mjd + dtt/3600/24;
383 const double dut = 0;
395 273.155+temp, press, hum,
406 double ra, dec, diam;
425 const double cosdir = cos(phi);
426 const double sindir = sin(phi);
429 const double cosdec = cos(out.
source.
dec);
430 const double sindec = sin(out.
source.
dec);
432 const double sintheta = sindec*cosoff + cosdec*sinoff*cosdir;
434 const double costheta = sintheta>1 ? 0 : sqrt(1 - sintheta*sintheta);
436 const double cosdeltara = (cosoff - sindec*sintheta)/(cosdec*costheta);
437 const double sindeltara = sindir*sinoff/costheta;
471 out.
sky.
az -= 2*M_PI;
538 uint8_t m0=0, uint8_t m1=0, uint8_t m2=0, uint8_t m3=0,
539 uint8_t m4=0, uint8_t m5=0, uint8_t m6=0, uint8_t m7=0)
541 const uint16_t desc = (cobid<<5) | 8;
543 vector<uint8_t>
data(11);
548 const uint8_t msg[8] = { m0, m1, m2, m3, m4, m5, m6, m7 };
549 memcpy(data.data()+3, msg, 8);
558 kReqErrStat = 0x1003,
559 kReqSoftVer = 0x100a,
560 kReqKeepAlive = 0x100b,
568 kSetPointVel = 0x2002,
570 kSetRpmMode = 0x3006,
571 kSetTrackVel = 0x3007,
572 kSetLedVoltage = 0x4000,
573 kSetPosition = 0x6004,
576 static uint32_t
String(uint8_t b0=0, uint8_t b1=0, uint8_t b2=0, uint8_t b3=0)
578 return uint32_t(b0)<<24 | uint32_t(b1)<<16 | uint32_t(b2)<<8 | uint32_t(b3);
585 uint32_t fErrCode[2];
587 void HandleSdo(
const uint8_t &
node,
const uint16_t &idx,
const uint8_t &subidx,
588 const uint32_t &val,
const Time &tv)
594 out <<
"SDO[" << int(node) <<
"] " << idx <<
"/" << int(subidx) <<
": " << val << dec;
595 Out() << out.str() << endl;
606 fErrCode[node/2] = (val>>8);
617 fIsInitialized[node/2] =
true;
628 fPdoPos1[node/2] = val;
629 fPdoTime1[node/2] = tv;
630 fHasChangedPos1[node/2] =
true;
633 fPdoPos2[node/2] = val;
634 fPdoTime2[node/2] = tv;
635 fHasChangedPos2[node/2] =
true;
641 fVelRes[node/2] = val;
645 fVelMax[node/2] = val;
649 fPosRes[node/2] = val;
654 str <<
"HandleSDO: Idx=0x"<< hex << idx <<
"/" << (int)subidx;
655 str <<
", val=0x" << val;
664 out <<
"SDO-OK[" << int(node) <<
"] " << idx <<
"/" << int(subidx) << dec <<
" ";
669 out <<
"(Armed state set)";
677 out <<
"(Pointing velocity set)";
681 out <<
"(Acceleration set)";
685 out <<
"(RPM mode set)";
689 out <<
"(LED Voltage set)";
710 out <<
"(Absolute positioning started)";
725 Out() << out.str() << endl;
733 out <<
"SDO-ERR[" << int(node) <<
"] " << idx <<
"/" << int(subidx) << dec;
734 Out() << out.str() << endl;
745 bool fHasChangedPos1[2];
746 bool fHasChangedPos2[2];
750 const uint32_t pos1 = (data[3]<<24) | (data[2]<<16) | (data[1]<<8) | data[0];
751 const uint32_t pos2 = (data[7]<<24) | (data[6]<<16) | (data[5]<<8) | data[4];
754 Out() <<
Time().
GetAsStr(
"%M:%S.%f") <<
" PDO1[" << (int)node <<
"] " << 360.*int32_t(pos1)/fPosRes[node/2] <<
" " << 360.*int32_t(pos2)/fPosRes[node/2] << endl;
758 fPdoPos1[node/2] = pos1;
759 fPdoTime1[node/2] = tv;
760 fHasChangedPos1[node/2] =
true;
762 fPdoPos2[node/2] = pos2;
763 fPdoTime2[node/2] = tv;
764 fHasChangedPos2[node/2] =
true;
767 uint8_t fStatusAxis[2];
809 const uint8_t sys = ((data[0] & 0x1c)<<2) | (data[1]);
814 const bool alarm = sys&kUpsAlarm;
815 const bool batt = sys&kUpsBattery;
816 const bool charge = sys&kUpsCharging;
817 const bool emcy = sys&kEmergencyOk;
818 const bool vltg = sys&kOvervoltOk;
819 const bool mode = sys&kManualMode;
822 if (alarm) out <<
" UPS-PowerLoss";
823 if (batt) out <<
" UPS-OnBattery";
824 if (charge) out <<
" UPS-Charging";
825 if (emcy) out <<
" EmcyOk";
826 if (vltg) out <<
" OvervoltOk";
827 if (mode) out <<
" ManualMove";
829 Info(
"New system status["+to_string(node)+
"]:"+out.str());
831 Out() <<
"PDO3[" << (int)node <<
"] StatusSys=" << hex << (
int)fStatusSys << dec << endl;
834 const uint8_t axis = (data[0]&0xa1) | (data[3]&0x06);
835 if (fStatusAxis[node/2]!=axis)
837 fStatusAxis[node/2] = axis;
839 const bool ready = axis&kAxisBb;
840 const bool move = axis&kAxisMoving;
841 const bool rpm = axis&kAxisRpmMode;
842 const bool rf = axis&kAxisRf;
843 const bool power = axis&kAxisHasPower;
846 if (ready) out <<
" DKC-Ready";
847 if (move) out <<
" Moving";
848 if (rpm) out <<
" RpmMode";
849 if (rf) out <<
" RF";
850 if (power) out <<
" PowerOn";
852 Info(
"New axis status["+to_string(node)+
"]:"+out.str());
854 Out() <<
"PDO3[" << (int)node <<
"] StatusAxis=" << hex << (
int)fStatusAxis[node/2] << dec << endl;
857 array<uint8_t, 3> arr = {{ fStatusAxis[0], fStatusAxis[1], fStatusSys }};
858 UpdateStatus(tv, arr);
865 case 0:
return "offline";
866 case 0xa000:
case 0xa0000:
867 case 0xa001:
case 0xa0001:
868 case 0xa002:
case 0xa0002:
869 case 0xa003:
case 0xa0003:
return "Communication phase "+to_string(code&0xf);
870 case 0xa010:
case 0xa0010:
return "Drive HALT";
871 case 0xa012:
case 0xa0012:
return "Control and power section ready for operation";
872 case 0xa013:
case 0xa0013:
return "Ready for power on";
873 case 0xa100:
case 0xa0100:
return "Drive in Torque mode";
874 case 0xa101:
case 0xa0101:
return "Drive in Velocity mode";
875 case 0xa102:
case 0xa0102:
return "Position control mode with encoder 1";
876 case 0xa103:
case 0xa0103:
return "Position control mode with encoder 2";
877 case 0xa104:
case 0xa0104:
return "Position control mode with encoder 1, lagless";
878 case 0xa105:
case 0xa0105:
return "Position control mode with encoder 2, lagless";
879 case 0xa106:
case 0xa0106:
return "Drive controlled interpolated positioning with encoder 1";
880 case 0xa107:
case 0xa0107:
return "Drive controlled interpolated positioning with encoder 2";
881 case 0xa108:
case 0xa0108:
return "Drive controlled interpolated positioning with encoder 1, lagless";
882 case 0xa109:
case 0xa0109:
return "Drive controlled interpolated positioning with encoder 2, lagless";
887 case 0xa150:
case 0xa0150:
return "Drive controlled positioning with encoder 1";
888 case 0xa151:
case 0xa0151:
return "Drive controlled positioning with encoder 1, lagless";
889 case 0xa152:
case 0xa0152:
return "Drive controlled positioning with encoder 2";
890 case 0xa153:
case 0xa0153:
return "Drive controlled positioning with encoder 2, lagless";
891 case 0xa208:
return "Jog mode positive";
892 case 0xa218:
return "Jog mode negative";
893 case 0xa400:
case 0xa4000:
return "Automatic drive check and adjustment";
894 case 0xa401:
case 0xa4001:
return "Drive decelerating to standstill";
895 case 0xa800:
case 0xa0800:
return "Unknown operation mode";
896 case 0xc217:
return "Motor encoder reading error";
897 case 0xc218:
return "Shaft encoder reading error";
898 case 0xc220:
return "Motor encoder initialization error";
899 case 0xc221:
return "Shaft encoder initialization error";
900 case 0xc300:
return "Command: set absolute measure";
901 case 0xc400:
case 0xc0400:
return "Switching to parameter mode";
902 case 0xc401:
case 0xc0401:
return "Drive active, switching mode not allowed";
903 case 0xc500:
case 0xc0500:
return "Error reset";
904 case 0xc600:
case 0xc0600:
return "Drive controlled homing procedure";
905 case 0xe225:
return "Motor overload";
906 case 0xe249:
case 0xe2049:
return "Positioning command velocity exceeds limit bipolar";
907 case 0xe250:
return "Drive overtemp warning";
908 case 0xe251:
return "Motor overtemp warning";
909 case 0xe252:
return "Bleeder overtemp warning";
910 case 0xe257:
return "Continous current limit active";
911 case 0xe2819:
return "Main power failure";
912 case 0xe259:
return "Command velocity limit active";
913 case 0xe8260:
return "Torque limit active";
914 case 0xe264:
return "Target position out of numerical range";
915 case 0xe829:
case 0xe8029:
return "Positive position limit exceeded";
916 case 0xe830:
case 0xe8030:
return "Negative position limit exceeded";
917 case 0xe831:
return "Position limit reached during jog";
918 case 0xe834:
return "Emergency-Stop";
919 case 0xe842:
return "Both end-switches activated";
920 case 0xe843:
return "Positive end-switch activated";
921 case 0xe844:
return "Negative end-switch activated";
922 case 0xf218:
case 0xf2018:
return "Amplifier overtemp shutdown";
923 case 0xf219:
case 0xf2019:
return "Motor overtemp shutdown";
924 case 0xf220:
return "Bleeder overload shutdown";
925 case 0xf221:
case 0xf2021:
return "Motor temperature surveillance defective";
926 case 0xf2022:
return "Unit temperature surveillance defective";
927 case 0xf224:
return "Maximum breaking time exceeded";
928 case 0xf2025:
return "Drive not ready for power on";
929 case 0xf228:
case 0xf2028:
return "Excessive control deviation";
930 case 0xf250:
return "Overflow of target position preset memory";
931 case 0xf257:
case 0xf2057:
return "Command position out of range";
932 case 0xf269:
return "Error during release of the motor holding brake";
933 case 0xf276:
return "Absolute encoder moved out of monitoring window";
934 case 0xf2074:
return "Absolute encoder 1 moved out of monitoring window";
935 case 0xf2075:
return "Absolute encoder 2 moved out of monitoring window";
936 case 0xf2174:
return "Lost reference of motor encoder";
937 case 0xf409:
case 0xf4009:
return "Bus error on Profibus interface";
938 case 0xf434:
return "Emergency-Stop";
939 case 0xf629:
return "Positive position limit exceeded";
940 case 0xf630:
return "Negative position limit exceeded";
941 case 0xf634:
return "Emergency-Stop";
942 case 0xf643:
return "Positive end-switch activated";
943 case 0xf644:
return "Negative end-switch activated";
944 case 0xf8069:
return "15V DC error";
945 case 0xf870:
case 0xf8070:
return "24V DC error";
946 case 0xf878:
case 0xf8078:
return "Velocity loop error";
947 case 0xf8079:
return "Velocity limit exceeded";
948 case 0xf2026:
return "Undervoltage in power section";
955 const uint8_t typ = fErrCode[node/2]>>16;
958 out <<
"IndraDrive ";
959 out << (node==1?
"Az":
"Zd");
960 out <<
" [" << hex << fErrCode[node/2];
962 out << ErrCodeToString(fErrCode[node/2]);
963 out << (typ==0xf || typ==0xe ?
"!" :
".");
967 case 0xf:
Error(out);
break;
968 case 0xe: Warn(out);
break;
969 case 0xa: Info(out);
break;
972 case 0xd: Message(out);
break;
973 default: Fatal(out);
break;
979 fErrCode[node/2] = (data[4]<<24) | (data[5]<<16) | (data[6]<<8) | data[7];
982 Out() <<
"PDO2[" << int(node) <<
"] err=" << hex << fErrCode[node/2] << endl;
995 SDO(uint8_t n, uint8_t r, uint16_t
i, uint8_t s, uint32_t v=0)
996 : node(n), req(r&0xf), idx(i), subidx(s), val(v) { }
1008 uint8_t n, uint8_t r, uint16_t
i, uint8_t s, uint32_t v, uint16_t millisec) :
SDO(n, r, i, s, v),
1009 ba::deadline_timer(ioservice)
1011 expires_from_now(boost::posix_time::milliseconds(millisec));
1023 if (bytes_received!=11 || fData[0]!=10 || err)
1025 if (err==ba::error::eof)
1026 Warn(
"Connection closed by remote host (cosy).");
1030 if (err && err!=ba::error::eof &&
1031 err!=ba::error::basic_errors::not_connected &&
1032 err!=ba::error::basic_errors::operation_aborted)
1035 str <<
"Reading from " << URL() <<
": " << err.message() <<
" (" << err <<
")";
1038 PostClose(err!=ba::error::basic_errors::operation_aborted);
1044 const uint16_t desc = fData[1]<<8 | fData[2];
1045 const uint16_t cobid = desc>>5;
1047 const uint8_t *
data = fData.data()+3;
1049 const uint16_t fcode = cobid >> 7;
1050 const uint8_t
node = cobid & 0x1f;
1055 Out() <<
"Received nodeguard" << endl;
1061 const uint8_t cmd = data[0];
1062 const uint16_t idx = data[1] | (data[2]<<8);
1063 const uint8_t subidx = data[3];
1064 const uint32_t dat = data[4] | (data[5]<<8) | (data[6]<<16) | (data[7]<<24);
1066 const auto it = find(fTimeouts.begin(), fTimeouts.end(),
SDO(node, cmd, idx, subidx));
1067 if (it!=fTimeouts.end())
1076 str <<
"Unexpected SDO (";
1077 str << uint32_t(node) <<
": ";
1078 str << ((cmd&0xf)==kTxSdo?
"RX ":
"TX ");
1079 str << idx <<
"/" << uint32_t(subidx) <<
")";
1087 HandleSdo(node, idx, subidx, dat, now);
1091 HandleSdo(node, idx, subidx, dat&0xffff, now);
1095 HandleSdo(node, idx, subidx, dat&0xff, now);
1099 HandleSdoOk(node, idx, subidx, now);
1103 HandleSdoError(node, idx, subidx, now);
1109 out <<
"Invalid SDO command code " << hex << cmd <<
" received.";
1119 HandlePdo1(node, data, now);
1123 HandlePdo2(node, data, now);
1127 HandlePdo3(node, data, now);
1133 out <<
"Invalid function code " << hex << fcode <<
" received.";
1147 ba::placeholders::error, ba::placeholders::bytes_transferred, 0));
1152 bool fIsInitialized[2];
1159 fIsInitialized[0] =
false;
1160 fIsInitialized[1] =
false;
1162 SendSdo(kNodeZd, kSetArmed, 1);
1163 SendSdo(kNodeAz, kSetArmed, 1);
1165 RequestSdo(kNodeZd, kReqErrStat);
1166 RequestSdo(kNodeAz, kReqErrStat);
1170 RequestSdo(kNodeZd, kReqPosRes);
1171 RequestSdo(kNodeAz, kReqPosRes);
1173 RequestSdo(kNodeZd, kReqVelRes);
1174 RequestSdo(kNodeAz, kReqVelRes);
1176 RequestSdo(kNodeZd, kReqVelMax);
1177 RequestSdo(kNodeAz, kReqVelMax);
1179 RequestSdo(kNodeZd, kReqPos, 0);
1180 RequestSdo(kNodeAz, kReqPos, 0);
1181 RequestSdo(kNodeZd, kReqPos, 1);
1182 RequestSdo(kNodeAz, kReqPos, 1);
1184 RequestSdo(kNodeZd, kReqKeepAlive);
1185 RequestSdo(kNodeAz, kReqKeepAlive);
1192 if (error==ba::error::basic_errors::operation_aborted)
1198 str <<
"SDO timeout of " << URL() <<
": " << error.message() <<
" (" << error <<
")";
1216 if (ref->expires_at() > ba::deadline_timer::traits_type::now())
1221 str <<
"SDO timeout (";
1222 str << uint32_t(ref->node) <<
": ";
1223 str << (ref->req==kTxSdo?
"RX ":
"TX ");
1224 str << ref->idx <<
"/" << uint32_t(ref->subidx) <<
" [" << ref->val <<
"] ";
1225 str << to_simple_string(ref->expires_from_now());
1233 void HandleTimeout(
const std::list<Timeout_t>::iterator &ref,
const bs::error_code &error)
1235 HandleTimeoutImp(ref, error);
1236 fTimeouts.erase(ref);
1240 uint16_t idx, uint8_t subidx, uint32_t val=0)
1243 Out() <<
"SDO-" << (req==kTxSdo?
"REQ":
"SET") <<
"[" <<
int(node) <<
"] " << idx <<
"/" << int(subidx) <<
" = " << val << endl;
1246 SendCanFrame(0x600|(node&0x1f), req, idx&0xff, idx>>8, subidx,
1247 val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff);
1258 const uint32_t milliseconds = 3000;
1259 fTimeouts.emplace_front(get_io_service(), node, req, idx, subidx, val, milliseconds);
1261 const std::list<Timeout_t>::iterator &timeout = fTimeouts.begin();
1268 fVerbosity(0), fData(11)
1285 SendSdoRequest(node, kTxSdo, idx, subidx);
1287 void SendSdo(uint8_t
node, uint16_t idx, uint8_t subidx, uint32_t val)
1289 SendSdoRequest(node, kTxSdo4, idx, subidx, val);
1294 SendSdo(node, idx, 0, val);
1299 return (fStatusAxis[0]&kAxisMoving) || (fStatusAxis[1]&kAxisMoving)
1300 || (fStatusAxis[0]&kAxisRpmMode) || (fStatusAxis[1]&kAxisRpmMode);
1307 return fIsInitialized[0] && fIsInitialized[1];
1312 const uint8_t typ0 = fErrCode[0]>>16;
1313 const uint8_t typ1 = fErrCode[1]>>16;
1314 return typ0==0xe || typ0==0xf || typ1==0xe || typ1==0xf;
1319 return fErrCode[0]!=0 && fErrCode[1]!=0;
1324 return fStatusAxis[0]&kAxisRf && fStatusAxis[1]&kAxisRf;
1329 return (fStatusSys&kEmergencyOk)==0 || (fStatusSys&kManualMode);
1334 return Encoder(
double(fPdoPos2[1])/fPosRes[1],
double(fPdoPos2[0])/fPosRes[0]);
1341 return (
Time(fPdoTime2[0]).Mjd()+
Time(fPdoTime2[1]).Mjd())/2;
1346 return Encoder(fVelMax[1], fVelMax[0]);
1351 const uint32_t val = mode ? String(
's',
't',
'r',
't') : String(
's',
't',
'o',
'p');
1352 SendSdo(kNodeAz, kSetRpmMode, val);
1353 SendSdo(kNodeZd, kSetRpmMode, val);
1358 SendSdo(kNodeAz, kSetAcc, lrint(acc.
az*1000000000+0.5));
1359 SendSdo(kNodeZd, kSetAcc, lrint(acc.
zd*1000000000+0.5));
1364 SendSdo(kNodeAz, kSetPointVel, lrint(vel.
az*fVelMax[0]*scale));
1365 SendSdo(kNodeZd, kSetPointVel, lrint(vel.
zd*fVelMax[1]*scale));
1369 SendSdo(kNodeAz, kSetTrackVel, lrint(vel.
az*fVelRes[0]));
1370 SendSdo(kNodeZd, kSetTrackVel, lrint(vel.
zd*fVelRes[1]));
1375 if (az) SendSdo(kNodeAz, kSetPosition, lrint(enc.
az*fPosRes[0]));
1376 if (zd) SendSdo(kNodeZd, kSetPosition, lrint(enc.
zd*fPosRes[1]));
1379 if (az) fStatusAxis[0] |= 0x02;
1380 if (zd) fStatusAxis[1] |= 0x02;
1387 SendSdo(kNodeAz, 0x4000, v1);
1388 SendSdo(kNodeZd, 0x4000, v2);
1417 fDimPointing.
setData(p.second);
1418 fDimPointing.
Update(p.first);
1424 fDimTracking.
setData(p.second);
1425 fDimTracking.
Update(p.first);
1432 const vector<char> &
data = get<1>(
t);
1433 const bool &tracking = get<2>(
t);
1444 fDimStatus.
Update(p.first);
1451 fDimTPoint.
Update(p.first);
1458 fQueuePointing.emplace(t, arr);
1463 fQueueTracking.emplace(t, arr);
1468 fQueueStatus.emplace(t, arr);
1474 vector<char> dim(
sizeof(data)+name.length()+1);
1475 memcpy(dim.data(), &
data,
sizeof(
data));
1476 memcpy(dim.data()+
sizeof(
data), name.c_str(), name.length()+1);
1478 fQueueTPoint.emplace(t, dim);
1483 vector<char> dat(5*
sizeof(
double)+31, 0);
1484 strncpy(dat.data()+5*
sizeof(double), name.c_str(), 30);
1486 fQueueSource.emplace(t, dat, tracking);
1491 vector<char> dat(5*
sizeof(
double)+31, 0);
1492 memcpy(dat.data(), arr.data(), 5*
sizeof(double));
1493 strncpy(dat.data()+5*
sizeof(double), name.c_str(), 30);
1495 fQueueSource.emplace(t, dat,
true);
1501 fDimPointing(
"DRIVE_CONTROL/POINTING_POSITION",
"D:1;D:1",
1502 "|Zd[deg]:Zenith distance (derived from encoder readout)" 1503 "|Az[deg]:Azimuth angle (derived from encoder readout)"),
1504 fDimTracking(
"DRIVE_CONTROL/TRACKING_POSITION",
"D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1",
1505 "|Ra[h]:Command right ascension pointing direction (J2000)" 1506 "|Dec[deg]:Command declination pointing direction (J2000)" 1507 "|Ha[h]:Hour angle pointing direction" 1508 "|SrcRa[h]:Right ascension source (J2000)" 1509 "|SrcDec[deg]:Declination source (J2000)" 1510 "|SrcHa[h]:Hour angle source" 1511 "|Zd[deg]:Nominal zenith distance" 1512 "|Az[deg]:Nominal azimuth angle" 1513 "|dZd[deg]:Control deviation Zd" 1514 "|dAz[deg]:Control deviation Az" 1515 "|dev[arcsec]:Absolute control deviation" 1516 "|avgdev[arcsec]:Average control deviation used to define OnTrack"),
1517 fDimSource(
"DRIVE_CONTROL/SOURCE_POSITION",
"D:1;D:1;D:1;D:1;D:1;C:31",
1518 "|Ra_src[h]:Source right ascension" 1519 "|Dec_src[deg]:Source declination" 1520 "|Offset[deg]:Wobble offset" 1521 "|Angle[deg]:Wobble angle" 1522 "|Period[min]:Time for one orbit" 1523 "|Name[string]:Source name if available"),
1524 fDimTPoint(
"DRIVE_CONTROL/TPOINT_DATA",
"D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;S:1;S:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;C",
1525 "|Ra[h]:Command right ascension" 1526 "|Dec[deg]:Command declination" 1527 "|Zd_nom[deg]:Nominal zenith distance" 1528 "|Az_nom[deg]:Nominal azimuth angle" 1529 "|Zd_cur[deg]:Current zenith distance (calculated from image)" 1530 "|Az_cur[deg]:Current azimuth angle (calculated from image)" 1531 "|Zd_enc[deg]:Feedback zenith axis (from encoder)" 1532 "|Az_enc[deg]:Feedback azimuth angle (from encoder)" 1533 "|N_leds[cnt]:Number of detected LEDs" 1534 "|N_rings[cnt]:Number of rings used to calculate the camera center" 1535 "|Xc[pix]:X position of center in CCD camera frame" 1536 "|Yc[pix]:Y position of center in CCD camera frame" 1537 "|Ic[au]:Average intensity (LED intensity weighted with their frequency of occurance in the calculation)" 1538 "|Xs[pix]:X position of start in CCD camera frame" 1539 "|Ys[pix]:Y position of star in CCD camera frame" 1540 "|Ms[mag]:Artifical magnitude of star (calculated from image)" 1541 "|Phi[deg]:Rotation angle of image derived from detected LEDs" 1542 "|Mc[mag]:Catalog magnitude of star" 1543 "|Dx[arcsec]:De-rotated dx" 1544 "|Dy[arcsec]:De-rotated dy" 1545 "|Name[string]:Name of star"),
1546 fDimStatus(
"DRIVE_CONTROL/STATUS",
"C:2;C:1",
""),
1560 template <
class T,
class S>
1605 msg << name <<
" - Received event has " << has <<
" bytes, but expected " << size <<
".";
1614 if (!CheckEventSize(evt.
GetSize(),
"HandleWeatherData", 7*4+2))
1617 return T::GetCurrentState();
1620 const float *ptr = evt.
Ptr<
float>(2);
1622 fWeather.
temp = ptr[0];
1623 fWeather.
hum = ptr[2];
1624 fWeather.
press = ptr[3];
1627 return T::GetCurrentState();
1634 return T::GetCurrentState();
1637 if (!CheckEventSize(evt.
GetSize(),
"HandleTPoint", 11*8))
1638 return T::GetCurrentState();
1642 return T::GetCurrentState();
1649 const double *ptr = evt.
Ptr<
double>();
1652 const double dx = ptr[0] * M_PI/648000;
1653 const double dy = ptr[1] * M_PI/648000;
1657 const double x2 = dx*dx;
1658 const double y2 = 1 + dy*dy;
1660 const double sd = cos(data.
sky.
zd);
1661 const double cd = sin(data.
sky.
zd);
1662 const double sdf = sd*sqrt(x2+y2);
1663 const double r2 = cd*cd*y2 - sd*sd*x2;
1667 if (r2<0 || fabs(sdf)>=1)
1669 T::Warn(
"Could not determine pointing direction from TPoint.");
1670 return T::GetCurrentState();
1673 const double r = sqrt(r2);
1674 const double s = sdf - dy * r;
1675 const double c = sdf * dy + r;
1676 const double phi = atan2(dx, r);
1679 const double az = fmod(data.
sky.
az-phi + 2*M_PI, 2*M_PI);
1680 const double zd = M_PI/2 - atan2(s, c);
1689 const bool exist = boost::filesystem::exists(fname);
1691 ofstream fout(fname, ios::app);
1694 fout <<
"FACT Model TPOINT data file" << endl;
1695 fout <<
": ALTAZ" << endl;
1697 fout << evt.
GetTime() << endl;
1699 fout << setprecision(7);
1700 fout << fmod(az*180/M_PI+360, 360) <<
" ";
1701 fout << 90-zd*180/M_PI <<
" ";
1702 fout << fmod(data.
mount.
az+360, 360) <<
" ";
1703 fout << 90-data.
mount.
zd <<
" ";
1704 fout << dev.
az <<
" ";
1705 fout << -dev.
zd <<
" ";
1706 fout << 90-data.
sky.
zd * 180/M_PI <<
" ";
1707 fout << data.
sky.
az * 180/M_PI <<
" ";
1708 fout << setprecision(10);
1709 fout << data.
mjd <<
" ";
1710 fout << setprecision(7);
1711 fout << ptr[6] <<
" ";
1712 fout << ptr[9] <<
" ";
1713 fout << ptr[4] <<
" ";
1714 fout << ptr[5] <<
" ";
1715 fout << ptr[7] <<
" ";
1716 fout << ptr[8] <<
" ";
1717 fout << ptr[2] <<
" ";
1718 fout << ptr[3] <<
" ";
1719 fout << ptr[0] <<
" ";
1720 fout << ptr[1] <<
" ";
1721 fout << ptr[10] <<
" ";
1722 fout << fPointingSetup.
source.
mag <<
" ";
1751 txt <<
"TPoint recorded [" << zd*180/M_PI <<
"/" << az*180/M_PI <<
" | " 1752 << data.
sky.
zd*180/M_PI <<
"/" << data.
sky.
az*180/M_PI <<
" | " 1754 << dx*180/M_PI <<
"/" << dy*180/M_PI <<
"]";
1757 return T::GetCurrentState();
1768 const double x = sin(meszd) * sin(nomzd) * cos(devaz);
1769 const double y = cos(meszd) * cos(nomzd);
1771 return acos(x + y) * 180/M_PI;
1780 in >> sgn >> d >> m >> s;
1782 const double ret = ((60.0 * (60.0 * (double)d + (
double)m) + s))/3600.;
1783 return sgn==
'-' ? -ret : ret;
1788 if (pos.
zd<fPointingMin.
zd)
1790 T::Error(
"Zenith distance "+to_string(pos.
zd)+
" below limit "+to_string(fPointingMin.
zd));
1794 if (pos.
zd>fPointingMax.
zd)
1796 T::Error(
"Zenith distance "+to_string(pos.
zd)+
" exceeds limit "+to_string(fPointingMax.
zd));
1800 if (pos.
az<fPointingMin.
az)
1802 T::Error(
"Azimuth angle "+to_string(pos.
az)+
" below limit "+to_string(fPointingMin.
az));
1806 if (pos.
az>fPointingMax.
az)
1808 T::Error(
"Azimuth angle "+to_string(pos.
az)+
" exceeds limit "+to_string(fPointingMax.
az));
1817 return fPointingModel.
CalcPointingPos(fPointingSetup, mjd, fWeather, fWeatherTimeout);
1825 if (!CheckEventSize(evt.
GetSize(),
"RequestSdo", 6))
1826 return T::kSM_FatalError;
1828 const uint16_t
node = evt.
Get<uint16_t>();
1829 const uint16_t index = evt.
Get<uint16_t>(2);
1830 const uint16_t subidx = evt.
Get<uint16_t>(4);
1832 if (node!=1 && node !=3)
1834 T::Error(
"Node id must be 1 (az) or 3 (zd).");
1835 return T::GetCurrentState();
1840 T::Error(
"Subindex must not be larger than 255.");
1841 return T::GetCurrentState();
1844 fDrive.RequestSdo(node, index, subidx);
1846 return T::GetCurrentState();
1851 if (!CheckEventSize(evt.
GetSize(),
"SendSdo", 6+8))
1852 return T::kSM_FatalError;
1854 const uint16_t
node = evt.
Get<uint16_t>();
1855 const uint16_t index = evt.
Get<uint16_t>(2);
1856 const uint16_t subidx = evt.
Get<uint16_t>(4);
1857 const uint64_t value = evt.
Get<uint64_t>(6);
1859 if (node!=1 && node!=3)
1861 T::Error(
"Node id must be 1 (az) or 3 (zd).");
1862 return T::GetCurrentState();
1867 T::Error(
"Subindex must not be larger than 255.");
1868 return T::GetCurrentState();
1871 fDrive.SendSdo(node, index, subidx, value);
1873 return T::GetCurrentState();
1888 fMovementTarget = fPointingModel.
SkyToMount(sky);
1891 if (!CheckRange(sky*(180/M_PI)))
1892 return StopMovement();
1895 fIsTracking = tracking;
1897 fDrive.SetRpmMode(
false);
1898 fDrive.SetAcceleration(fAccPointing);
1901 fDrive.UpdateSource(
Time(), name,
false);
1904 const array<double, 5> dim =
1912 fDrive.UpdateSource(fPointingSetup.
start, dim, fPointingSetup.
source.
name);
1920 if (!CheckEventSize(evt.
GetSize(),
"MoveTo", 16))
1921 return T::kSM_FatalError;
1923 const double *dat = evt.
Ptr<
double>();
1926 out <<
"Pointing telescope to Zd=" << dat[0] <<
"deg Az=" << dat[1] <<
"deg";
1929 return InitMovement(
ZdAz(dat[0]*M_PI/180, dat[1]*M_PI/180));
1939 out <<
"Tracking position now at Zd=" << data.
sky.
zd*180/M_PI <<
"deg Az=" << data.
sky.
az*180/M_PI <<
"deg";
1942 return InitMovement(data.
sky,
true);
1947 if (src.
ra<0 || src.
ra>=24)
1950 out <<
"Right ascension out of range [0;24[: Ra=" << src.
ra <<
"h Dec=" << src.
dec <<
"deg";
1951 if (!src.
name.empty())
1952 out <<
" [" << src.
name <<
"]";
1956 if (src.
dec<-90 || src.
dec>90)
1959 out <<
"Declination out of range [-90;90]: Ra=" << src.
ra <<
"h Dec=" << src.
dec <<
"deg";
1960 if (!src.
name.empty())
1961 out <<
" [" << src.
name <<
"]";
1967 out <<
"Tracking Ra=" << src.
ra <<
"h Dec=" << src.
dec <<
"deg";
1968 if (!src.
name.empty())
1969 out <<
" [" << src.
name <<
"]";
1973 fPointingSetup.
source = src;
1978 return InitTracking();
1991 T::Error(
"TrackCelest - Celestial object "+to_string(p)+
" not yet supported.");
1992 return T::GetCurrentState();
1995 fPointingSetup.
planet = p;
2000 return InitTracking();
2006 out <<
"Parking telescope at Zd=" << fParkingPos.
zd <<
"deg Az=" << fParkingPos.
az <<
"deg";
2009 const int rc = InitMovement(
ZdAz(fParkingPos.
zd*M_PI/180, fParkingPos.
az*M_PI/180),
false,
"Park");
2015 if (!CheckEventSize(evt.
GetSize(),
"Wobble", 32))
2016 return T::kSM_FatalError;
2018 const double *dat = evt.
Ptr<
double>();
2023 return StartTracking(src, dat[2], dat[3]);
2028 if (!CheckEventSize(evt.
GetSize(),
"Orbit", 40))
2029 return T::kSM_FatalError;
2031 const double *dat = evt.
Ptr<
double>();
2036 return StartTracking(src, dat[2], dat[3], dat[4]);
2041 if (find(ptr, last,
'\0')==last)
2043 T::Fatal(
"TrackWobble - The name transmitted by dim is not null-terminated.");
2044 throw uint32_t(T::kSM_FatalError);
2047 const string name(ptr);
2049 const sources::const_iterator it = fSources.find(name);
2050 if (it==fSources.end())
2052 T::Error(
"Source '"+name+
"' not found in list.");
2053 throw uint32_t(T::GetCurrentState());
2064 msg <<
"TrackWobble - Received event has " << evt.
GetSize() <<
" bytes, but expected at least 3.";
2066 return T::kSM_FatalError;
2072 msg <<
"TrackWobble - Source name missing.";
2074 return T::GetCurrentState();
2077 const uint16_t wobble = evt.
GetUShort();
2078 if (wobble!=1 && wobble!=2)
2081 msg <<
"TrackWobble - Wobble id " << wobble <<
" undefined, only 1 and 2 allowed.";
2083 return T::GetCurrentState();
2086 const char *ptr = evt.
Ptr<
char>(2);
2087 const char *last = ptr+evt.
GetSize()-2;
2091 const sources::const_iterator it = GetSourceFromDB(ptr, last);
2093 const Source &src = it->second;
2094 return StartTracking(src, src.
offset, src.
angles[wobble-1]);
2096 catch (
const uint32_t &e)
2104 const char *last = ptr+
size;
2108 const sources::const_iterator it = GetSourceFromDB(ptr, last);
2110 const Source &src = it->second;
2111 return StartTracking(src, offset<0?0.6:offset, angle,
time);
2113 catch (
const uint32_t &e)
2121 if (!CheckEventSize(evt.
GetSize(),
"Track", 16))
2122 return T::kSM_FatalError;
2127 src.
ra = evt.
Get<
double>(0);
2128 src.
dec = evt.
Get<
double>(8);
2130 return StartTracking(src, 0, 0);
2138 msg <<
"TrackOn - Received event has " << evt.
GetSize() <<
" bytes, but expected at least 17.";
2140 return T::kSM_FatalError;
2146 msg <<
"TrackOn - Source name missing.";
2148 return T::GetCurrentState();
2151 const double offset = evt.
Get<
double>(0);
2152 const double angle = evt.
Get<
double>(8);
2154 return StartTrackWobble(evt.
Ptr<
char>(16), evt.
GetSize()-16, offset, angle);
2162 msg <<
"TrackOn - Source name missing.";
2164 return T::GetCurrentState();
2167 return StartTrackWobble(evt.
Ptr<
char>(), evt.
GetSize());
2175 msg <<
"TrackOrbit - Received event has " << evt.
GetSize() <<
" bytes, but expected at least 17.";
2177 return T::kSM_FatalError;
2182 msg <<
"TrackOrbit - Source name missing.";
2184 return T::GetCurrentState();
2187 const double angle = evt.
Get<
double>(0);
2188 const double time = evt.
Get<
double>(8);
2190 return StartTrackWobble(evt.
Ptr<
char>(16), evt.
GetSize()-16, -1, angle,
time);
2195 fDrive.SetAcceleration(fAccMax);
2196 fDrive.SetRpmMode(
false);
2198 fTrackingLoop.cancel();
2200 fDrive.UpdateSource(
Time(),
"",
false);
2207 const int rc = CheckState();
2215 T::Info(
"TPoint initiated.");
2217 return T::GetCurrentState();
2225 msg <<
"Screenshot - Received event has " << evt.
GetSize() <<
" bytes, but expected at least 2.";
2227 return T::kSM_FatalError;
2233 msg <<
"Screenshot - Filename missing.";
2235 return T::GetCurrentState();
2238 T::Info(
"Screenshot initiated.");
2240 return T::GetCurrentState();
2245 if (!CheckEventSize(evt.
GetSize(),
"SetLedBrightness", 8))
2246 return T::kSM_FatalError;
2248 const uint32_t *led = evt.
Ptr<uint32_t>();
2250 fDrive.SetLedVoltage(led[0], led[1]);
2252 return T::GetCurrentState();
2257 fDrive.SetLedVoltage(0, 0);
2258 return T::GetCurrentState();
2265 if (!CheckEventSize(evt.
GetSize(),
"SetVerbosity", 2))
2266 return T::kSM_FatalError;
2270 return T::GetCurrentState();
2275 for (
auto it=fSources.begin(); it!=fSources.end(); it++)
2277 const string &name = it->first;
2278 const Source &src = it->second;
2280 T::Out() << name <<
",";
2281 T::Out() << src.
ra <<
"," << src.
dec <<
"," << src.
offset <<
",";
2282 T::Out() << src.
angles[0] <<
"," << src.
angles[1] << endl;
2284 return T::GetCurrentState();
2289 const int rc = CheckState();
2299 catch (
const exception &e)
2301 T::Error(
"Reading sources from databse failed: "+
string(e.what()));
2303 return T::GetCurrentState();
2309 fDrive.PostClose(
false);
2317 return T::GetCurrentState();
2323 fDrive.PostClose(
false);
2327 ba::io_service::poll();
2333 fDrive.PostClose(
true);
2335 return T::GetCurrentState();
2348 const Encoder sepos = fDrive.GetSePos()*360;
2352 const double absdev = GetDevAbs(data.
mount.
zd, sepos.zd, dev.
az)*3600;
2355 fDevBuffer[fDevCount++%5] = absdev;
2358 const uint8_t cnt = fDevCount<5 ? fDevCount : 5;
2359 const double avgdev = accumulate(fDevBuffer.begin(), fDevBuffer.begin()+cnt, 0.)/cnt;
2362 if (avgdev<fDeviationLimit)
2365 fTrackingCounter = 0;
2367 const double ha = fmod(fDrive.GetSeTime(),1)*24 -
Nova::ORM().lng/15;
2369 array<double, 12> dim;
2376 dim[6] = data.
sky.
zd * 180/M_PI;
2377 dim[7] = data.
sky.
az * 180/M_PI;
2383 fDrive.UpdateTracking(fDrive.GetSeTime(), dim);
2385 if (fDrive.GetVerbosity())
2386 T::Out() <<
Time().
GetAsStr(
" %H:%M:%S.%f") <<
" - Deviation [deg] " << absdev <<
"\"|" << avgdev <<
"\"|" << fDevCount<<
" dZd=" << dev.
zd*3600 <<
"\" dAz=" << dev.
az*3600 <<
"\"" << endl;
2393 if (T::GetCurrentState()==
State::kTracking && fTrackingCounter>=fDeviationCounter)
2397 return T::GetCurrentState();
2402 const Encoder sepos = fDrive.GetSePos()*360;
2406 array<double, 2>
data;
2407 data[0] = pos.
zd*180/M_PI;
2408 data[1] = pos.
az*180/M_PI;
2409 fDrive.UpdatePointing(fDrive.GetSeTime(),
data);
2411 if (fDrive.GetVerbosity())
2412 T::Out() <<
Time().
GetAsStr(
" %H:%M:%S.%f") <<
" - Position [deg] " << pos.
zd*180/M_PI <<
" " << pos.
az*180/M_PI << endl;
2415 void TrackingLoop(
const boost::system::error_code &error=boost::system::error_code())
2417 if (error==ba::error::basic_errors::operation_aborted)
2423 str <<
"TrackingLoop: " << error.message() <<
" (" << error <<
")";
2440 fTrackingLoop.expires_from_now(boost::posix_time::milliseconds(250));
2442 const double mjd =
Time().
Mjd();
2449 const PointingData data0 = CalcPointingPos(mjd-0.45/24/3600);
2450 const PointingData data1 = CalcPointingPos(mjd+0.55/24/3600);
2453 const Encoder dest0 = data0.mount*(1./360);
2456 if (!CheckRange(data1.
sky))
2464 const Encoder sepos = fDrive.GetSePos();
2467 const Encoder dist = dest1 - dest0;
2471 const Velocity vt = vel - dev/(1./60);
2473 if (fDrive.GetVerbosity()>1)
2475 T::Out() <<
"Ideal position [deg] " << dest.
zd *360 <<
" " << dest.az *360 << endl;
2476 T::Out() <<
"Encoder pos. [deg] " << sepos.
zd*360 <<
" " << sepos.
az*360 << endl;
2477 T::Out() <<
"Deviation [arcmin] " << dev.
zd *360*60 <<
" " << dev.
az *360*60 << endl;
2478 T::Out() <<
"Distance 1s [arcmin] " << dist.
zd *360*60 <<
" " << dist.
az *360*60 << endl;
2479 T::Out() <<
"Velocity 1s [rpm] " << vt.
zd <<
" " << vt.
az << endl;
2480 T::Out() <<
"Delta T (enc) [ms] " << fabs(mjd-fDrive.fPdoTime2[0].Mjd())*24*3600*1000 << endl;
2481 T::Out() <<
"Delta T (now) [ms] " << (
Time().
Mjd()-mjd)*24*3600*1000 << endl;
2494 fDrive.SetTrackingVelocity(vt);
2497 this, ba::placeholders::error));
2504 if (!fDrive.IsConnected())
2507 if (!fDrive.IsOnline())
2512 if (fDrive.HasError())
2518 return StopMovement();
2531 if (fDrive.IsOnline() && fDrive.IsBlocked())
2534 if (fDrive.IsOnline() && !fDrive.IsReady())
2539 if (fDrive.IsOnline() && fDrive.IsReady() && !fDrive.IsInitialized())
2553 msg <<
"Next sun-rise will be at " << fSunRise;
2566 const int rc = CheckState();
2571 static time_t lastTime = 0;
2572 const time_t tm =
time(NULL);
2573 if (lastTime!=tm && fDrive.IsInitialized())
2577 UpdatePointingPosition();
2580 return UpdateTrackingPosition();
2589 if (fIsTracking && fStep==1)
2592 fDrive.SetAcceleration(fAccTracking);
2593 fDrive.SetRpmMode(
true);
2596 fTrackingCounter = 0;
2598 fTrackingLoop.expires_from_now(boost::posix_time::milliseconds(1));
2600 this, ba::placeholders::error));
2607 out <<
"Start tracking at Ra=" << data.
pointing.
ra*12/M_PI <<
"h Dec=" << data.
pointing.
dec*180/M_PI <<
"deg";
2614 const Encoder dest = fMovementTarget*(1./360);
2615 const Encoder sepos = fDrive.GetSePos();
2618 const Encoder dist = dest - sepos;
2622 cd *= 1./fMaxPointingResidual;
2626 const bool cdzd = cd.
zd>1;
2627 const bool cdaz = cd.
az>1;
2634 T::Info(
"Target position reached in "+to_string(fStep)+
" steps.");
2640 T::Error(
"Target position not reached in "+to_string(fStep)+
" steps.");
2652 if (fDrive.GetVerbosity())
2654 T::Out() <<
"Moving step " << fStep << endl;
2655 T::Out() <<
"Encoder [deg] " << sepos.zd*360 <<
" " << sepos.az*360 << endl;
2656 T::Out() <<
"Destination [deg] " << dest.
zd *360 <<
" " << dest.
az *360 << endl;
2657 T::Out() <<
"Residual [deg] " << dist.
zd *360 <<
" " << dist.
az *360 << endl;
2658 T::Out() <<
"Residual/max [1] " << cd.
zd <<
" " << cd.
az << endl;
2659 T::Out() <<
"Rel. time [1] " << t.
zd <<
" " << t.
az << endl;
2660 T::Out() <<
"Rel. velocity [1] " << vel.
zd <<
" " << vel.
az << endl;
2663 fDrive.SetPointingVelocity(vel, fPointingVelocity);
2664 fDrive.StartAbsolutePositioning(dest, cdzd, cdaz);
2668 out <<
"Moving to encoder Zd=" << dest.
zd*360 <<
"deg Az=" << dest.
az*360 <<
"deg";
2670 out <<
"Moving residual of dZd=" << dist.
zd*360*60 <<
"' dAz=" << dist.
az*360*60 <<
"'";
2683 fTrackingLoop(*this), fSunRise(
Time().GetNextSunRise()), fDevBuffer(5)
2686 T::Subscribe(
"MAGIC_WEATHER/DATA")
2689 T::Subscribe(
"TPOINT/DATA")
2694 "No connection to SPS");
2696 "Connection to SPS, no information received yet");
2699 "Drive system is locked (will not accept commands)");
2702 "Connected to SPS, no connection to at least one IndraDrives");
2704 "Connected to SPS and to IndraDrives, but at least one drive not in RF");
2706 "Drive system is blocked by manual operation or a pressed emergeny button");
2708 "Connected to SPS and IndraDrives in RF, but not yet initialized");
2710 "Connected to SPS and IndraDrives in RF and initialized");
2713 "Stop command sent, waiting for telescope to be still");
2715 "Telescope in parking operation, waiting for telescope to be still");
2717 "Telescope moving");
2719 "Telescope in tracking mode");
2721 "Telescope tracking stable");
2724 "Target position was not reached within ten steps");
2726 "Telecope went out of range during tracking");
2728 "Tracking coordinates out of range");
2733 (
"Request an SDO from the drive" 2734 "|node[uint32]:Node identifier (1:az, 3:zd)" 2735 "|index[uint32]:SDO index" 2736 "|subindex[uint32]:SDO subindex");
2740 (
"Request an SDO from the drive" 2741 "|node[uint32]:Node identifier (1:az, 3:zd)" 2742 "|index[uint32]:SDO index" 2743 "|subindex[uint32]:SDO subindex" 2744 "|value[uint64]:Value");
2749 (
"Move the telescope to the given local sky coordinates" 2750 "|Zd[deg]:Zenith distance" 2751 "|Az[deg]:Azimuth");
2755 (
"Move the telescope to the given sky coordinates and start tracking them" 2756 "|Ra[h]:Right ascension" 2757 "|Dec[deg]:Declination");
2761 (
"Move the telescope to the given wobble position around the given sky coordinates and start tracking them" 2762 "|Ra[h]:Right ascension" 2763 "|Dec[deg]:Declination" 2764 "|Offset[deg]:Wobble offset" 2765 "|Angle[deg]:Wobble angle");
2769 (
"Move the telescope in a circle around the source" 2770 "|Ra[h]:Right ascension" 2771 "|Dec[deg]:Declination" 2772 "|Offset[deg]:Wobble offset" 2773 "|Angle[deg]:Starting angle" 2774 "|Period[min]:Time for one orbit");
2778 (
"Move the telescope to the given wobble position around the given source and start tracking" 2779 "|Offset[deg]:Wobble offset" 2780 "|Angle[deg]:Wobble angle" 2781 "|Name[string]:Source name");
2785 (
"Move the telescope to the given wobble position around the given source and start tracking" 2786 "|Id:Wobble angle id (1 or 2)" 2787 "|Name[string]:Source name");
2791 (
"Move the telescope in a circle around the source" 2792 "|Angle[deg]:Starting angle" 2793 "|Period[min]:Time for one orbit" 2794 "|Name[string]:Source name");
2798 (
"Move the telescope to the given position and start tracking" 2799 "|Name[string]:Source name");
2803 (
"Start tracking the moon");
2806 (
"Start tracking Venus");
2809 (
"Start tracking Mars");
2812 (
"Start tracking Jupiter");
2815 (
"Start tracking Saturn");
2820 (
"Park the telescope");
2824 (
"Stop any kind of movement.");
2828 (
"Acknoledge an internal error (PositioningFailed, AllowedRangeExceeded)");
2834 T::AddEvent(
"SCREENSHOT",
"B:1;C")
2836 (
"Take a screenshot" 2837 "|color[bool]:False if just the gray image should be saved." 2838 "|name[string]:Filename");
2840 T::AddEvent(
"SET_LED_BRIGHTNESS",
"I:2")
2842 (
"Set the LED brightness of the top and bottom leds" 2843 "|top[au]:Allowed range 0-32767 for top LEDs" 2844 "|bot[au]:Allowed range 0-32767 for bottom LEDs");
2846 T::AddEvent(
"LEDS_OFF")
2848 (
"Switch off TPoint LEDs");
2852 (
"Unlock locked state.");
2855 T::AddEvent(
"SET_VERBOSITY",
"S:1")
2857 (
"Set verbosity state" 2858 "|verbosity[uint16]:disable or enable verbosity for received data (yes/no), except dynamic data");
2863 (
"disconnect from ethernet");
2867 (
"(Re)connect Ethernet connection to SPS, a new address can be given" 2868 "|[host][string]:new ethernet address in the form <host:port>");
2871 T::AddEvent(
"PRINT")
2873 (
"Print source list.");
2877 (
"Reload sources from database after database has changed..");
2881 fDrive.StartConnect();
2886 fDrive.SetEndpoint(url);
2891 const auto it = fSources.find(name);
2892 if (it!=fSources.end())
2893 T::Warn(
"Source '"+name+
"' already in list... overwriting.");
2895 fSources[name] = src;
2896 return it==fSources.
end();
2904 T::Message(
"Connected to '"+db.
uri()+
"'");
2906 const mysqlpp::StoreQueryResult res =
2907 db.query(
"SELECT fSourceName, fRightAscension, fDeclination, fWobbleOffset, fWobbleAngle0, fWobbleAngle1, fMagnitude FROM Source").store();
2910 for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
2912 const string name = (*v)[0].c_str();
2921 src.
mag = (*v)[6] ? double((*v)[6]) : 0;
2922 AddSource(name, src);
2928 msg <<
" " << name << setprecision(8) <<
": Ra=" << src.
ra <<
"h Dec=" << src.
dec <<
"deg";
2929 msg <<
" Wobble=[" << src.
offset <<
"," << src.
angles[0] <<
"," << src.
angles[1] <<
"] Mag=" << src.
mag;
2933 T::Warn(
"MySQL support not compiled into the program.");
2942 fDrive.SetVerbose(!conf.
Get<
bool>(
"quiet"));
2944 fMaxPointingResidual = conf.
Get<
double>(
"pointing.max.residual");
2945 fPointingVelocity = conf.
Get<
double>(
"pointing.velocity");
2947 fPointingMin =
Encoder(conf.
Get<
double>(
"pointing.min.zd"),
2948 conf.
Get<
double>(
"pointing.min.az"));
2949 fPointingMax =
Encoder(conf.
Get<
double>(
"pointing.max.zd"),
2950 conf.
Get<
double>(
"pointing.max.az"));
2952 fParkingPos.
zd = conf.
Has(
"parking-pos.zd") ? conf.
Get<
double>(
"parking-pos.zd") : 90;
2953 fParkingPos.
az = conf.
Has(
"parking-pos.az") ? conf.
Get<
double>(
"parking-pos.az") : 0;
2955 if (!CheckRange(fParkingPos))
2958 fAccPointing =
Acceleration(conf.
Get<
double>(
"pointing.acceleration.zd"),
2959 conf.
Get<
double>(
"pointing.acceleration.az"));
2960 fAccTracking =
Acceleration(conf.
Get<
double>(
"tracking.acceleration.zd"),
2961 conf.
Get<
double>(
"tracking.acceleration.az"));
2963 conf.
Get<
double>(
"acceleration.max.az"));
2965 fWeatherTimeout = conf.
Get<uint16_t>(
"weather-timeout");
2967 if (fAccPointing>fAccMax)
2969 T::Error(
"Pointing acceleration exceeds maximum acceleration.");
2973 if (fAccTracking>fAccMax)
2975 T::Error(
"Tracking acceleration exceeds maximum acceleration.");
2979 fDeviationLimit = conf.
Get<uint16_t>(
"deviation-limit");
2980 fDeviationCounter = conf.
Get<uint16_t>(
"deviation-count");
2981 fDeviationMax = conf.
Get<uint16_t>(
"deviation-max");
2983 const string fname = conf.
Get<
string>(
"pointing.model-file");
2987 fPointingModel.
Load(fname);
2989 catch (
const exception &e)
2995 const vector<string> &vec = conf.
Vec<
string>(
"source");
2997 for (vector<string>::const_iterator it=vec.begin(); it!=vec.end(); it++)
2999 istringstream stream(*it);
3008 while (getline(stream, buffer,
','))
3010 istringstream is(buffer);
3014 case 0: name =
buffer;
break;
3015 case 1: src.
ra = ReadAngle(is);
break;
3016 case 2: src.
dec = ReadAngle(is);
break;
3017 case 3: is >> src.
offset;
break;
3018 case 4: is >> src.
angles[0];
break;
3019 case 5: is >> src.
angles[1];
break;
3028 AddSource(name, src);
3032 T::Warn(
"Resource 'source' not correctly formatted: '"+*it+
"'");
3037 if (conf.
Has(
"source-database"))
3039 fDatabase = conf.
Get<
string>(
"source-database");
3046 msg <<
"Next sun-rise will be at " << fSunRise;
3052 SetEndpoint(conf.
Get<
string>(
"addr"));
3063 template<
class T,
class S,
class R>
3066 return Main::execute<T, StateMachineDrive<S, R>>(conf);
3071 po::options_description control(
"Drive control options");
3072 control.add_options()
3073 (
"quiet,q",
po_bool(),
"Disable debug messages")
3074 (
"no-dim,d",
po_switch(),
"Disable dim services")
3075 (
"addr,a", var<string>(
"sps:5357"),
"Network address of cosy")
3076 (
"verbosity,v", var<uint16_t>(0),
"Vervosity level (0=off; 1=major updates; 2=most updates; 3=frequent updates)")
3077 (
"pointing.model-file", var<string>()->required(),
"Name of the file with the pointing model in use")
3078 (
"pointing.max.zd", var<double>( 104.9),
"Maximum allowed zenith angle in sky pointing coordinates [deg]")
3079 (
"pointing.max.az", var<double>( 85.0),
"Maximum allowed azimuth angle in sky pointing coordinates [deg]")
3080 (
"pointing.min.zd", var<double>(-104.9),
"Minimum allowed zenith angle in sky pointing coordinates [deg]")
3081 (
"pointing.min.az", var<double>(-295.0),
"Minimum allowed azimuth angle in sky pointing coordinates [deg]")
3082 (
"pointing.max.residual", var<double>(1./32768),
"Maximum residual for a pointing operation [revolutions]")
3083 (
"pointing.velocity", var<double>(0.3),
"Moving velocity when pointing [% max]")
3084 (
"pointing.acceleration.az", var<double>(0.01),
"Acceleration for azimuth axis for pointing operations")
3085 (
"pointing.acceleration.zd", var<double>(0.03),
"Acceleration for zenith axis for pointing operations")
3086 (
"tracking.acceleration.az", var<double>(0.01),
"Acceleration for azimuth axis during tracking operations")
3087 (
"tracking.acceleration.zd", var<double>(0.01),
"Acceleration for zenith axis during tracking operations")
3088 (
"parking-pos.zd", var<double>(101),
"Parking position zenith angle in sky pointing coordinates [deg]")
3089 (
"parking-pos.az", var<double>(0),
"Parking position azimuth angle in sky pointing coordinates [deg]")
3090 (
"acceleration.max.az", var<double>(0.03),
"Maximum allowed acceleration value for azimuth axis")
3091 (
"acceleration.max.zd", var<double>(0.09),
"Maximum allowed acceleration value for zenith axis")
3092 (
"weather-timeout", var<uint16_t>(300),
"Timeout [sec] for weather data (after timeout default values are used)")
3093 (
"deviation-limit", var<uint16_t>(90),
"Deviation limit in arcsec to get 'OnTrack'")
3094 (
"deviation-count", var<uint16_t>(3),
"Minimum number of reported deviation below deviation-limit to get 'OnTrack'")
3095 (
"deviation-max", var<uint16_t>(180),
"Maximum deviation in arcsec allowed to keep status 'OnTrack'")
3096 (
"source-database", var<string>(),
"Database link as in\n\tuser:password@server[:port]/database.")
3097 (
"source", vars<string>(),
"Additional source entry in the form \"name,hh:mm:ss,dd:mm:ss\"")
3115 "The drivectrl is an interface to the drive PLC.\n" 3117 "The default is that the program is started without user intercation. " 3118 "All actions are supposed to arrive as DimCommands. Using the -c " 3119 "option, a local shell can be initialized. With h or help a short " 3120 "help message about the usuage can be brought to the screen.\n" 3122 "Usage: drivectrl [-c type] [OPTIONS]\n" 3123 " or: drivectrl [OPTIONS]\n";
3129 Main::PrintHelp<StateMachineDrive<StateMachine,ConnectionDrive>>();
3149 int main(
int argc,
const char* argv[])
3162 if (!conf.
Has(
"console"))
3164 if (conf.
Get<
bool>(
"no-dim"))
3165 return RunShell<LocalStream, StateMachine, ConnectionDrive>(conf);
3167 return RunShell<LocalStream, StateMachineDim, ConnectionDimDrive>(conf);
3170 if (conf.
Get<
bool>(
"no-dim"))
3172 if (conf.
Get<
int>(
"console")==0)
3173 return RunShell<LocalShell, StateMachine, ConnectionDrive>(conf);
3175 return RunShell<LocalConsole, StateMachine, ConnectionDrive>(conf);
3179 if (conf.
Get<
int>(
"console")==0)
3180 return RunShell<LocalShell, StateMachineDim, ConnectionDimDrive>(conf);
3182 return RunShell<LocalConsole, StateMachineDim, ConnectionDimDrive>(conf);
RaDecHa(double _ra, double _dec, double _ha)
double fMaxPointingResidual
AltAz & operator+=(const AltAz &aa)
bool operator>(const Acceleration &a) const
int StartTrackWobble(const char *ptr, size_t size, const double &offset=0, const double &angle=0, double time=0)
void SetAcceleration(const Acceleration &acc)
virtual void UpdateTracking(const Time &, const array< double, 12 > &)
vector< double > fDevBuffer
double GetDevAbs(double nomzd, double meszd, double devaz)
virtual void UpdateSource(const Time &, const string &, bool)
int TrackOn(const EventImp &evt)
uint16_t GetVerbosity() const
int EvalOptions(Configuration &conf)
void StartAbsolutePositioning(const Encoder &enc, bool zd, bool az)
array< double, 2 > angles
AltAz(double _alt, double _az)
int TrackOrbit(const EventImp &evt)
AltAz & operator-=(const AltAz &aa)
void UpdatePointingPosition()
A general base-class describing events issues in a state machine.
void SetupConfiguration(Configuration &conf)
Encoder operator*(double f) const
uint64_t fTrackingCounter
bool SendSource(const tuple< Time, vector< char >, bool > &t)
void SetLedVoltage(const uint32_t &v1, const uint32_t &v2)
void SetupConfiguration(Configuration &conf)
int RequestSdo(const EventImp &evt)
ba::deadline_timer fTrackingLoop
int main(int argc, const char *argv[])
Acceleration fAccPointing
PointingSetup fPointingSetup
void setQuality(int quality)
bool SendTracking(const pair< Time, array< double, 12 >> &p)
void UpdateSource(const Time &t, const string &name, bool tracking)
The base implementation of a distributed messaging system.
Adds some functionality to boost::posix_time::ptime for our needs.
Encoder GetVelUnit() const
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
uint32_t NightAsInt() const
void SetTrackingVelocity(const Velocity &vel)
Time GetNextSunRise(double horizon) const
ZdAz MountToSky(const Encoder &mnt) const
ConnectionDrive(ba::io_service &ioservice, MessageImp &imp)
Velocity operator/(double f) const
po::typed_value< bool > * po_switch()
Timeout_t(ba::io_service &ioservice, uint8_t n, uint8_t r, uint16_t i, uint8_t s, uint32_t v, uint16_t millisec)
int Reconnect(const EventImp &evt)
int TrackSource(const EventImp &evt)
void HandlePdo1(const uint8_t &node, const uint8_t *data, const Time &tv)
int HandleTPoint(const EventImp &evt)
Queue< pair< Time, array< uint8_t, 3 > > > fQueueStatus
std::vector< T > Vec(const std::string &var)
std::list< Timeout_t > fTimeouts
bool IsInitialized() const
std::string GetString() const
void UpdatePointing(const Time &t, const array< double, 2 > &arr)
map< string, Source > sources
int Orbit(const EventImp &evt)
int SendSdo(const EventImp &evt)
Encoder & operator*=(double f)
int HandleWeatherData(const EventImp &evt)
ZdAz(double _zd=0, double _az=0)
void SetRpmMode(bool mode)
RaDec(double _ra, double _dec)
uint16_t GetUShort() const
PointingData CalcPointingPos(double mjd)
void HandleSdo(const uint8_t &node, const uint16_t &idx, const uint8_t &subidx, const uint32_t &val, const Time &tv)
void UpdateTPoint(const Time &t, const DimTPoint &data, const string &name)
void palAmpqk(double ra, double da, double amprms[21], double *rm, double *dm)
void SetVerbosity(const uint16_t &v)
void HandleReceivedData(const boost::system::error_code &err, size_t bytes_received, int)
void HandleSdoOk(const uint8_t &node, const uint16_t &idx, const uint8_t &subidx, const Time &)
void ReadDatabase(bool print=true)
void SendSdo(uint8_t node, uint16_t idx, uint32_t val)
PointingData CalcPointingPos(const PointingSetup &setup, double _mjd, const Weather &weather, uint16_t timeout, bool tpoint=false)
double palDtt(double dju)
bool Has(const std::string &var)
void palMappa(double eq, double date, double amprms[21])
int Screenshot(const EventImp &evt)
void LogErrorCode(uint32_t node)
Acceleration(double _zd=0, double _az=0)
void palAopqk(double rap, double dap, const double aoprms[14], double *aob, double *zob, double *hob, double *dob, double *rob)
virtual void UpdateSource(const Time &, const array< double, 5 > &, const string &="")
Queue< pair< Time, array< double, 2 > > > fQueuePointing
Velocity(double _zd=0, double _az=0)
int SetLedBrightness(const EventImp &evt)
void AddOptions(const po::options_description &opt, bool visible=true)
double Sign(double val, double alt) const
int TrackCelest(const Planets_t &p)
void SendSdoRequest(uint8_t node, uint8_t req, uint16_t idx, uint8_t subidx, uint32_t val=0)
void SetPointingVelocity(const Velocity &vel, double scale=1)
void setData(const void *ptr, size_t sz)
int TrackWobble(const EventImp &evt)
virtual Time GetTime() const
Encoder operator-(const Encoder &a, const Encoder &b)
string ErrCodeToString(uint32_t code) const
void RequestSdo(uint8_t node, uint16_t idx, uint8_t subidx=0)
int UpdateTrackingPosition()
static uint32_t String(uint8_t b0=0, uint8_t b1=0, uint8_t b2=0, uint8_t b3=0)
void SendCommandNB(const std::string &command)
Warning because the service this data corrsponds to might have been last updated longer ago than Local time
int InitMovement(const ZdAz &sky, bool tracking=false, const string &name="")
uint16_t fDeviationCounter
bool AddSource(const string &name, const Source &src)
void HandlePdo3(const uint8_t &node, const uint8_t *data, const Time &tv)
ZdAz operator*(const double &f) const
int MoveTo(const EventImp &evt)
int StartTracking(const Source &src, double offset, double angle, double period=0)
bool SendStatus(const pair< Time, array< uint8_t, 3 >> &p)
void TrackingLoop(const boost::system::error_code &error=boost::system::error_code())
Commandline parsing, resource file parsing and database access.
void HandleSdoError(const uint8_t &node, const uint16_t &idx, const uint8_t &subidx, const Time &)
Encoder & operator-=(const Encoder &enc)
void HandleTimeout(const std::list< Timeout_t >::iterator &ref, const bs::error_code &error)
virtual void UpdateStatus(const Time &, const array< uint8_t, 3 > &)
Queue< pair< Time, vector< char > > > fQueueTPoint
bool operator==(const SDO &s) const
bool SendTPoint(const pair< Time, vector< char >> &p)
void UpdateSource(const Time &t, const array< double, 5 > &arr, const string &name="")
Encoder operator/(const Encoder &a, const Encoder &b)
ConnectionDimDrive(ba::io_service &ioservice, MessageImp &imp)
PointingSetup(Planets_t p=kENone)
Error, something unexpected happened, but can still be handled by the program.
void HandlePdo2(const uint8_t &node, const uint8_t *data, const Time &)
int SetVerbosity(const EventImp &evt)
Acceleration fAccTracking
void SendCanFrame(uint16_t cobid, uint8_t m0=0, uint8_t m1=0, uint8_t m2=0, uint8_t m3=0, uint8_t m4=0, uint8_t m5=0, uint8_t m6=0, uint8_t m7=0)
PointingModel fPointingModel
void ConnectionEstablished()
Encoder SkyToMount(AltAz p)
Queue< tuple< Time, vector< char >, bool > > fQueueSource
Queue< pair< Time, array< double, 12 > > > fQueueTracking
void SendSdo(uint8_t node, uint16_t idx, uint8_t subidx, uint32_t val)
Error states should be between 0x100 and 0xffff.
void palRdplan(double date, int np, double elong, double phi, double *ra, double *dec, double *diam)
Return to feeserver c CVS log Up to[MAIN] dcscvs FeeServer feeserver src Wed FeeServer_v0 v0 dev
bool CheckRange(ZdAz pos)
Velocity operator*(double f) const
void Load(const string &name)
void SetEndpoint(const string &url)
Connection(boost::asio::io_service &io_service, std::ostream &out)
po::typed_value< bool > * po_bool(bool def=false)
int Wobble(const EventImp &evt)
int Track(const EventImp &evt)
virtual void UpdatePointing(const Time &, const array< double, 2 > &)
T Get(size_t offset=0) const
bool CheckEventSize(size_t has, const char *name, size_t size)
std::string GetAsStr(const char *fmt="%Y-%m-%d %H:%M:%S") const
Maintains an ansynchronous TCP/IP client connection.
void UpdateTracking(const Time &t, const array< double, 12 > &arr)
virtual const void * GetData() const
void palAoppa(double date, double dut, double elongm, double phim, double hm, double xp, double yp, double tdk, double pmb, double rh, double wl, double tlr, double aoprms[14])
void palMapqkz(double rm, double dm, double amprms[21], double *ra, double *da)
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
SDO(uint8_t n, uint8_t r, uint16_t i, uint8_t s, uint32_t v=0)
void UpdateStatus(const Time &t, const array< uint8_t, 3 > &arr)
double ReadAngle(istream &in)
Do not initialize the time.
int TrackCelest(const string &cmd, const string &source)
Encoder(double _zd=0, double _az=0)
const T * Ptr(size_t offset=0) const
const sources::const_iterator GetSourceFromDB(const char *ptr, const char *last)
Local(double _zd=0, double _az=0)
Velocity operator/(double t) const
void HandleTimeoutImp(const std::list< Timeout_t >::iterator &ref, const bs::error_code &error)
StateMachineDrive(ostream &out=cout)
int RunShell(Configuration &conf)
virtual void UpdateTPoint(const Time &, const DimTPoint &, const string &)
virtual size_t GetSize() const
bool SendPointing(const pair< Time, array< double, 2 >> &p)