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