canopen.cpp
Go to the documentation of this file.
00001 #include "canopen.h"
00002 
00003 namespace canopen {
00004 
00005   // ----------------- Variable definitions: --------------
00006 
00007   std::chrono::milliseconds syncInterval;
00008   HANDLE h;
00009   std::map<uint8_t, Device> devices;
00010   std::map<std::string, DeviceGroup> deviceGroups;
00011 
00012   std::map<SDOkey, std::function<void (uint8_t CANid, BYTE data[8])> > incomingDataHandlers
00013   { { statusword, statusword_incoming },
00014       { modes_of_operation_display, modes_of_operation_display_incoming }  };
00015 
00016   std::map<uint16_t, std::function<void (const TPCANRdMsg m)> > incomingPDOHandlers;
00017 
00018   TPCANMsg NMTmsg;
00019   TPCANMsg syncMsg;
00020   TPCANMsg nodeguardMsg;
00021   bool atFirstInit = true;
00022 
00023   // ----------------- Function definitions: --------------
00024 
00025   bool openConnection(std::string devName) {
00026     h = LINUX_CAN_Open(devName.c_str(), O_RDWR);
00027     if (!h) return false;
00028     errno = CAN_Init(h, CAN_BAUD_500K, CAN_INIT_TYPE_ST);
00029     return true;
00030   }
00031 
00032   void setMotorState(uint16_t CANid, std::string targetState) { // todo: not finished
00033     // if (devices[CANid].motorState_ == "fault")
00034     while (devices[CANid].motorState_ != targetState) {
00035       canopen::sendSDO(CANid, canopen::statusword);
00036       if (devices[CANid].motorState_ == "fault") {
00037         canopen::sendSDO(CANid, canopen::controlword, canopen::controlword_fault_reset_0);
00038         std::this_thread::sleep_for(std::chrono::milliseconds(50));
00039         canopen::sendSDO(CANid, canopen::controlword, canopen::controlword_fault_reset_1);
00040         std::this_thread::sleep_for(std::chrono::milliseconds(200));
00041       }
00042       if (devices[CANid].motorState_ == "switch_on_disabled") {
00043         canopen::sendSDO(CANid, canopen::controlword, canopen::controlword_shutdown);
00044       }
00045       if (devices[CANid].motorState_ == "ready_to_switch_on") {
00046         canopen::sendSDO(CANid, canopen::controlword, canopen::controlword_switch_on);
00047       }
00048       if (devices[CANid].motorState_ == "switched_on") {
00049         canopen::sendSDO(CANid, canopen::controlword, canopen::controlword_enable_operation);
00050       }
00051       std::this_thread::sleep_for(std::chrono::milliseconds(50));
00052     }
00053   }
00054 
00055   void init(std::string deviceFile, std::chrono::milliseconds syncInterval) {
00056     // canopen::devices must be set up before this function is called
00057     CAN_Close(h);
00058 
00059     syncMsg.ID = 0x80;
00060     syncMsg.MSGTYPE = 0x00;
00061     syncMsg.LEN = 0x00;
00062     NMTmsg.ID = 0;
00063     NMTmsg.MSGTYPE = 0x00;
00064     NMTmsg.LEN = 2;
00065     nodeguardMsg.MSGTYPE = 0x01; // remote frame
00066     nodeguardMsg.LEN = 0;
00067 
00068     if (!canopen::openConnection(deviceFile)) {
00069       std::cout << "Cannot open CAN device; aborting." << std::endl;
00070       exit(EXIT_FAILURE);
00071     }
00072 
00073     if (atFirstInit)
00074       canopen::initListenerThread(canopen::defaultListener);
00075       // atFirstInit = false;
00076     // }
00077 
00078     for (auto device : devices) {
00079       sendSDO(device.second.CANid_, ip_time_units, (uint8_t) syncInterval.count() );
00080       sendSDO(device.second.CANid_, ip_time_index, ip_time_index_milliseconds);
00081       sendSDO(device.second.CANid_, sync_timeout_factor, sync_timeout_factor_disable_timeout);
00082 
00083       // NMT & motor state machine:
00084       if (atFirstInit) {
00085         canopen::sendNMT(device.second.CANid_, canopen::NMT_stop);
00086         std::this_thread::sleep_for(std::chrono::milliseconds(100));
00087         canopen::sendNMT(device.second.CANid_, canopen::NMT_start);
00088         std::this_thread::sleep_for(std::chrono::milliseconds(100));
00089       }
00090 
00091       setMotorState(device.second.CANid_, "operation_enable");
00092       /* canopen::sendSDO(device.second.CANid_, canopen::controlword, canopen::controlword_shutdown);
00093       canopen::sendSDO(device.second.CANid_, canopen::controlword, canopen::controlword_switch_on);
00094       canopen::sendSDO(device.second.CANid_, canopen::controlword, canopen::controlword_enable_operation); */
00095     }
00096     
00097     if (atFirstInit)
00098       atFirstInit = false;
00099   }
00100 
00101   void defaultListener() {
00102     while (true) {
00103       TPCANRdMsg m;
00104       if ((errno = LINUX_CAN_Read(h, &m))) {
00105         perror("LINUX_CAN_Read() error");
00106       }
00107 
00108       if (m.Msg.ID >= 0x180 && m.Msg.ID <= 0x4ff) { // incoming PDO 
00109         if (incomingPDOHandlers.find(m.Msg.ID) != incomingPDOHandlers.end())
00110           incomingPDOHandlers[m.Msg.ID](m);
00111       }
00112       else if (m.Msg.ID >= 0x580 && m.Msg.ID <= 0x5ff) { // incoming SDO 
00113         SDOkey sdoKey(m);
00114         if (incomingDataHandlers.find(sdoKey) != incomingDataHandlers.end())
00115           incomingDataHandlers[sdoKey](m.Msg.ID - 0x580, m.Msg.DATA);
00116       } else if (m.Msg.ID >= 0x700 && m.Msg.ID <= 0x7FF) 
00117         incomingNodeguardHandler(m.Msg.ID - 0x700, m.Msg.DATA);
00118     }
00119   }
00120 
00121   void initListenerThread(std::function<void ()> const& listener) {
00122     std::thread listener_thread(listener);
00123     listener_thread.detach();
00124     std::this_thread::sleep_for(std::chrono::milliseconds(10));
00125   }
00126 
00127   void initDeviceManagerThread(std::function<void ()> const& deviceManager) {
00128     std::thread device_manager_thread(deviceManager);
00129     device_manager_thread.detach();
00130     std::this_thread::sleep_for(std::chrono::milliseconds(10));
00131   }
00132 
00133   void deviceManager() {
00134     // todo: init, recover... (e.g. when to start/stop sending SYNCs)
00135     while (true) {
00136       auto tic = std::chrono::high_resolution_clock::now();
00137       for (auto device : devices) {
00138         if (device.second.initialized) {
00139           devices[device.first].updateDesiredPos();
00140           sendPos(device.second.CANid_, device.second.desiredPos_);
00141         }
00142       }
00143       sendSync();
00144       std::this_thread::sleep_for(syncInterval - (std::chrono::high_resolution_clock::now() - tic ));
00145     }
00146   }
00147 
00148   // ----------------- Functions to handle incoming data: --------------
00149 
00150   void incomingNodeguardHandler(uint8_t CANid, BYTE data[8]) {
00151     // update variables of the corresponding device object with nodeguard info
00152   }
00153 
00154   void statusword_incoming(uint8_t CANid, BYTE data[8]) {
00155 
00156     /* for (int i=0; i<8; i++)
00157       printf("%02x ", data[i]);
00158       std::cout << std::endl; */
00159 
00160     uint16_t mydata = data[4] + (data[5] << 8);
00161     // update variables of the corresponding device object, e.g.
00162     // printf("mydata: %04x\n", mydata);
00163     if ((mydata & 8) == 8) 
00164       devices[CANid].motorState_ = "fault";
00165     else if ((mydata & 0x4f) == 0x40) 
00166       devices[CANid].motorState_ = "switch_on_disabled";
00167     else if ((mydata & 0x6f) == 0x21)
00168       devices[CANid].motorState_ = "ready_to_switch_on";
00169     else if ((mydata & 0x6f) == 0x23)
00170       devices[CANid].motorState_ = "switched_on";
00171     else if ((mydata & 0x6f) == 0x27)
00172       devices[CANid].motorState_ = "operation_enable";
00173 
00174     devices[CANid].voltage_enabled_ = (mydata >> 4) & 0x1;
00175     devices[CANid].driveReferenced_ = (mydata >> 15) & 0x1;
00176     
00177     std::cout << "STATUSWORD incoming; drive referenced? " << 
00178       devices[CANid].driveReferenced_ << std::endl;
00179   }
00180 
00181   void modes_of_operation_display_incoming(uint8_t CANid, BYTE data[8]) {
00182     // update variables of the corresponding device object
00183   }
00184 
00185   void schunkDefaultPDO_incoming(uint8_t CANid, const TPCANRdMsg m) {
00186     double newPos = mdeg2rad(m.Msg.DATA[4] + (m.Msg.DATA[5] << 8) + 
00187                              (m.Msg.DATA[6] << 16) + (m.Msg.DATA[7] << 24) );
00188 
00189     if (devices[CANid].timeStamp_msec_ != std::chrono::milliseconds(0) ||  // already 1 msg received
00190         devices[CANid].timeStamp_usec_ != std::chrono::microseconds(0)) {
00191       auto deltaTime_msec = std::chrono::milliseconds(m.dwTime) - devices[CANid].timeStamp_msec_;
00192       auto deltaTime_usec = std::chrono::microseconds(m.wUsec) - devices[CANid].timeStamp_usec_;
00193       double deltaTime_double = static_cast<double>
00194         (deltaTime_msec.count()*1000 + deltaTime_usec.count()) * 0.000001;
00195       devices[ CANid ].actualVel_ = (newPos - devices[CANid].actualPos_) / deltaTime_double;
00196 
00197       if (! devices[CANid].initialized) {
00198         devices[ CANid ].desiredPos_ = devices[ CANid ].actualPos_;
00199         devices[ CANid ].initialized = true;
00200       }
00201     }
00202      
00203     devices[ CANid ].actualPos_ = newPos;
00204     devices[ CANid ].timeStamp_msec_ = std::chrono::milliseconds(m.dwTime);
00205     devices[ CANid ].timeStamp_usec_ = std::chrono::microseconds(m.wUsec);
00206   }
00207   
00208   // ----------------- Functions for sending out data: --------------
00209 
00210   void sendSDO(uint8_t CANid, SDOkey sdo) {
00211     // for SDO read commands, e.g. statusword
00212     TPCANMsg msg;
00213     msg.ID = CANid + 0x600; // 0x600 = SDO identifier
00214     msg.MSGTYPE = 0x00; // standard message
00215     msg.LEN = 4;
00216     msg.DATA[0] = 0x40;
00217     msg.DATA[1] = (sdo.index & 0xFF);
00218     msg.DATA[2] = (sdo.index >> 8) & 0xFF; 
00219     msg.DATA[3] = sdo.subindex;
00220     CAN_Write(h, &msg);
00221   }
00222 
00223   void sendSDO(uint8_t CANid, SDOkey sdo, uint32_t value) {
00224     TPCANMsg msg;
00225     msg.ID = CANid + 0x600; // 0x600 = SDO identifier
00226     msg.LEN = 8;
00227     msg.DATA[0] = 0x23;
00228     msg.DATA[1] = (sdo.index & 0xFF);
00229     msg.DATA[2] = (sdo.index >> 8) & 0xFF; 
00230     msg.DATA[3] = sdo.subindex;
00231     msg.DATA[4] = value & 0xFF;
00232     msg.DATA[5] = (value >> 8) & 0xFF;
00233     msg.DATA[6] = (value >> 16) & 0xFF;
00234     msg.DATA[7] = (value >> 24) & 0xFF;
00235     CAN_Write(h, &msg);
00236   } 
00237 
00238   void sendSDO(uint8_t CANid, SDOkey sdo, int32_t value) {
00239     TPCANMsg msg;
00240     msg.ID = CANid + 0x600; // 0x600 = SDO identifier
00241     msg.LEN = 8;
00242     msg.DATA[0] = 0x23;
00243     msg.DATA[1] = (sdo.index & 0xFF);
00244     msg.DATA[2] = (sdo.index >> 8) & 0xFF; // todo: & 0xFF not needed, I think
00245     msg.DATA[3] = sdo.subindex;
00246     msg.DATA[4] = value & 0xFF;
00247     msg.DATA[5] = (value >> 8) & 0xFF;
00248     msg.DATA[6] = (value >> 16) & 0xFF;
00249     msg.DATA[7] = (value >> 24) & 0xFF;
00250     CAN_Write(h, &msg);
00251   } 
00252 
00253   void sendSDO(uint8_t CANid, SDOkey sdo, uint8_t value) {
00254     TPCANMsg msg;
00255     msg.ID = CANid + 0x600; // 0x600 = SDO identifier
00256     msg.LEN = 5;
00257     msg.DATA[0] = 0x2F;
00258     msg.DATA[1] = (sdo.index & 0xFF);
00259     msg.DATA[2] = (sdo.index >> 8) & 0xFF; // todo: & 0xFF not needed, I think
00260     msg.DATA[3] = sdo.subindex;
00261     msg.DATA[4] = value & 0xFF;
00262     CAN_Write(h, &msg);
00263   } 
00264 
00265   void sendSDO(uint8_t CANid, SDOkey sdo, uint16_t value) {
00266     TPCANMsg msg;
00267     msg.ID = CANid + 0x600; // 0x600 = SDO identifier
00268     msg.LEN = 6;
00269     msg.DATA[0] = 0x2B;
00270     msg.DATA[1] = (sdo.index & 0xFF);
00271     msg.DATA[2] = (sdo.index >> 8) & 0xFF; // todo: & 0xFF not needed, I think
00272     msg.DATA[3] = sdo.subindex;
00273     msg.DATA[4] = value & 0xFF;
00274     msg.DATA[5] = (value >> 8) & 0xFF;
00275     CAN_Write(h, &msg);
00276   } 
00277 
00278   std::function< void (uint16_t CANid, double positionValue) > sendPos;
00279 
00280   void schunkDefaultPDOOutgoing(uint16_t CANid, double positionValue) {
00281     static const uint16_t myControlword = 
00282       controlword_enable_operation | controlword_enable_ip_mode;
00283     TPCANMsg msg;
00284     msg.ID = 0x200 + CANid;
00285     msg.MSGTYPE = 0x00;
00286     msg.LEN = 8;
00287     msg.DATA[0] = myControlword & 0xFF;
00288     msg.DATA[1] = (myControlword >> 8) & 0xFF; // todo: & not needed (?)
00289     msg.DATA[2] = 0;
00290     msg.DATA[3] = 0;
00291     int32_t mdegPos = rad2mdeg(positionValue);
00292     msg.DATA[4] = mdegPos & 0xFF;
00293     msg.DATA[5] = (mdegPos >> 8) & 0xFF;
00294     msg.DATA[6] = (mdegPos >> 16) & 0xFF;
00295     msg.DATA[7] = (mdegPos >> 24) & 0xFF;
00296     CAN_Write(h, &msg);
00297   }
00298 
00299 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


ipa_canopen_core
Author(s): Tobias Sing
autogenerated on Fri Mar 1 2013 18:36:29