Working Maveric

MaxonEPOS4.cpp

Committer:
mettrque
Date:
2017-05-30
Revision:
6:ef95300898b2
Parent:
0:bdca5e4773dd
Child:
10:36a2131f636c

File content as of revision 6:ef95300898b2:

/*
 * MaxonEPOS4.cpp
 * Copyright (c) 2017, ZHAW
 * All rights reserved.
 *
 *  Created on: 06.02.2017
 *      Author: Marcel Honegger
 */

#include "MaxonEPOS4.h"

using namespace std;

/**
 * Creates and initializes this device.
 * @param canOpen a reference to a CANopen device driver.
 * @param nodeID the node ID of this device on the CANopen network.
 * @param period the period of the cyclic communication on the CAN bus, given in [s].
 */
MaxonEPOS4::MaxonEPOS4(CANopen& canOpen, uint32_t nodeID, float period) : canOpen(canOpen), thread(osPriorityRealtime, STACK_SIZE) {
    
    // initialize local values
    
    this->nodeID = nodeID;
    
    enable = false;
    targetTorque = 0;
    targetVelocity = 0;
    statusword = 0x0000;
    positionActualValue = 0;
    
    // register this CANopen slave with the CANopen device driver
    
    canOpen.registerCANopenSlave(nodeID, this);
    
    // set slave into preoperational state
    
    canOpen.transmitNMTObject(CANopen::ENTER_PREOPERATIONAL_STATE, nodeID);
    
    // initialize slave CYCLIC_SYNCHRONOUS_TORQUE_MODE
    
    canOpen.writeSDO(nodeID, 0x1600, 0x00, 0x00, 1);        // disable RPDO1
    canOpen.writeSDO(nodeID, 0x1600, 0x01, 0x60400010, 4);  // controlword, 2 bytes
    canOpen.writeSDO(nodeID, 0x1600, 0x02, 0x60600008, 4);  // modes of operation, 1 byte
    canOpen.writeSDO(nodeID, 0x1600, 0x03, 0x60710010, 4);  // target torque, 2 bytes
    canOpen.writeSDO(nodeID, 0x1600, 0x00, 0x03, 1);        // enable RPDO1
    
    
    // initialize slave PROFILE_VELOCITY_MODE
    /*
    canOpen.writeSDO(nodeID, 0x1600, 0x00, 0x00, 1);        // disable RPDO1
    canOpen.writeSDO(nodeID, 0x1600, 0x01, 0x60400010, 4);  // controlword, 2 bytes
    canOpen.writeSDO(nodeID, 0x1600, 0x02, 0x60600008, 4);  // modes of operation, 1 byte
    canOpen.writeSDO(nodeID, 0x1600, 0x03, 0x60FF0020, 4);  // target velocity, 4 bytes
    canOpen.writeSDO(nodeID, 0x1600, 0x00, 0x03, 1);        // enable RPDO1
    */
    canOpen.writeSDO(nodeID, 0x1400, 0x01, CANopen::RPDO1+nodeID, 4);   // reconfigure communication with RPDO1
    
    canOpen.writeSDO(nodeID, 0x1A00, 0x00, 0x00, 1);        // disable TPDO1
    canOpen.writeSDO(nodeID, 0x1A00, 0x01, 0x60410010, 4);  // statusword, 2 bytes
    canOpen.writeSDO(nodeID, 0x1A00, 0x02, 0x60640020, 4);  // position actual value, 4 bytes
    canOpen.writeSDO(nodeID, 0x1A00, 0x00, 0x02, 1);        // enable TPDO1
    
    canOpen.writeSDO(nodeID, 0x1800, 0x01, 0x80000000, 4);  // reconfigure communication with TPDO1
    canOpen.writeSDO(nodeID, 0x1800, 0x02, 253, 1);
    canOpen.writeSDO(nodeID, 0x1800, 0x03, static_cast<uint16_t>(period*10000/2), 2);
    canOpen.writeSDO(nodeID, 0x1800, 0x01, CANopen::TPDO1+nodeID, 4);
    
    // set slave into operational state
    
    canOpen.transmitNMTObject(CANopen::START_REMOTE_NODE, nodeID);
    
    // start thread and timer interrupt
    
    thread.start(callback(this, &MaxonEPOS4::run));
    ticker.attach(callback(this, &MaxonEPOS4::sendSignal), period);
}

/**
 * Deletes this device driver object and releases all allocated resources.
 */
MaxonEPOS4::~MaxonEPOS4() {
    
    ticker.detach();
}

/**
 * Enables or disables the power stage of this servo controller.
 * @param enable flag to indicate if the power stage should be enabled.
 */
void MaxonEPOS4::setEnable(bool enable) {
    
    this->enable = enable;
}

/**
 * Checks if the power stage of this servo controller is enabled and operational.
 * @return <code>true</code> if the power stage is enabled, <code>false</code> otherwise.
 */
bool MaxonEPOS4::isEnabled() {
    
    return (statusword & STATUSWORD_MASK) == OPERATION_ENABLED;
}

/**
 * Sets the desired torque of the servo controller.
 * @param targetTorque the desired torque, given in [&permil;] of the rated torque.
 */
