mirror of
https://github.com/eclipse/upm.git
synced 2025-07-04 10:51:12 +03:00
grovemd: add support for 'mode1' stepping and add stepper examples
The current grovemd driver supported 'mode2' stepping, where the driver simply passed various stepper commands to the board for it to carry out on it's own. This doesn't work very well (or at all if you have old/buggy firmware) so add a new 'mode1' stepper capability. This mode lets the driver manually control the stepping operation without requiring special firmware. This is now the default and recommended mode to use for stepper motors on this device. It is also more flexible in terms of the maximum number of steps you can do (mode2 was limited to 254 steps max). This was tested using a bipolar NEMA-17 stepper motor with an external 12v power supply. Note: 'Mode1' and 'Mode2' are the Seeed Studio terms for these different stepping modes. Signed-off-by: Jon Trulson <jtrulson@ics.com> Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:

committed by
Mihai Tudor Panu

parent
d94a6d00fb
commit
83e62aabba
@ -33,39 +33,36 @@ using namespace upm;
|
||||
using namespace std;
|
||||
|
||||
|
||||
GroveMD::GroveMD(int bus, uint8_t address)
|
||||
GroveMD::GroveMD(int bus, uint8_t address) :
|
||||
m_i2c(bus)
|
||||
{
|
||||
m_addr = address;
|
||||
|
||||
// setup our i2c link
|
||||
if ( !(m_i2c = mraa_i2c_init(bus)) )
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__) +
|
||||
": mraa_i2c_init() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// this board *requires* 100Khz i2c bus only
|
||||
mraa_result_t rv;
|
||||
if ( (rv = mraa_i2c_frequency(m_i2c, MRAA_I2C_STD)) != MRAA_SUCCESS )
|
||||
mraa::Result rv;
|
||||
if ( (rv = m_i2c.frequency(mraa::I2C_STD)) != mraa::SUCCESS )
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__) +
|
||||
": mraa_i2c_frequency(MRAA_I2C_STD) failed");
|
||||
": I2c.frequency(I2C_STD) failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mraa_i2c_address(m_i2c, m_addr))
|
||||
if (m_i2c.address(m_addr))
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": mraa_i2c_address() failed");
|
||||
": I2c.address() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
initClock();
|
||||
// default to mode1 stepper operation, 200 steps per rev.
|
||||
configStepper(200, STEP_MODE1);
|
||||
}
|
||||
|
||||
GroveMD::~GroveMD()
|
||||
{
|
||||
setMotorSpeeds(0, 0);
|
||||
mraa_i2c_stop(m_i2c);
|
||||
writePacket(SET_DIRECTION, 0, GROVEMD_NOOP);
|
||||
}
|
||||
|
||||
bool GroveMD::writePacket(REG_T reg, uint8_t data1, uint8_t data2)
|
||||
@ -76,11 +73,10 @@ bool GroveMD::writePacket(REG_T reg, uint8_t data1, uint8_t data2)
|
||||
buf[1] = data1;
|
||||
buf[2] = data2;
|
||||
|
||||
mraa_result_t rv;
|
||||
if ( (rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS )
|
||||
if ( m_i2c.write(buf, 3) != mraa::SUCCESS )
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": mraa_i2c_address() failed");
|
||||
": I2c.write() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -91,13 +87,6 @@ bool GroveMD::writePacket(REG_T reg, uint8_t data1, uint8_t data2)
|
||||
|
||||
usleep(100);
|
||||
|
||||
if ( (rv = mraa_i2c_write(m_i2c, buf, 3)) != MRAA_SUCCESS )
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": mraa_i2c_write() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -119,25 +108,137 @@ bool GroveMD::setMotorDirections(DC_DIRECTION_T dirA, DC_DIRECTION_T dirB)
|
||||
|
||||
bool GroveMD::enableStepper(STEP_DIRECTION_T dir, uint8_t speed)
|
||||
{
|
||||
return writePacket(STEPPER_ENABLE, dir, speed);
|
||||
// If mode 2, send the command and return immediately
|
||||
if (m_stepMode == STEP_MODE2)
|
||||
return writePacket(STEPPER_ENABLE, dir, speed);
|
||||
|
||||
// otherwise, mode 1, setup the basics and start stepping.
|
||||
|
||||
m_stepDelay = 60 * 1000 / m_stepsPerRev / speed;
|
||||
m_stepDirection = ((dir == STEP_DIR_CW) ? 1 : -1);
|
||||
|
||||
// seeed says speed should always be 255,255 for stepper operation
|
||||
setMotorSpeeds(255, 255);
|
||||
|
||||
while (m_totalSteps > 0)
|
||||
{
|
||||
if (getMillis() >= m_stepDelay)
|
||||
{
|
||||
// reset the clock
|
||||
initClock();
|
||||
|
||||
m_currentStep += m_stepDirection;
|
||||
|
||||
if (m_stepDirection == 1)
|
||||
{
|
||||
if (m_currentStep >= m_stepsPerRev)
|
||||
m_currentStep = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_currentStep <= 0)
|
||||
m_currentStep = m_stepsPerRev;
|
||||
}
|
||||
|
||||
m_totalSteps--;
|
||||
stepperStep();
|
||||
}
|
||||
}
|
||||
|
||||
// and... we're done
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GroveMD::disableStepper()
|
||||
{
|
||||
return writePacket(STEPPER_DISABLE, GROVEMD_NOOP, GROVEMD_NOOP);
|
||||
if (m_stepMode == STEP_MODE2)
|
||||
return writePacket(STEPPER_DISABLE, GROVEMD_NOOP, GROVEMD_NOOP);
|
||||
|
||||
// else, mode 1
|
||||
writePacket(SET_DIRECTION, 0, GROVEMD_NOOP);
|
||||
return setMotorSpeeds(0, 0);
|
||||
}
|
||||
|
||||
bool GroveMD::setStepperSteps(uint8_t steps)
|
||||
bool GroveMD::setStepperSteps(unsigned int steps)
|
||||
{
|
||||
if (steps == 0)
|
||||
if (m_stepMode == STEP_MODE2)
|
||||
{
|
||||
// invalid
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": invalid number of steps. " +
|
||||
"Valid values are between 1 and 255.");
|
||||
return false;
|
||||
if (steps == 0)
|
||||
{
|
||||
// invalid
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": invalid number of steps. " +
|
||||
"Valid values are between 1 and 255.");
|
||||
return false;
|
||||
}
|
||||
return writePacket(STEPPER_NUM_STEPS, steps, GROVEMD_NOOP);
|
||||
}
|
||||
|
||||
return writePacket(STEPPER_NUM_STEPS, steps, GROVEMD_NOOP);
|
||||
// for mode one, just store it for future use by enableStepper()
|
||||
m_totalSteps = steps;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GroveMD::initClock()
|
||||
{
|
||||
gettimeofday(&m_startTime, NULL);
|
||||
}
|
||||
|
||||
uint32_t GroveMD::getMillis()
|
||||
{
|
||||
struct timeval elapsed, now;
|
||||
uint32_t elapse;
|
||||
|
||||
// get current time
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
// compute the delta since m_startTime
|
||||
if( (elapsed.tv_usec = now.tv_usec - m_startTime.tv_usec) < 0 )
|
||||
{
|
||||
elapsed.tv_usec += 1000000;
|
||||
elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec;
|
||||
}
|
||||
|
||||
elapse = (uint32_t)((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000));
|
||||
|
||||
// never return 0
|
||||
if (elapse == 0)
|
||||
elapse = 1;
|
||||
|
||||
return elapse;
|
||||
}
|
||||
|
||||
void GroveMD::configStepper(unsigned int stepsPerRev, STEP_MODE_T mode)
|
||||
{
|
||||
m_stepsPerRev = stepsPerRev;
|
||||
m_stepMode = mode;
|
||||
m_currentStep = 0;
|
||||
m_stepDelay = 0;
|
||||
m_stepDirection = 1;
|
||||
m_totalSteps = 0;
|
||||
}
|
||||
|
||||
void GroveMD::stepperStep()
|
||||
{
|
||||
int step = m_currentStep % 4;
|
||||
|
||||
switch (step)
|
||||
{
|
||||
case 0:
|
||||
writePacket(SET_DIRECTION, 0b0101, GROVEMD_NOOP);
|
||||
break;
|
||||
case 1:
|
||||
writePacket(SET_DIRECTION, 0b0110, GROVEMD_NOOP);
|
||||
break;
|
||||
case 2:
|
||||
writePacket(SET_DIRECTION, 0b1010, GROVEMD_NOOP);
|
||||
break;
|
||||
case 3:
|
||||
writePacket(SET_DIRECTION, 0b1001, GROVEMD_NOOP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user