gobot.io/x/gobot@v1.16.0/drivers/i2c/adafruit_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"errors"
     5  	"log"
     6  	"math"
     7  	"time"
     8  
     9  	"gobot.io/x/gobot"
    10  )
    11  
    12  // AdafruitDirection declares a type for specification of the motor direction
    13  type AdafruitDirection int
    14  
    15  // AdafruitStepStyle declares a type for specification of the stepper motor rotation
    16  type AdafruitStepStyle int
    17  
    18  type adaFruitDCMotor struct {
    19  	pwmPin, in1Pin, in2Pin byte
    20  }
    21  type adaFruitStepperMotor struct {
    22  	pwmPinA, pwmPinB                   byte
    23  	ain1, ain2                         byte
    24  	bin1, bin2                         byte
    25  	secPerStep                         float64
    26  	currentStep, stepCounter, revSteps int
    27  }
    28  
    29  // AdafruitMotorHatDriver is a driver for the DC+Stepper Motor HAT from Adafruit.
    30  // The HAT is a Raspberry Pi add-on that can drive up to 4 DC or 2 Stepper motors
    31  // with full PWM speed control.  It has a dedicated PWM driver chip onboard to
    32  // control both motor direction and speed over I2C.
    33  type AdafruitMotorHatDriver struct {
    34  	name               string
    35  	connector          Connector
    36  	motorHatConnection Connection
    37  	servoHatConnection Connection
    38  	Config
    39  	gobot.Commander
    40  	dcMotors      []adaFruitDCMotor
    41  	stepperMotors []adaFruitStepperMotor
    42  }
    43  
    44  var adafruitDebug = false // Set this to true to see debug output
    45  
    46  var (
    47  	// Each Adafruit HAT must have a unique I2C address. The default address for
    48  	// the DC and Stepper Motor HAT is 0x60. The addresses of the Motor HATs can
    49  	// range from 0x60 to 0x80 for a total of 32 unique addresses.
    50  	// The base address for the Adafruit PWM-Servo HAT is 0x40.  Please consult
    51  	// the Adafruit documentation for soldering and addressing stacked HATs.
    52  	motorHatAddress       = 0x60
    53  	servoHatAddress       = 0x40
    54  	stepperMicrosteps     = 8
    55  	stepperMicrostepCurve []int
    56  	step2coils            = make(map[int][]int32)
    57  )
    58  
    59  const (
    60  	// Registers
    61  	_Mode1       = 0x00
    62  	_Mode2       = 0x01
    63  	_SubAdr1     = 0x02
    64  	_SubAdr2     = 0x03
    65  	_SubAdr3     = 0x04
    66  	_Prescale    = 0xFE
    67  	_LedZeroOnL  = 0x06
    68  	_LedZeroOnH  = 0x07
    69  	_LedZeroOffL = 0x08
    70  	_LedZeroOffH = 0x09
    71  	_AllLedOnL   = 0xFA
    72  	_AllLedOnH   = 0xFB
    73  	_AllLedOffL  = 0xFC
    74  	_AllLedOffH  = 0xFD
    75  
    76  	// Bits
    77  	_Restart = 0x80
    78  	_Sleep   = 0x10
    79  	_AllCall = 0x01
    80  	_Invrt   = 0x10
    81  	_Outdrv  = 0x04
    82  )
    83  
    84  const (
    85  	AdafruitForward  AdafruitDirection = iota // 0
    86  	AdafruitBackward                          // 1
    87  	AdafruitRelease                           // 2
    88  )
    89  
    90  const (
    91  	AdafruitSingle     AdafruitStepStyle = iota // 0
    92  	AdafruitDouble                              // 1
    93  	AdafruitInterleave                          // 2
    94  	AdafruitMicrostep                           // 3
    95  )
    96  
    97  // NewAdafruitMotorHatDriver initializes the internal DCMotor and StepperMotor types.
    98  // Again the Adafruit Motor Hat supports up to four DC motors and up to two stepper motors.
    99  // Params:
   100  //		conn Connector - the Adaptor to use with this Driver
   101  //
   102  // Optional params:
   103  //		i2c.WithBus(int):	bus to use with this driver
   104  //		i2c.WithAddress(int):	address to use with this driver
   105  //
   106  func NewAdafruitMotorHatDriver(conn Connector, options ...func(Config)) *AdafruitMotorHatDriver {
   107  	var dc []adaFruitDCMotor
   108  	var st []adaFruitStepperMotor
   109  	for i := 0; i < 4; i++ {
   110  		switch {
   111  		case i == 0:
   112  			dc = append(dc, adaFruitDCMotor{pwmPin: 8, in1Pin: 10, in2Pin: 9})
   113  			st = append(st, adaFruitStepperMotor{pwmPinA: 8, pwmPinB: 13,
   114  				ain1: 10, ain2: 9, bin1: 11, bin2: 12, revSteps: 200, secPerStep: 0.1})
   115  		case i == 1:
   116  			dc = append(dc, adaFruitDCMotor{pwmPin: 13, in1Pin: 11, in2Pin: 12})
   117  			st = append(st, adaFruitStepperMotor{pwmPinA: 2, pwmPinB: 7,
   118  				ain1: 4, ain2: 3, bin1: 5, bin2: 6, revSteps: 200, secPerStep: 0.1})
   119  		case i == 2:
   120  			dc = append(dc, adaFruitDCMotor{pwmPin: 2, in1Pin: 4, in2Pin: 3})
   121  		case i == 3:
   122  			dc = append(dc, adaFruitDCMotor{pwmPin: 7, in1Pin: 5, in2Pin: 6})
   123  		}
   124  	}
   125  
   126  	driver := &AdafruitMotorHatDriver{
   127  		name:          gobot.DefaultName("AdafruitMotorHat"),
   128  		connector:     conn,
   129  		Config:        NewConfig(),
   130  		Commander:     gobot.NewCommander(),
   131  		dcMotors:      dc,
   132  		stepperMotors: st,
   133  	}
   134  
   135  	for _, option := range options {
   136  		option(driver)
   137  	}
   138  
   139  	// TODO: add API funcs
   140  	return driver
   141  }
   142  
   143  // SetMotorHatAddress sets the I2C address for the DC and Stepper Motor HAT.
   144  // This addressing flexibility empowers "stacking" the HATs.
   145  func (a *AdafruitMotorHatDriver) SetMotorHatAddress(addr int) (err error) {
   146  	motorHatAddress = addr
   147  	return
   148  }
   149  
   150  // SetServoHatAddress sets the I2C address for the PWM-Servo Motor HAT.
   151  // This addressing flexibility empowers "stacking" the HATs.
   152  func (a *AdafruitMotorHatDriver) SetServoHatAddress(addr int) (err error) {
   153  	servoHatAddress = addr
   154  	return
   155  }
   156  
   157  // Name identifies this driver object
   158  func (a *AdafruitMotorHatDriver) Name() string { return a.name }
   159  
   160  // SetName sets nae for driver
   161  func (a *AdafruitMotorHatDriver) SetName(n string) { a.name = n }
   162  
   163  // Connection identifies the particular adapter object
   164  func (a *AdafruitMotorHatDriver) Connection() gobot.Connection { return a.connector.(gobot.Connection) }
   165  
   166  func (a *AdafruitMotorHatDriver) startDriver(connection Connection) (err error) {
   167  	if err = a.setAllPWM(connection, 0, 0); err != nil {
   168  		return
   169  	}
   170  	reg := byte(_Mode2)
   171  	val := byte(_Outdrv)
   172  	if _, err = connection.Write([]byte{reg, val}); err != nil {
   173  		return
   174  	}
   175  	reg = byte(_Mode1)
   176  	val = byte(_AllCall)
   177  	if _, err = connection.Write([]byte{reg, val}); err != nil {
   178  		return
   179  	}
   180  	time.Sleep(5 * time.Millisecond)
   181  
   182  	// Read a byte from the I2C device.  Note: no ability to read from a specified reg?
   183  	mode1 := []byte{0}
   184  	_, rerr := connection.Read(mode1)
   185  	if rerr != nil {
   186  		return rerr
   187  	}
   188  	if len(mode1) > 0 {
   189  		reg = byte(_Mode1)
   190  		val = mode1[0] & _Sleep
   191  		if _, err = connection.Write([]byte{reg, val}); err != nil {
   192  			return
   193  		}
   194  		time.Sleep(5 * time.Millisecond)
   195  	}
   196  
   197  	return
   198  }
   199  
   200  // Start initializes both I2C-addressable Adafruit Motor HAT drivers
   201  func (a *AdafruitMotorHatDriver) Start() (err error) {
   202  	bus := a.GetBusOrDefault(a.connector.GetDefaultBus())
   203  
   204  	err = a.startServoHat(bus)
   205  	if adafruitDebug && err != nil {
   206  		log.Printf("[adafruit_driver] start servohat error: %s\n", err)
   207  	}
   208  
   209  	err = a.startMotorHat(bus)
   210  	if adafruitDebug && err != nil {
   211  		log.Printf("[adafruit_driver] start motorhat error: %s\n", err)
   212  	}
   213  
   214  	return
   215  }
   216  
   217  // startServoHat starts the Servo motors connection.
   218  func (a *AdafruitMotorHatDriver) startServoHat(bus int) (err error) {
   219  	if a.servoHatConnection, err = a.connector.GetConnection(servoHatAddress, bus); err != nil {
   220  		return
   221  	}
   222  
   223  	if err = a.startDriver(a.servoHatConnection); err != nil {
   224  		return
   225  	}
   226  
   227  	return
   228  }
   229  
   230  // startMotorHat starts the DC motors connection.
   231  func (a *AdafruitMotorHatDriver) startMotorHat(bus int) (err error) {
   232  	if a.motorHatConnection, err = a.connector.GetConnection(motorHatAddress, bus); err != nil {
   233  		return
   234  	}
   235  
   236  	if err = a.startDriver(a.motorHatConnection); err != nil {
   237  		return
   238  	}
   239  
   240  	return
   241  }
   242  
   243  // Halt returns true if devices is halted successfully
   244  func (a *AdafruitMotorHatDriver) Halt() (err error) { return }
   245  
   246  // setPWM sets the start (on) and end (off) of the high-segment of the PWM pulse
   247  // on the specific channel (pin).
   248  func (a *AdafruitMotorHatDriver) setPWM(conn Connection, pin byte, on, off int32) (err error) {
   249  	// register and values to be written to that register
   250  	regVals := make(map[int][]byte)
   251  	regVals[0] = []byte{byte(_LedZeroOnL + 4*pin), byte(on & 0xff)}
   252  	regVals[1] = []byte{byte(_LedZeroOnH + 4*pin), byte(on >> 8)}
   253  	regVals[2] = []byte{byte(_LedZeroOffL + 4*pin), byte(off & 0xff)}
   254  	regVals[3] = []byte{byte(_LedZeroOffH + 4*pin), byte(off >> 8)}
   255  	for i := 0; i < len(regVals); i++ {
   256  		if _, err = conn.Write(regVals[i]); err != nil {
   257  			return
   258  		}
   259  	}
   260  	return
   261  }
   262  
   263  // SetServoMotorFreq sets the frequency for the currently addressed PWM Servo HAT.
   264  func (a *AdafruitMotorHatDriver) SetServoMotorFreq(freq float64) (err error) {
   265  	if err = a.setPWMFreq(a.servoHatConnection, freq); err != nil {
   266  		return
   267  	}
   268  	return
   269  }
   270  
   271  // SetServoMotorPulse is a convenience function to specify the 'tick' value,
   272  // between 0-4095, when the signal will turn on, and when it will turn off.
   273  func (a *AdafruitMotorHatDriver) SetServoMotorPulse(channel byte, on, off int32) (err error) {
   274  	if err = a.setPWM(a.servoHatConnection, channel, on, off); err != nil {
   275  		return
   276  	}
   277  	return
   278  }
   279  
   280  // setPWMFreq adjusts the PWM frequency which determines how many full
   281  // pulses per second are generated by the integrated circuit.  The frequency
   282  // determines how "long" each pulse is in duration from start to finish,
   283  // taking into account the high and low segments of the pulse.
   284  func (a *AdafruitMotorHatDriver) setPWMFreq(conn Connection, freq float64) (err error) {
   285  	// 25MHz
   286  	preScaleVal := 25000000.0
   287  	// 12-bit
   288  	preScaleVal /= 4096.0
   289  	preScaleVal /= freq
   290  	preScaleVal -= 1.0
   291  	preScale := math.Floor(preScaleVal + 0.5)
   292  	if adafruitDebug {
   293  		log.Printf("Setting PWM frequency to:	%.2f Hz", freq)
   294  		log.Printf("Estimated pre-scale: 		%.2f", preScaleVal)
   295  		log.Printf("Final pre-scale: 			%.2f", preScale)
   296  	}
   297  	// default (and only) reads register 0
   298  	oldMode := []byte{0}
   299  	_, err = conn.Read(oldMode)
   300  	if err != nil {
   301  		return
   302  	}
   303  	// sleep?
   304  	if len(oldMode) > 0 {
   305  		newMode := (oldMode[0] & 0x7F) | 0x10
   306  		reg := byte(_Mode1)
   307  		if _, err = conn.Write([]byte{reg, newMode}); err != nil {
   308  			return
   309  		}
   310  		reg = byte(_Prescale)
   311  		val := byte(math.Floor(preScale))
   312  		if _, err = conn.Write([]byte{reg, val}); err != nil {
   313  			return
   314  		}
   315  		reg = byte(_Mode1)
   316  		if _, err = conn.Write([]byte{reg, oldMode[0]}); err != nil {
   317  			return
   318  		}
   319  		time.Sleep(5 * time.Millisecond)
   320  		if _, err = conn.Write([]byte{reg, (oldMode[0] | 0x80)}); err != nil {
   321  			return
   322  		}
   323  	}
   324  	return
   325  }
   326  
   327  // setAllPWM sets all PWM channels for the given address
   328  func (a *AdafruitMotorHatDriver) setAllPWM(conn Connection, on, off int32) (err error) {
   329  	// register and values to be written to that register
   330  	regVals := make(map[int][]byte)
   331  	regVals[0] = []byte{byte(_AllLedOnL), byte(on & 0xff)}
   332  	regVals[1] = []byte{byte(_AllLedOnH), byte(on >> 8)}
   333  	regVals[2] = []byte{byte(_AllLedOffL), byte(off & 0xFF)}
   334  	regVals[3] = []byte{byte(_AllLedOffH), byte(off >> 8)}
   335  	for i := 0; i < len(regVals); i++ {
   336  		if _, err = conn.Write(regVals[i]); err != nil {
   337  			return
   338  		}
   339  	}
   340  	return
   341  }
   342  
   343  func (a *AdafruitMotorHatDriver) setPin(conn Connection, pin byte, value int32) (err error) {
   344  	if value == 0 {
   345  		return a.setPWM(conn, pin, 0, 4096)
   346  	}
   347  	if value == 1 {
   348  		return a.setPWM(conn, pin, 4096, 0)
   349  	}
   350  	return errors.New("Invalid pin")
   351  }
   352  
   353  // SetDCMotorSpeed will set the appropriate pins to run the specified DC motor
   354  // for the given speed.
   355  func (a *AdafruitMotorHatDriver) SetDCMotorSpeed(dcMotor int, speed int32) (err error) {
   356  	if err = a.setPWM(a.motorHatConnection, a.dcMotors[dcMotor].pwmPin, 0, speed*16); err != nil {
   357  		return
   358  	}
   359  	return
   360  }
   361  
   362  // RunDCMotor will set the appropriate pins to run the specified DC motor for
   363  // the given direction
   364  func (a *AdafruitMotorHatDriver) RunDCMotor(dcMotor int, dir AdafruitDirection) (err error) {
   365  
   366  	switch {
   367  	case dir == AdafruitForward:
   368  		if err = a.setPin(a.motorHatConnection, a.dcMotors[dcMotor].in2Pin, 0); err != nil {
   369  			return
   370  		}
   371  		if err = a.setPin(a.motorHatConnection, a.dcMotors[dcMotor].in1Pin, 1); err != nil {
   372  			return
   373  		}
   374  	case dir == AdafruitBackward:
   375  		if err = a.setPin(a.motorHatConnection, a.dcMotors[dcMotor].in1Pin, 0); err != nil {
   376  			return
   377  		}
   378  		if err = a.setPin(a.motorHatConnection, a.dcMotors[dcMotor].in2Pin, 1); err != nil {
   379  			return
   380  		}
   381  	case dir == AdafruitRelease:
   382  		if err = a.setPin(a.motorHatConnection, a.dcMotors[dcMotor].in1Pin, 0); err != nil {
   383  			return
   384  		}
   385  		if err = a.setPin(a.motorHatConnection, a.dcMotors[dcMotor].in2Pin, 0); err != nil {
   386  			return
   387  		}
   388  	}
   389  	return
   390  }
   391  
   392  func (a *AdafruitMotorHatDriver) oneStep(motor int, dir AdafruitDirection, style AdafruitStepStyle) (steps int, err error) {
   393  	pwmA := 255
   394  	pwmB := 255
   395  
   396  	// Determine the stepping procedure
   397  	switch {
   398  	case style == AdafruitSingle:
   399  		if (a.stepperMotors[motor].currentStep / (stepperMicrosteps / 2) % 2) != 0 {
   400  			// we're at an odd step
   401  			if dir == AdafruitForward {
   402  				a.stepperMotors[motor].currentStep += stepperMicrosteps / 2
   403  			} else {
   404  				a.stepperMotors[motor].currentStep -= stepperMicrosteps / 2
   405  			}
   406  		} else {
   407  			// go to next even step
   408  			if dir == AdafruitForward {
   409  				a.stepperMotors[motor].currentStep += stepperMicrosteps
   410  			} else {
   411  				a.stepperMotors[motor].currentStep -= stepperMicrosteps
   412  			}
   413  		}
   414  	case style == AdafruitDouble:
   415  		if (a.stepperMotors[motor].currentStep / (stepperMicrosteps / 2) % 2) == 0 {
   416  			// we're at an even step, weird
   417  			if dir == AdafruitForward {
   418  				a.stepperMotors[motor].currentStep += stepperMicrosteps / 2
   419  			} else {
   420  				a.stepperMotors[motor].currentStep -= stepperMicrosteps / 2
   421  			}
   422  		} else {
   423  			// go to next odd step
   424  			if dir == AdafruitForward {
   425  				a.stepperMotors[motor].currentStep += stepperMicrosteps
   426  			} else {
   427  				a.stepperMotors[motor].currentStep -= stepperMicrosteps
   428  			}
   429  		}
   430  	case style == AdafruitInterleave:
   431  		if dir == AdafruitForward {
   432  			a.stepperMotors[motor].currentStep += stepperMicrosteps / 2
   433  		} else {
   434  			a.stepperMotors[motor].currentStep -= stepperMicrosteps / 2
   435  		}
   436  	case style == AdafruitMicrostep:
   437  		if dir == AdafruitForward {
   438  			a.stepperMotors[motor].currentStep++
   439  		} else {
   440  			a.stepperMotors[motor].currentStep--
   441  		}
   442  		// go to next step and wrap around
   443  		a.stepperMotors[motor].currentStep += stepperMicrosteps * 4
   444  		a.stepperMotors[motor].currentStep %= stepperMicrosteps * 4
   445  
   446  		pwmA = 0
   447  		pwmB = 0
   448  		currStep := a.stepperMotors[motor].currentStep
   449  		if currStep >= 0 && currStep < stepperMicrosteps {
   450  			pwmA = stepperMicrostepCurve[stepperMicrosteps-currStep]
   451  			pwmB = stepperMicrostepCurve[currStep]
   452  		} else if currStep >= stepperMicrosteps && currStep < stepperMicrosteps*2 {
   453  			pwmA = stepperMicrostepCurve[currStep-stepperMicrosteps]
   454  			pwmB = stepperMicrostepCurve[stepperMicrosteps*2-currStep]
   455  		} else if currStep >= stepperMicrosteps*2 && currStep < stepperMicrosteps*3 {
   456  			pwmA = stepperMicrostepCurve[stepperMicrosteps*3-currStep]
   457  			pwmB = stepperMicrostepCurve[currStep-stepperMicrosteps*2]
   458  		} else if currStep >= stepperMicrosteps*3 && currStep < stepperMicrosteps*4 {
   459  			pwmA = stepperMicrostepCurve[currStep-stepperMicrosteps*3]
   460  			pwmB = stepperMicrostepCurve[stepperMicrosteps*4-currStep]
   461  		}
   462  	} //switch
   463  
   464  	//go to next 'step' and wrap around
   465  	a.stepperMotors[motor].currentStep += stepperMicrosteps * 4
   466  	a.stepperMotors[motor].currentStep %= stepperMicrosteps * 4
   467  
   468  	//only really used for microstepping, otherwise always on!
   469  	if err = a.setPWM(a.motorHatConnection, a.stepperMotors[motor].pwmPinA, 0, int32(pwmA*16)); err != nil {
   470  		return
   471  	}
   472  	if err = a.setPWM(a.motorHatConnection, a.stepperMotors[motor].pwmPinB, 0, int32(pwmB*16)); err != nil {
   473  		return
   474  	}
   475  	var coils []int32
   476  	currStep := a.stepperMotors[motor].currentStep
   477  	if style == AdafruitMicrostep {
   478  		switch {
   479  		case currStep >= 0 && currStep < stepperMicrosteps:
   480  			coils = []int32{1, 1, 0, 0}
   481  		case currStep >= stepperMicrosteps && currStep < stepperMicrosteps*2:
   482  			coils = []int32{0, 1, 1, 0}
   483  		case currStep >= stepperMicrosteps*2 && currStep < stepperMicrosteps*3:
   484  			coils = []int32{0, 0, 1, 1}
   485  		case currStep >= stepperMicrosteps*3 && currStep < stepperMicrosteps*4:
   486  			coils = []int32{1, 0, 0, 1}
   487  		}
   488  	} else {
   489  		// step-2-coils is initialized in init()
   490  		coils = step2coils[(currStep / (stepperMicrosteps / 2))]
   491  	}
   492  	if adafruitDebug {
   493  		log.Printf("[adafruit_driver] currStep: %d, index into step2coils: %d\n",
   494  			currStep, (currStep / (stepperMicrosteps / 2)))
   495  		log.Printf("[adafruit_driver] coils state = %v", coils)
   496  	}
   497  	if err = a.setPin(a.motorHatConnection, a.stepperMotors[motor].ain2, coils[0]); err != nil {
   498  		return
   499  	}
   500  	if err = a.setPin(a.motorHatConnection, a.stepperMotors[motor].bin1, coils[1]); err != nil {
   501  		return
   502  	}
   503  	if err = a.setPin(a.motorHatConnection, a.stepperMotors[motor].ain1, coils[2]); err != nil {
   504  		return
   505  	}
   506  	if err = a.setPin(a.motorHatConnection, a.stepperMotors[motor].bin2, coils[3]); err != nil {
   507  		return
   508  	}
   509  	return a.stepperMotors[motor].currentStep, nil
   510  }
   511  
   512  // SetStepperMotorSpeed sets the seconds-per-step for the given Stepper Motor.
   513  func (a *AdafruitMotorHatDriver) SetStepperMotorSpeed(stepperMotor int, rpm int) (err error) {
   514  	revSteps := a.stepperMotors[stepperMotor].revSteps
   515  	a.stepperMotors[stepperMotor].secPerStep = 60.0 / float64(revSteps*rpm)
   516  	a.stepperMotors[stepperMotor].stepCounter = 0
   517  	return
   518  }
   519  
   520  // Step will rotate the stepper motor the given number of steps, in the given direction and step style.
   521  func (a *AdafruitMotorHatDriver) Step(motor, steps int, dir AdafruitDirection, style AdafruitStepStyle) (err error) {
   522  	secPerStep := a.stepperMotors[motor].secPerStep
   523  	latestStep := 0
   524  	if style == AdafruitInterleave {
   525  		secPerStep = secPerStep / 2.0
   526  	}
   527  	if style == AdafruitMicrostep {
   528  		secPerStep /= float64(stepperMicrosteps)
   529  		steps *= stepperMicrosteps
   530  	}
   531  	if adafruitDebug {
   532  		log.Printf("[adafruit_driver] %f seconds per step", secPerStep)
   533  	}
   534  	for i := 0; i < steps; i++ {
   535  		if latestStep, err = a.oneStep(motor, dir, style); err != nil {
   536  			return
   537  		}
   538  		time.Sleep(time.Duration(secPerStep) * time.Second)
   539  	}
   540  	// As documented in the Adafruit python driver:
   541  	// This is an edge case, if we are in between full steps, keep going to end on a full step
   542  	if style == AdafruitMicrostep {
   543  		for latestStep != 0 && latestStep != stepperMicrosteps {
   544  			if latestStep, err = a.oneStep(motor, dir, style); err != nil {
   545  				return
   546  			}
   547  			time.Sleep(time.Duration(secPerStep) * time.Second)
   548  		}
   549  	}
   550  	return
   551  }
   552  
   553  func init() {
   554  	stepperMicrostepCurve = []int{0, 50, 98, 142, 180, 212, 236, 250, 255}
   555  	step2coils[0] = []int32{1, 0, 0, 0}
   556  	step2coils[1] = []int32{1, 1, 0, 0}
   557  	step2coils[2] = []int32{0, 1, 0, 0}
   558  	step2coils[3] = []int32{0, 1, 1, 0}
   559  	step2coils[4] = []int32{0, 0, 1, 0}
   560  	step2coils[5] = []int32{0, 0, 1, 1}
   561  	step2coils[6] = []int32{0, 0, 0, 1}
   562  	step2coils[7] = []int32{1, 0, 0, 1}
   563  }