$search
00001 #ifndef CANOPEN_H 00002 #define CANOPEN_H 00003 00004 #include <iostream> 00005 #include <map> 00006 #include <vector> 00007 #include <string> 00008 #include <chrono> 00009 #include <unordered_map> 00010 #include <functional> 00011 #include <cstdlib> 00012 #include <thread> 00013 #include <math.h> 00014 #include <libpcan.h> 00015 #include <utility> 00016 #include <fcntl.h> // for O_RDWR 00017 #include <stdint.h> 00018 #include <inttypes.h> 00019 00020 namespace canopen { 00021 00022 extern std::chrono::milliseconds syncInterval; 00023 extern bool atFirstInit; 00024 // ^ true only at first call of the init() function, to prevent 00025 // from launching the listener thread twice 00026 extern HANDLE h; // PCAN device handle 00027 00028 // ---------------- incoming message handlers: ---------------- 00029 00030 struct SDOkey { 00031 uint16_t index; 00032 uint8_t subindex; 00033 inline SDOkey(TPCANRdMsg m) : index((m.Msg.DATA[2] << 8) + m.Msg.DATA[1]), 00034 subindex(m.Msg.DATA[3]) {} 00035 inline SDOkey(uint16_t i, uint8_t s) : index(i), subindex(s) {}; 00036 }; 00037 inline bool operator<(const SDOkey &a, const SDOkey&b) { 00038 return a.index < b.index || (a.index == b.index && a.subindex < b.subindex); } 00039 00040 extern std::map<SDOkey, std::function<void (uint8_t CANid, BYTE data[8])> > 00041 incomingDataHandlers; 00042 extern std::map<uint16_t, std::function<void (const TPCANRdMsg m)> > 00043 incomingPDOHandlers; 00044 00045 void incomingNodeguardHandler(uint8_t CANid, BYTE data[8]); 00046 void statusword_incoming(uint8_t CANid, BYTE data[8]); 00047 void modes_of_operation_display_incoming(uint8_t CANid, BYTE data[8]); 00048 00049 // ----------------- CAN device representations: -------------- 00050 00051 class Device { 00052 public: 00053 Device() {}; 00054 Device(uint8_t CANid) : CANid_(CANid), desiredVel_(0), actualVel_(0), 00055 actualPos_(0), desiredPos_(0), initialized(false), motorState_("not initialized") {}; 00056 Device(uint8_t CANid, std::string name, std::string group, std::string bus) : 00057 CANid_(CANid), name_(name), group_(group), deviceFile_(bus), 00058 desiredVel_(0), actualVel_(0), 00059 actualPos_(0), desiredPos_(0), initialized(false) {}; 00060 00061 std::string motorState_; 00062 00063 00064 inline void setVel(double vel) { desiredVel_ = vel; } 00065 inline void updateDesiredPos() { 00066 desiredPos_ += desiredVel_ * (syncInterval.count() / 1000.0); } 00067 00068 uint8_t CANid_; 00069 // uint16_t motorState_; 00070 std::string deviceFile_; 00071 std::string group_; 00072 std::string name_; 00073 bool initialized; 00074 bool voltage_enabled_; 00075 bool driveReferenced_; 00076 double actualPos_; // unit = rad 00077 double desiredPos_; // unit = rad 00078 double actualVel_; // unit = rad/sec 00079 double desiredVel_; // unit = rad/sec 00080 std::chrono::milliseconds timeStamp_msec_; 00081 std::chrono::microseconds timeStamp_usec_; 00082 }; 00083 00084 extern std::map<uint8_t, Device> devices; // CANid->Device object 00085 00086 class DeviceGroup { 00087 public: 00088 DeviceGroup() {}; 00089 DeviceGroup(std::vector<uint8_t> CANids) : CANids_(CANids) {}; 00090 DeviceGroup(std::vector<uint8_t> CANids, std::vector<std::string> names) : 00091 CANids_(CANids), names_(names) {}; 00092 00093 inline std::vector<double> getActualPos() { 00094 std::vector<double> actualPos; 00095 for (uint8_t CANid : CANids_) 00096 actualPos.push_back(devices[CANid].actualPos_); 00097 return actualPos; 00098 } 00099 inline std::vector<double> getDesiredPos() { 00100 std::vector<double> desiredPos; 00101 for (auto CANid : CANids_) 00102 desiredPos.push_back(devices[CANid].desiredPos_); 00103 return desiredPos; 00104 } 00105 inline std::vector<double> getActualVel() { 00106 std::vector<double> actualVel; 00107 for (auto CANid : CANids_) 00108 actualVel.push_back(devices[CANid].actualVel_); 00109 return actualVel; 00110 } 00111 inline std::vector<double> getDesiredVel() { 00112 std::vector<double> desiredVel; 00113 for (auto CANid : CANids_) 00114 desiredVel.push_back(devices[CANid].desiredVel_); 00115 return desiredVel; 00116 } 00117 inline void setVel(std::vector<double> velocities) { 00118 for (int i=0; i<velocities.size(); i++) { 00119 devices[CANids_[i]].desiredVel_ = velocities[i]; 00120 std::cout << "setVel CANID " << (int) CANids_[i] 00121 << " name: " << names_[i] << " vel: " << velocities[i] << std::endl; 00122 } 00123 } 00124 00125 std::vector<uint8_t> CANids_; 00126 std::vector<std::string> names_; 00127 }; 00128 00129 00130 extern std::map<std::string, DeviceGroup> deviceGroups; 00131 // ^ DeviceGroup name (e.g. "tray", "arm1", etc.) -> DeviceGroup object 00132 00133 // ----------------- Constants: -------------- 00134 00135 const uint8_t NMT_stop = 0x02; 00136 const uint8_t NMT_start = 0x01; 00137 const uint8_t NMT_reset = 0x81; 00138 00139 const SDOkey statusword(0x6041, 0x0); 00140 const SDOkey controlword(0x6040, 0x0); 00141 const SDOkey sync_timeout_factor(0x200e, 0x0); 00142 const SDOkey ip_time_units(0x60C2, 0x1); 00143 const SDOkey ip_time_index(0x60C2, 0x2); 00144 const int8_t ip_time_index_milliseconds = 0xFD; 00145 const int8_t ip_time_index_hundredmicroseconds = 0xFC; 00146 const uint8_t sync_timeout_factor_disable_timeout = 0; 00147 00148 const SDOkey modes_of_operation(0x6060, 0x0); 00149 const SDOkey modes_of_operation_display(0x6061, 0x0); 00150 const uint8_t modes_of_operation_homing_mode = 0x6; 00151 const uint8_t modes_of_operation_profile_position_mode = 0x1; 00152 const uint8_t modes_of_operation_velocity_mode = 0x2; 00153 const uint8_t modes_of_operation_profile_velocity_mode = 0x3; 00154 const uint8_t modes_of_operation_torque_profile_mode = 0x4; 00155 const uint8_t modes_of_operation_interpolated_position_mode = 0x7; 00156 00157 const uint16_t controlword_shutdown = 6; 00158 const uint16_t controlword_switch_on = 7; 00159 const uint16_t controlword_start_homing = 16; 00160 const uint16_t controlword_enable_operation = 15; 00161 const uint16_t controlword_enable_ip_mode = 16; 00162 const uint16_t controlword_fault_reset_0 = 0x00; 00163 const uint16_t controlword_fault_reset_1 = 0x80; 00164 00165 // ----------------- CAN communication functions: -------------- 00166 00167 bool openConnection(std::string devName); 00168 void init(std::string deviceFile, std::chrono::milliseconds syncInterval); 00169 void initListenerThread(std::function<void ()> const& listener); 00170 void defaultListener(); 00171 void initDeviceManagerThread(std::function<void ()> const& deviceManager); 00172 void deviceManager(); 00173 void setMotorState(uint16_t CANid, std::string targetState); 00174 00175 void sendSDO(uint8_t CANid, SDOkey sdo); 00176 void sendSDO(uint8_t CANid, SDOkey sdo, uint32_t value); 00177 void sendSDO(uint8_t CANid, SDOkey sdo, int32_t value); 00178 void sendSDO(uint8_t CANid, SDOkey sdo, uint16_t value); 00179 void sendSDO(uint8_t CANid, SDOkey sdo, uint8_t value); 00180 00181 extern std::function< void (uint16_t CANid, double positionValue) > sendPos; 00182 00183 // ----------------- manufacturer-specific PDOs: -------------- 00184 00185 void schunkDefaultPDO_incoming(uint8_t CANid, const TPCANRdMsg m); 00186 void schunkDefaultPDOOutgoing(uint16_t CANid, double positionValue); 00187 00188 // ----------------- prep-prepared CAN messages: -------------- 00189 00190 extern TPCANMsg syncMsg; 00191 extern TPCANMsg NMTmsg; 00192 extern TPCANMsg nodeguardMsg; 00193 inline void sendSync() { 00194 CAN_Write(h, &syncMsg); 00195 } 00196 inline void sendNMT(uint8_t command, uint8_t CANid) { 00197 NMTmsg.DATA[1] = command; 00198 NMTmsg.DATA[0] = CANid; 00199 CAN_Write(h, &NMTmsg); 00200 } 00201 inline void sendNodeguard(uint8_t CANid) { 00202 nodeguardMsg.ID = 0x700 + CANid; 00203 CAN_Write(h, &nodeguardMsg); 00204 } 00205 00206 // ----------------- type conversions: -------------- 00207 00208 inline int32_t rad2mdeg(double phi) { 00209 return static_cast<int32_t>( round( phi/(2*M_PI)*360000.0 ) ); } 00210 inline double mdeg2rad(int32_t alpha) { 00211 return static_cast<double>( static_cast<double>(alpha)/360000.0*2*M_PI ); } 00212 00213 } 00214 00215 #endif