00001 #include "canopen.h"
00002
00003 namespace canopen {
00004
00005
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
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) {
00033
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
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;
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
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
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
00093
00094
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) {
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) {
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
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
00149
00150 void incomingNodeguardHandler(uint8_t CANid, BYTE data[8]) {
00151
00152 }
00153
00154 void statusword_incoming(uint8_t CANid, BYTE data[8]) {
00155
00156
00157
00158
00159
00160 uint16_t mydata = data[4] + (data[5] << 8);
00161
00162
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
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) ||
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
00209
00210 void sendSDO(uint8_t CANid, SDOkey sdo) {
00211
00212 TPCANMsg msg;
00213 msg.ID = CANid + 0x600;
00214 msg.MSGTYPE = 0x00;
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;
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;
00241 msg.LEN = 8;
00242 msg.DATA[0] = 0x23;
00243 msg.DATA[1] = (sdo.index & 0xFF);
00244 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
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;
00256 msg.LEN = 5;
00257 msg.DATA[0] = 0x2F;
00258 msg.DATA[1] = (sdo.index & 0xFF);
00259 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
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;
00268 msg.LEN = 6;
00269 msg.DATA[0] = 0x2B;
00270 msg.DATA[1] = (sdo.index & 0xFF);
00271 msg.DATA[2] = (sdo.index >> 8) & 0xFF;
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;
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 }