void MaxonEPOS4::writeTorque(int16_t targetTorque) {
    
    this->targetTorque = targetTorque;
}

/**
 * Sets the desired velocity of the servo controller.
 * @param targetVelocity the desired velocity, given in [rpm].
 */
void MaxonEPOS4::writeVelocity(int32_t targetVelocity) {
    
    this->targetVelocity = targetVelocity;
}

/**
 * Gets the actual position value of the drive conntected to the servo controller.
 * @return the actual position value, given in [counts].
 */
int32_t MaxonEPOS4::readPositionValue() {
    
    return positionActualValue;
}

/**
 * Implements the interface of the CANopen delegate class to receive
 * CANopen messages targeted to this device driver.
 */
void MaxonEPOS4::receiveObject(uint32_t functionCode, uint8_t object[]) {
    
    if (functionCode == CANopen::TPDO1) {
        
        statusword = (static_cast<uint16_t>(object[0]) & 0xFF) | ((static_cast<uint16_t>(object[1]) & 0xFF) << 8);
        positionActualValue = (static_cast<int32_t>(object[2]) & 0xFF) | ((static_cast<int32_t>(object[3]) & 0xFF) << 8) | ((static_cast<int32_t>(object[4]) & 0xFF) << 16) | ((static_cast<int32_t>(object[5]) & 0xFF) << 24);
    }
}

/**
 * This method is called by the ticker timer interrupt service routine.
 * It sends a signal to the thread to make it run again.
 */
void MaxonEPOS4::sendSignal() {
    
    thread.signal_set(signal);
}

/**
 * This <code>run()</code> method contains an infinite loop with the run logic.
 */
void MaxonEPOS4::run() {
    
    while (true) {
        
        // wait for the periodic signal
        
        thread.signal_wait(signal);
        
        // set new controlword
        
        uint16_t controlword = 0x0000;
        
        if (enable) {
            
                 if ((statusword & STATUSWORD_MASK) == NOT_READY_TO_SWITCH_ON) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == SWITCH_ON_DISABLED) controlword = SHUTDOWN;
            else if ((statusword & STATUSWORD_MASK) == READY_TO_SWITCH_ON) controlword = SWITCH_ON;
            else if ((statusword & STATUSWORD_MASK) == SWITCHED_ON) controlword = ENABLE_OPERATION;
            else if ((statusword & STATUSWORD_MASK) == OPERATION_ENABLED) controlword = ENABLE_OPERATION;
            else if ((statusword & STATUSWORD_MASK) == QUICK_STOP_ACTIVE) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == FAULT_REACTION_ACTIVE) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == FAULT) controlword = FAULT_RESET;
            
        } else {
            
                 if ((statusword & STATUSWORD_MASK) == NOT_READY_TO_SWITCH_ON) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == SWITCH_ON_DISABLED) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == READY_TO_SWITCH_ON) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == SWITCHED_ON) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == OPERATION_ENABLED) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == QUICK_STOP_ACTIVE) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == FAULT_REACTION_ACTIVE) controlword = DISABLE_VOLTAGE;
            else if ((statusword & STATUSWORD_MASK) == FAULT) controlword = FAULT_RESET;
        }
        
        // request TPDO1
        
        uint8_t tpdo1[6];
        
        canOpen.transmitObject(CANopen::TPDO1, nodeID, tpdo1, 6, CANRemote);
        
        Thread::wait(1);
        
        // transmit RPDO1
        
        //CYCLIC_SYNCHRONOUS_TORQUE_MODE
        
        uint8_t rpdo1[5];
        
        rpdo1[0] = static_cast<uint8_t>(controlword & 0xFF);
        rpdo1[1] = static_cast<uint8_t>((controlword >> 8) & 0xFF);
        rpdo1[2] = static_cast<uint8_t>(CYCLIC_SYNCHRONOUS_TORQUE_MODE);
        rpdo1[3] = static_cast<uint8_t>(targetTorque & 0xFF);
        rpdo1[4] = static_cast<uint8_t>((targetTorque >> 8) & 0xFF);
        
        canOpen.transmitObject(CANopen::RPDO1, nodeID, rpdo1, 5);
        

        //PROFILE_VELOCITY_MODE
        /*
        uint8_t rpdo1[7];
        
        rpdo1[0] = static_cast<uint8_t>(controlword & 0xFF);
        rpdo1[1] = static_cast<uint8_t>((controlword >> 8) & 0xFF);
        rpdo1[2] = static_cast<uint8_t>(PROFILE_VELOCITY_MODE);
        rpdo1[3] = static_cast<uint8_t>(targetVelocity & 0xFF);
        rpdo1[4] = static_cast<uint8_t>((targetVelocity >> 8) & 0xFF);
        rpdo1[5] = static_cast<uint8_t>((targetVelocity >> 16) & 0xFF);
        rpdo1[6] = static_cast<uint8_t>((targetVelocity >> 24) & 0xFF);
        
        canOpen.transmitObject(CANopen::RPDO1, nodeID, rpdo1, 7);
        */
    }
}