diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index d9575c24..58dfe89f 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -99,6 +99,8 @@ add_executable (l298-stepper-example l298-stepper.cxx) add_executable (at42qt1070-example at42qt1070.cxx) add_executable (grovemd-example grovemd.cxx) add_executable (pca9685-example pca9685.cxx) +add_executable (adafruitms1438-example adafruitms1438.cxx) +add_executable (adafruitms1438-stepper-example adafruitms1438-stepper.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -179,6 +181,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/l298) include_directories (${PROJECT_SOURCE_DIR}/src/at42qt1070) include_directories (${PROJECT_SOURCE_DIR}/src/grovemd) include_directories (${PROJECT_SOURCE_DIR}/src/pca9685) +include_directories (${PROJECT_SOURCE_DIR}/src/adafruitms1438) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -279,3 +282,5 @@ target_link_libraries (l298-stepper-example l298 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (at42qt1070-example at42qt1070 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (grovemd-example grovemd ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (pca9685-example pca9685 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (adafruitms1438-example adafruitms1438 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (adafruitms1438-stepper-example adafruitms1438 ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/c++/adafruitms1438-stepper.cxx b/examples/c++/adafruitms1438-stepper.cxx new file mode 100644 index 00000000..1bcf75b0 --- /dev/null +++ b/examples/c++/adafruitms1438-stepper.cxx @@ -0,0 +1,82 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "adafruitms1438.h" + +using namespace std; +using namespace upm; + +int main(int argc, char **argv) +{ +//! [Interesting] + // Instantiate an Adafruit MS 1438 on I2C bus 0 + + upm::AdafruitMS1438 *ms = + new upm::AdafruitMS1438(ADAFRUITMS1438_I2C_BUS, + ADAFRUITMS1438_DEFAULT_I2C_ADDR); + + // Setup for use with a stepper motor connected to the M1 & M2 ports + + // set a PWM period of 50Hz + + // disable first, to be safe + ms->disableStepper(AdafruitMS1438::STEPMOTOR_M12); + + // configure for a NEMA-17, 200 steps per revolution + ms->stepConfig(AdafruitMS1438::STEPMOTOR_M12, 200); + + // set speed at 10 RPM's + ms->setStepperSpeed(AdafruitMS1438::STEPMOTOR_M12, 10); + ms->setStepperDirection(AdafruitMS1438::STEPMOTOR_M12, + AdafruitMS1438::DIR_CW); + + // enable + cout << "Enabling..." << endl; + ms->enableStepper(AdafruitMS1438::STEPMOTOR_M12); + + cout << "Rotating 1 full revolution at 10 RPM speed." << endl; + ms->stepperSteps(AdafruitMS1438::STEPMOTOR_M12, 200); + + cout << "Sleeping for 2 seconds..." << endl; + sleep(2); + cout << "Rotating 1/2 revolution in opposite direction at 10 RPM speed." + << endl; + + ms->setStepperDirection(AdafruitMS1438::STEPMOTOR_M12, + AdafruitMS1438::DIR_CCW); + ms->stepperSteps(AdafruitMS1438::STEPMOTOR_M12, 100); + + cout << "Disabling..." << endl; + ms->disableStepper(AdafruitMS1438::STEPMOTOR_M12); + + cout << "Exiting" << endl; + +//! [Interesting] + + delete ms; + return 0; +} diff --git a/examples/c++/adafruitms1438.cxx b/examples/c++/adafruitms1438.cxx new file mode 100644 index 00000000..8ca184cb --- /dev/null +++ b/examples/c++/adafruitms1438.cxx @@ -0,0 +1,75 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "adafruitms1438.h" + +using namespace std; +using namespace upm; + +int main(int argc, char **argv) +{ +//! [Interesting] + // Instantiate an Adafruit MS 1438 on I2C bus 0 + + upm::AdafruitMS1438 *ms = + new upm::AdafruitMS1438(ADAFRUITMS1438_I2C_BUS, + ADAFRUITMS1438_DEFAULT_I2C_ADDR); + + // Setup for use with a DC motor connected to the M3 port + + // set a PWM period of 50Hz + ms->setPWMPeriod(50); + + // disable first, to be safe + ms->disableMotor(AdafruitMS1438::MOTOR_M3); + + // set speed at 50% + ms->setMotorSpeed(AdafruitMS1438::MOTOR_M3, 50); + ms->setMotorDirection(AdafruitMS1438::MOTOR_M3, AdafruitMS1438::DIR_CW); + + cout << "Spin M3 at half speed for 3 seconds, then reverse for 3 seconds." + << endl; + + ms->enableMotor(AdafruitMS1438::MOTOR_M3); + + sleep(3); + + cout << "Reversing M3" << endl; + ms->setMotorDirection(AdafruitMS1438::MOTOR_M3, AdafruitMS1438::DIR_CCW); + + sleep(3); + + cout << "Stopping M3" << endl; + ms->disableMotor(AdafruitMS1438::MOTOR_M3); + + cout << "Exiting" << endl; + +//! [Interesting] + + delete ms; + return 0; +} diff --git a/examples/javascript/adafruitms1438-stepper.js b/examples/javascript/adafruitms1438-stepper.js new file mode 100644 index 00000000..d06edceb --- /dev/null +++ b/examples/javascript/adafruitms1438-stepper.js @@ -0,0 +1,92 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ +/* +* Author: Zion Orent +* Copyright (c) 2015 Intel Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +function exit() +{ + console.log("Exiting"); + + myMotorShield_obj = null; + if (MotorShield_lib) + { + MotorShield_lib.cleanUp(); + MotorShield_lib = null; + } + process.exit(0); +} + +var MotorShield_lib = require('jsupm_adafruitms1438'); + +/* Import header values */ +var I2CBus = MotorShield_lib.ADAFRUITMS1438_I2C_BUS; +var I2CAddr = MotorShield_lib.ADAFRUITMS1438_DEFAULT_I2C_ADDR; + +var M12motor = MotorShield_lib.AdafruitMS1438.STEPMOTOR_M12; +var MotorDirCW = MotorShield_lib.AdafruitMS1438.DIR_CW; +var MotorDirCCW = MotorShield_lib.AdafruitMS1438.DIR_CCW; + + +// Instantiate an Adafruit MS 1438 on I2C bus 0 +var myMotorShield_obj = new MotorShield_lib.AdafruitMS1438(I2CBus, I2CAddr); + + +// Setup for use with a stepper motor connected to the M1 & M2 ports + +// disable first, to be safe +myMotorShield_obj.disableStepper(M12motor); + +// configure for a NEMA-17, 200 steps per revolution +myMotorShield_obj.stepConfig(M12motor, 200); + +// set speed at 10 RPM's +myMotorShield_obj.setStepperSpeed(M12motor, 10); +myMotorShield_obj.setStepperDirection(M12motor, MotorDirCW); + +console.log("Enabling..."); +myMotorShield_obj.enableStepper(M12motor); + +console.log("Rotating 1 full revolution at 10 RPM speed."); +myMotorShield_obj.stepperSteps(M12motor, 200); + +console.log("Sleeping for 2 seconds..."); + + +setTimeout(function() +{ + console.log("Rotating 1/2 revolution in opposite direction at 10 RPM speed."); + + myMotorShield_obj.setStepperDirection(M12motor, MotorDirCCW); + myMotorShield_obj.stepperSteps(M12motor, 100); + + console.log("Disabling..."); + myMotorShield_obj.disableStepper(M12motor); + exit(); +}, 2000); + + +process.on('SIGINT', function() +{ + exit(); +}); diff --git a/examples/javascript/adafruitms1438.js b/examples/javascript/adafruitms1438.js new file mode 100644 index 00000000..7c34d1a0 --- /dev/null +++ b/examples/javascript/adafruitms1438.js @@ -0,0 +1,89 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ +/* +* Author: Zion Orent +* Copyright (c) 2015 Intel Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +function exit() +{ + console.log("Exiting"); + + myMotorShield_obj = null; + if (MotorShield_lib) + { + MotorShield_lib.cleanUp(); + MotorShield_lib = null; + } + process.exit(0); +} + +var MotorShield_lib = require('jsupm_adafruitms1438'); + + +/* Import header values */ +var I2CBus = MotorShield_lib.ADAFRUITMS1438_I2C_BUS; +var I2CAddr = MotorShield_lib.ADAFRUITMS1438_DEFAULT_I2C_ADDR; + +var M3motor = MotorShield_lib.AdafruitMS1438.MOTOR_M3; +var MotorDirCW = MotorShield_lib.AdafruitMS1438.DIR_CW; +var MotorDirCCW = MotorShield_lib.AdafruitMS1438.DIR_CCW; + + +// Instantiate an Adafruit MS 1438 on I2C bus 0 +var myMotorShield_obj = new MotorShield_lib.AdafruitMS1438(I2CBus, I2CAddr); + + +// Setup for use with a DC motor connected to the M3 port + +// set a PWM period of 50Hz +myMotorShield_obj.setPWMPeriod(50); + +// disable first, to be safe +myMotorShield_obj.disableMotor(M3motor); + +// set speed at 50% +myMotorShield_obj.setMotorSpeed(M3motor, 50); +myMotorShield_obj.setMotorDirection(M3motor, MotorDirCW); + +process.stdout.write("Spin M3 at half speed for 3 seconds, "); +console.log("then reverse for 3 seconds."); +myMotorShield_obj.enableMotor(M3motor); + +setTimeout(function() +{ + console.log("Reversing M3"); + myMotorShield_obj.setMotorDirection(M3motor, MotorDirCCW); +}, 3000); + + +setTimeout(function() +{ + console.log("Stopping M3"); + myMotorShield_obj.disableMotor(M3motor); + exit(); +}, 6000); + +process.on('SIGINT', function() +{ + exit(); +}); diff --git a/src/adafruitms1438/CMakeLists.txt b/src/adafruitms1438/CMakeLists.txt new file mode 100644 index 00000000..66db9400 --- /dev/null +++ b/src/adafruitms1438/CMakeLists.txt @@ -0,0 +1,10 @@ +set (libname "adafruitms1438") +set (libdescription "upm module for the Adafruit Motor Shield 1438") +set (module_src ${libname}.cxx) +set (module_h ${libname}.h) +set (reqlibname "upm-pca9685") +include_directories("../pca9685") +upm_module_init() +target_link_libraries(${libname} pca9685) +swig_link_libraries (jsupm_${libname} -lupm-pca9685 ${MRAA_LIBRARIES} ${NODE_LIBRARIES}) +swig_link_libraries (pyupm_${libname} -lupm-pca9685 ${PYTHON_LIBRARIES} ${MRAA_LIBRARIES}) diff --git a/src/adafruitms1438/adafruitms1438.cxx b/src/adafruitms1438/adafruitms1438.cxx new file mode 100644 index 00000000..8d86261e --- /dev/null +++ b/src/adafruitms1438/adafruitms1438.cxx @@ -0,0 +1,305 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "adafruitms1438.h" + +using namespace upm; +using namespace std; + + +AdafruitMS1438::AdafruitMS1438(int bus, uint8_t address) : + m_pca9685(new PCA9685(bus, address)) +{ + setupPinMaps(); + + // set a default period of 50Hz + setPWMPeriod(50); + + // disable all PWM's (4 of them). They are shared with each other + // (stepper/DC), so just disable the DC motors here + disableMotor(MOTOR_M1); + disableMotor(MOTOR_M2); + disableMotor(MOTOR_M3); + disableMotor(MOTOR_M4); + + // Set all 'on time' registers to 0 + m_pca9685->ledOnTime(PCA9685_ALL_LED, 0); + + // set the default stepper config at 200 steps per rev + stepConfig(STEPMOTOR_M12, 200); + stepConfig(STEPMOTOR_M34, 200); +} + +AdafruitMS1438::~AdafruitMS1438() +{ + delete m_pca9685; +} + +void AdafruitMS1438::initClock(STEPMOTORS_T motor) +{ + gettimeofday(&m_stepConfig[motor].startTime, NULL); +} + +uint32_t AdafruitMS1438::getMillis(STEPMOTORS_T motor) +{ + struct timeval elapsed, now; + uint32_t elapse; + + // get current time + gettimeofday(&now, NULL); + + struct timeval startTime = m_stepConfig[motor].startTime; + + // compute the delta since m_startTime + if( (elapsed.tv_usec = now.tv_usec - startTime.tv_usec) < 0 ) + { + elapsed.tv_usec += 1000000; + elapsed.tv_sec = now.tv_sec - startTime.tv_sec - 1; + } + else + { + elapsed.tv_sec = now.tv_sec - startTime.tv_sec; + } + + elapse = (uint32_t)((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000)); + + // never return 0 + if (elapse == 0) + elapse = 1; + + return elapse; +} + +// setup the pin mappings of the pca9685 outputs to the proper motor controls +void AdafruitMS1438::setupPinMaps() +{ + // first the dc motors + m_dcMotors[0] = (DC_PINMAP_T){ 8, 10, 9 }; + m_dcMotors[1] = (DC_PINMAP_T){ 13, 11, 12 }; + m_dcMotors[2] = (DC_PINMAP_T){ 2, 4, 3 }; + m_dcMotors[3] = (DC_PINMAP_T){ 7, 5, 6 }; + + // now the 2 steppers + m_stepMotors[0] = (STEPPER_PINMAP_T){ 8, 10, 9, + 13, 11, 12 }; + m_stepMotors[1] = (STEPPER_PINMAP_T){ 2, 4, 3, + 7, 5, 6 }; +} + +void AdafruitMS1438::setPWMPeriod(float hz) +{ + // must be in sleep mode to set the prescale register + m_pca9685->setModeSleep(true); + m_pca9685->setPrescaleFromHz(hz); + m_pca9685->setModeSleep(false); +} + +void AdafruitMS1438::enableMotor(DCMOTORS_T motor) +{ + m_pca9685->ledFullOff(m_dcMotors[motor].pwm, false); +} + +void AdafruitMS1438::disableMotor(DCMOTORS_T motor) +{ + m_pca9685->ledFullOff(m_dcMotors[motor].pwm, true); +} + +void AdafruitMS1438::enableStepper(STEPMOTORS_T motor) +{ + m_pca9685->ledFullOff(m_stepMotors[motor].pwmA, false); + m_pca9685->ledFullOff(m_stepMotors[motor].pwmB, false); +} + +void AdafruitMS1438::disableStepper(STEPMOTORS_T motor) +{ + m_pca9685->ledFullOff(m_stepMotors[motor].pwmA, true); + m_pca9685->ledFullOff(m_stepMotors[motor].pwmB, true); +} + +void AdafruitMS1438::setMotorSpeed(DCMOTORS_T motor, int speed) +{ + if (speed < 0) + speed = 0; + + if (speed > 100) + speed = 100; + + float percent = float(speed) / 100.0; + + m_pca9685->ledOffTime(m_dcMotors[motor].pwm, int(4095.0 * percent)); +} + +void AdafruitMS1438::setStepperSpeed(STEPMOTORS_T motor, int speed) +{ + m_stepConfig[motor].stepDelay = 60 * 1000 / + m_stepConfig[motor].stepsPerRev / speed; +} + +void AdafruitMS1438::setMotorDirection(DCMOTORS_T motor, DIRECTION_T dir) +{ + if (dir & 0x01) + { + m_pca9685->ledFullOn(m_dcMotors[motor].in1, true); + m_pca9685->ledFullOff(m_dcMotors[motor].in1, false); + } + else + { + m_pca9685->ledFullOff(m_dcMotors[motor].in1, true); + m_pca9685->ledFullOn(m_dcMotors[motor].in1, false); + } + + if (dir & 0x02) + { + m_pca9685->ledFullOn(m_dcMotors[motor].in2, true); + m_pca9685->ledFullOff(m_dcMotors[motor].in2, false); + } + else + { + m_pca9685->ledFullOff(m_dcMotors[motor].in2, true); + m_pca9685->ledFullOn(m_dcMotors[motor].in2, false); + } +} + +void AdafruitMS1438::setStepperDirection(STEPMOTORS_T motor, DIRECTION_T dir) +{ + switch (dir) + { + case DIR_CW: + m_stepConfig[motor].stepDirection = 1; + break; + case DIR_CCW: + m_stepConfig[motor].stepDirection = -1; + break; + default: // default to 1 if DIR_NONE specified + m_stepConfig[motor].stepDirection = 1; + break; + } +} + +void AdafruitMS1438::stepConfig(STEPMOTORS_T motor, unsigned int stepsPerRev) +{ + m_stepConfig[motor].stepsPerRev = stepsPerRev; + m_stepConfig[motor].currentStep = 0; + m_stepConfig[motor].stepDelay = 0; + m_stepConfig[motor].stepDirection = 1; // forward + + // now, setup the control pins - we want both FULL ON and FULL OFF. + // Since FULL OFF has precedence, we can then control the steps by + // just turning on/off the FULL OFF bit for the relevant outputs + + m_pca9685->ledFullOff(m_stepMotors[motor].pwmA, true); + m_pca9685->ledFullOn(m_stepMotors[motor].pwmA, true); + + m_pca9685->ledFullOff(m_stepMotors[motor].pwmB, true); + m_pca9685->ledFullOn(m_stepMotors[motor].pwmB, true); + + m_pca9685->ledFullOff(m_stepMotors[motor].in1A, true); + m_pca9685->ledFullOn(m_stepMotors[motor].in1A, true); + + m_pca9685->ledFullOff(m_stepMotors[motor].in2A, true); + m_pca9685->ledFullOn(m_stepMotors[motor].in2A, true); + + m_pca9685->ledFullOff(m_stepMotors[motor].in1B, true); + m_pca9685->ledFullOn(m_stepMotors[motor].in1B, true); + + m_pca9685->ledFullOff(m_stepMotors[motor].in2B, true); + m_pca9685->ledFullOn(m_stepMotors[motor].in2B, true); +} + +void AdafruitMS1438::stepperStep(STEPMOTORS_T motor) +{ + int step = m_stepConfig[motor].currentStep % 4; + + // Step I0 I1 I2 I3 + // 1 1 0 1 0 + // 2 0 1 1 0 + // 3 0 1 0 1 + // 4 1 0 0 1 + + // we invert the logic since we are essentially toggling an OFF bit, + // not an ON bit. + switch (step) + { + case 0: // 1010 + m_pca9685->ledFullOff(m_stepMotors[motor].in1A, false); + m_pca9685->ledFullOff(m_stepMotors[motor].in2A, true); + m_pca9685->ledFullOff(m_stepMotors[motor].in1B, false); + m_pca9685->ledFullOff(m_stepMotors[motor].in2B, true); + break; + case 1: // 0110 + m_pca9685->ledFullOff(m_stepMotors[motor].in1A, true); + m_pca9685->ledFullOff(m_stepMotors[motor].in2A, false); + m_pca9685->ledFullOff(m_stepMotors[motor].in1B, false); + m_pca9685->ledFullOff(m_stepMotors[motor].in2B, true); + break; + case 2: //0101 + m_pca9685->ledFullOff(m_stepMotors[motor].in1A, true); + m_pca9685->ledFullOff(m_stepMotors[motor].in2A, false); + m_pca9685->ledFullOff(m_stepMotors[motor].in1B, true); + m_pca9685->ledFullOff(m_stepMotors[motor].in2B, false); + break; + case 3: //1001 + m_pca9685->ledFullOff(m_stepMotors[motor].in1A, false); + m_pca9685->ledFullOff(m_stepMotors[motor].in2A, true); + m_pca9685->ledFullOff(m_stepMotors[motor].in1B, true); + m_pca9685->ledFullOff(m_stepMotors[motor].in2B, false); + break; + } +} + +void AdafruitMS1438::stepperSteps(STEPMOTORS_T motor, unsigned int steps) +{ + while (steps > 0) + { + if (getMillis(motor) >= m_stepConfig[motor].stepDelay) + { + // reset the clock + initClock(motor); + + m_stepConfig[motor].currentStep += m_stepConfig[motor].stepDirection; + + if (m_stepConfig[motor].stepDirection == 1) + { + if (m_stepConfig[motor].currentStep >= + m_stepConfig[motor].stepsPerRev) + m_stepConfig[motor].currentStep = 0; + } + else + { + if (m_stepConfig[motor].currentStep <= 0) + m_stepConfig[motor].currentStep = + m_stepConfig[motor].stepsPerRev; + } + + steps--; + stepperStep(motor); + } + } +} + diff --git a/src/adafruitms1438/adafruitms1438.h b/src/adafruitms1438/adafruitms1438.h new file mode 100644 index 00000000..59a9dc75 --- /dev/null +++ b/src/adafruitms1438/adafruitms1438.h @@ -0,0 +1,244 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include +#include + +#include "pca9685.h" + +#define ADAFRUITMS1438_I2C_BUS 0 +#define ADAFRUITMS1438_DEFAULT_I2C_ADDR 0x60 + +namespace upm { + + /** + * @brief UPM module for the Adafruit Motor Shield 1438 + * @defgroup adafruitms1438 libupm-adafruitms1438 + */ + + /** + * @brief C++ API for the ADAFRUITMS1438 motor shield + * + * This class implements support for the stepper and DC motors that + * can be connected to this Motor Shield. + * http://www.adafruit.com/products/1438 + * + * NOTE: The two servo connections are not actually controlled by + * the pca9685 controller (or this class), rather they are connected + * directly to digital PWM pins 9 and 10 on the arduino breakout. + * + * @ingroup i2c adafruitms1438 + * An example using a DC motor conected to M3 + * @snippet adafruitms1438.cxx Interesting + * An example using a stepper motor connected to M1 & M2 + * @snippet adafruitms1438-stepper.cxx Interesting + */ + class AdafruitMS1438 { + public: + + /** + * Enum to specify the direction of a motor + */ + typedef enum { + DIR_NONE = 0x00, + DIR_CW = 0x01, + DIR_CCW = 0x02 + } DIRECTION_T; + + /** + * Enum to specify a DC motor + */ + typedef enum { + MOTOR_M1 = 0, + MOTOR_M2 = 1, + MOTOR_M3 = 2, + MOTOR_M4 = 3 + } DCMOTORS_T; + + /** + * Enum to specify a Stepper motor + */ + typedef enum { + STEPMOTOR_M12 = 0, + STEPMOTOR_M34 = 1 + } STEPMOTORS_T; + + /** + * AdafruitMS1438 constructor + * + * @param bus i2c bus to use + * @param address the address for this sensor + */ + AdafruitMS1438(int bus, uint8_t address = ADAFRUITMS1438_DEFAULT_I2C_ADDR); + + /** + * AdafruitMS1438 Destructor + */ + ~AdafruitMS1438(); + + /** + * Return the number of milliseconds elapsed since initClock(...) + * was last called. + * + * @return elapsed milliseconds + */ + uint32_t getMillis(STEPMOTORS_T motor); + + /** + * Reset the Clock + * + */ + void initClock(STEPMOTORS_T motor); + + /** + * Set the PWM period. Note this applies to all PWM channels. + * + * @param hz set the PWM period + */ + void setPWMPeriod(float hz); + + /** + * enable PWM output for a motor + * + * @param motor the DC motor to enable + */ + void enableMotor(DCMOTORS_T motor); + + /** + * disable PWM output for a motor + * + * @param motor the DC motor to disable + */ + void disableMotor(DCMOTORS_T motor); + + /** + * enable output for a stepper motor + * + * @param motor the stepper motor to enable + */ + void enableStepper(STEPMOTORS_T motor); + + /** + * disable output for a stepper motor + * + * @param motor the stepper motor to disable + */ + void disableStepper(STEPMOTORS_T motor); + + /** + * set the speed of a DC motor. Values can range from 0 (off) to + * 100 (full speed). + * + * @param motor the DC motor to configure + * @param speed speed to set the motor to + */ + void setMotorSpeed(DCMOTORS_T motor, int speed); + + /** + * set the speed of a stepper in revolution per minute (RPM) + * + * @param motor the DC motor to configure + * @param speed speed to set the motor to + */ + void setStepperSpeed(STEPMOTORS_T motor, int speed); + + /** + * set the direction of a DC motor, clockwise or counter clockwise + * + * @param motor the DC motor to configure + * @param dir direction to set the motor to + */ + void setMotorDirection(DCMOTORS_T motor, DIRECTION_T dir); + + /** + * set the direction of a stepper motor, clockwise or counter clockwise + * + * @param motor the stepper motor to configure + * @param dir direction to set the motor to + */ + void setStepperDirection(STEPMOTORS_T motor, DIRECTION_T dir); + + /** + * set a stepper motor configuration + * + * @param motor the stepper motor to configure + * @param stepsPerRev the number of step to complete a full revolution + */ + void stepConfig(STEPMOTORS_T motor, unsigned int stepsPerRev); + + /** + * step a stepper motor a specified number of steps + * + * @param motor the stepper motor to step + * @param steps number of steps to move the stepper motor + */ + void stepperSteps(STEPMOTORS_T motor, unsigned int steps); + + private: + // SWIG will generate warning for these 'nested structs', however + // those can be ignored as these structs are never exposed. + + // struct to hold mappings of the dc motors + typedef struct { + int pwm; + int in1; + int in2; + } DC_PINMAP_T; + + // struct to hold mappings of the stepper motors + typedef struct { + int pwmA; + int in1A; + int in2A; + int pwmB; + int in1B; + int in2B; + } STEPPER_PINMAP_T; + + // struct to hold some information about each stepper + typedef struct { + int stepsPerRev; // steps per revolution + int currentStep; // current step number + uint32_t stepDelay; // delay between steps + int stepDirection; // direction to step + struct timeval startTime; // starting time + } STEPPER_CONFIG_T; + + void setupPinMaps(); + void stepperStep(STEPMOTORS_T motor); + + DC_PINMAP_T m_dcMotors[4]; + STEPPER_PINMAP_T m_stepMotors[2]; + STEPPER_CONFIG_T m_stepConfig[2]; + + PCA9685 *m_pca9685; + }; +} + + diff --git a/src/adafruitms1438/jsupm_adafruitms1438.i b/src/adafruitms1438/jsupm_adafruitms1438.i new file mode 100644 index 00000000..69060e54 --- /dev/null +++ b/src/adafruitms1438/jsupm_adafruitms1438.i @@ -0,0 +1,8 @@ +%module jsupm_adafruitms1438 +%include "../upm.i" + +%{ + #include "adafruitms1438.h" +%} + +%include "adafruitms1438.h" diff --git a/src/adafruitms1438/pyupm_adafruitms1438.i b/src/adafruitms1438/pyupm_adafruitms1438.i new file mode 100644 index 00000000..69016601 --- /dev/null +++ b/src/adafruitms1438/pyupm_adafruitms1438.i @@ -0,0 +1,13 @@ +%module pyupm_adafruitms1438 +%include "../upm.i" + +%feature("autodoc", "3"); + +#ifdef DOXYGEN +%include "adafruitms1438_doc.i" +#endif + +%include "adafruitms1438.h" +%{ + #include "adafruitms1438.h" +%}