Home Products Shop Articles Applications Learning Zone About Us

  • Up






  • Using a Raspberry Pi with StepperBee
    (also applies to StepperBee+)

     The following details show how to control a StepperBee using a program written in Python running under the Raspbian operating system on a Raspberry Pi model B single board Computer.
     ( If you are not familiar with basic Stepper Bee functionality, more details can be found here )

    The Raspberry Pi has two standard USB sockets. One of them is usually dedicated to the keyboard (or keyboard and mouse where a small USB hub has been used). It is assumed the StepperBee is connected via a standard USB lead to one of these ports or to a free USB port on a hub if one is connected.

    The following simple example of Python Code is all that is required to run stepper motor 1 forward by 50 steps with an interval of 100ms between steps. It will also turn on switching output 1. Have a look at this code and then see the explanation that follows for a more detailed description of each of the lines.

    import usb.core

    dev = usb.core.find(idVendor=0x04d8, idProduct=0x005d)

    if dev is None:
        raise ValueError('Device not found')
    else:
        try:
            dev.detach_kernel_driver(0)
        except:
            pass
        dev.set_configuration()

        timeLSB = 100
        timeMSB = 1
        stepsLSB = 50
        stepsMSB = 1
        direction = 1
        outputs = 0b00000110

        data=[2, direction, timeLSB, timeMSB, stepsLSB, stepsMSB, outputs]
        dev.write(2,data)

    import usb.core
        This line of code imports the very popular PyUSB library of functions for communicating with USB devices. It avoids having to write any of your own code to access USB devices and provides a good range of functions to meet many requirements. In our case we only need to use four of its functions. It is freely available to download and can be installed on your Raspberry Pi very easily. There is no point in duplicating install instructions here so I will just give you a link to follow....
    http://sourceforge.net/projects/pyusb/     (opens in new window)

    dev = usb.core.find(idVendor=0x04d8, idProduct=0x005d)
        This uses one of the PyUSB functions to "find" the attached StepperBee.  The way it finds the StepperBee is by checking all available USB ports to find the one with a device that has the unique identifier associated with the StepperBee. This identifier is made up to two parts: the Vendor ID and the Product ID.  For the StepperBee this is the two hexadecimal numbers 0x04d8 and 0x005d respectively. If the device is found, the "dev" object is created for the StepperBee and can then be used for susequent operations on the StepperBee. It is only necessary to use this statement once in your program, but obviously, it needs to be before any other use of the "dev" functions.

    if dev is None:
      
     raise ValueError('Device not found
    ')
        It is always good programming practice to check if the StepperBee has actually been found before continuing. This "if" statement will "raise" an exception and halt the program if it is not.
    Assuming it is found, execution continues with the statements after the else:

        try:
            dev.detach_kernel_driver(0)
       
    except:
           
    pass
     
        The function dev.detach_kernel_driver(0) gets round a possible problem with the operating system restricting the use of the StepperBee. When the StepperBee is first plugged into the USB port the operating system tries to be helpful and associates one of its standard drivers to deal with all operations to the board. We don't want this, but, with it "attached" to the StepperBee it won't then allow any other direct operations.  This line "detaches" this driver from the StepperBee allowing us to access it directly. Note that this only needs to be done the first time the program is run after connecting the StepperBee (or after reboot). If you try and detach the driver when it is already detached the program will raise an exception and halt the program. I have found the best way to deal with this is simply to put the detach function at the head of the program inside a "try... except" clause.  In this way it will detach the driver if necessary and ignore it if already detached.

    dev.set_configuration()
        USB devices have different "configurations" that they can be set to depending on the task they are required to perform. In the case of the StepperBee, it simply has one configuration which is it's default. However, this still needs to be "set" as the active one using the statement shown. This only needs to done once in your program and before any other code that communicates with the StepperBee.

    timeLSB = 100
    timeMSB = 1
    stepsLSB = 50
    stepsMSB = 1
    direction = 1
    outputs = 0b00000110
    data=[2, direction, timeLSB, timeMSB, stepsLSB, stepsMSB, outputs]
    dev.write(2,data)

        The StepperBee obeys the usual rules of a standard USB device which requires data to be sent to it in the form of message blocks (in USB terms these are called Endpoints).  In Python we specifiy this message block by using a number sequence using the square brackets as shown.  A message block for the StepperBee consists of a message type number followed by six 8-bit numbers that correspond to the required settings for the stepper motor. The message type number for commands for stepper motor 1 is simply '2'. This indicates to the StepperBee that it should use the following 6 numbers to control stepper motor 1.  Each number has been given a named variable above but it could just as easily have been entered as simple numbers into the data array. For example the above is equivalent to .....
    data=[2, 1, 100, 1, 50, 1, 0b00000001]
        The "timeLSB and timeMSB" variables hold the time interval between stepper motor steps. i.e. this controls the speed of rotation.  The time interval, expressed in milliseconds, is made up of these two 8 bit numbers, both in the range 1 to 128.  The actual resulting time interval is simply (timeMSB x 128) + timeLSB.. Similarly, the stepsLSB and stepsMSB correspond to the number of steps to do. Again this is given by two n umbers in the range 1 to 128 with the resulting number being  (stepsMSB x 128) + timeLSB.
        The "direction" variable is either '0' or '1' which corresponds to "forward" or "reverse" respectively.
    The "outputs" variable contains the desired settings for the three switching outputs associated with motor 1.  It is a simple 8 bit number with the least significant bits corrsponding to the 3 outputs. The number shown (0b00000001) would turn on output 1 (outputs 2 and 3 off).
        In the example shown the time interval between steps would be 100ms, the number of steps to run would be 50, the direction would be forward and only switching output '1' would be on.
        dev.write(2, data)  The line immediately following the setup of the data array actually "writes" this data to the stepper bee across the USB interface. The number '2' shown is just the USB buffer name used by the stepper bee for incoming messages and remains constant for all messages sent to the board.
        To stop a motor that is currently running, you just need to send a message with the steps and interval set to '0'.... i.e.
    data=[2, 0, 0, 0, 0, 0, outputs]
    dev.write(2, data)

        Note that this will still set the outputs to the bit pattern supplied in the "outputs" variable. This offers a convenient way of manipulating the outputs without moving the stepper motor. i.e. just keep sending stop commands with your chosen outputs set.

        The above set of code applies to running stepper motor 1.   To run motor 2,  the code is identical except that the message number is now '4'.   the equivalent  for motor 2 would be ....
    data=[4, 1, 100, 1, 50, 1, 0b00000001]
    dev.write(2, data)

        In the above description its worth noting that the first few lines may look slightly complicated but, once your program has "found" the StepperBee, detached the kernel driver (if necessary) and set the StepperBee configuration, the control of the StepperBee motors and is simply a case of using the "dev.write" function (with the appropriate data in the data array) as often as you like.

     Raspbian Note:   Always remember that running code in Raspbian that accesses USB devices requires you to be in "superuser" mode to have the necessary permissions. This may mean running your Python program with the usual "sudo ...." prefix or, if using the graphical environment with IDLE as your programming environment, you may need to run it from a terminal window (i.e.  typing "sudo idle" in the terminal window) for the programs created to work properly.

    Some examples:

    # run motor1 forward by 1000 steps with 50ms between steps and turn on output 2
        data=[2, 0, 51, 1, 105, 8, 0b00000010]
        dev.write(2,data)

    # run motor2 forward by 100 steps with 500ms between steps and turn on output 3
        data=[4, 0, 4, 117, 101, 1, 0b00000100]
        dev.write(2,data)

    # run motor2 in reverse by 10 steps with 100ms between steps and turn all outputs off
        data=[2, 1, 101, 1, 11, 1, 0b00000000]
        dev.write(2,data)

    Note:  It is probably worth emphasizing that, in the above examples, it may look odd that the number used is always one more than you would expect. i.e. in the example directly above where it is required to run for 10 steps, the stepsLSB number is 11.  This is due to the number range being used as 1 -128 (not 0 - 128).  It is simply a quirk of the microcontroller subsystem and should just be accepted (as odd as it may seem).  This also applies to the time interval numbers.

    --------

     Other Facilities
       There are two other facilities available on the stepper bee which can be used when required. These are to "SetStepMode" (i.e. fullstep, wavestep or power off) and the "GetCurrentStatus" function which returns the current running state of both motors and the current state of the 5 digital inputs. These functions still rely on the initial setup of the board as described above having been completed successfully. These two functions will now be described in more detail...

    GetCurrentStatus
    data=[8]
    dev.write(2, data)

       These two lines of code send a message to the StepperBee in exactly the same way as the previous but this time the data is simply the number '8'.  This tells the StepperBee to read its current status and make that available to be read across the USB interface by a subsequent command.  The command that actually reads this data from the StepperBee is next....

     status = dev.read(0x81, 6)
        The status data, made ready by the previous code, is now read by this statement. It is very similar to the "write" statement shown earlier. The 0x81 is just a hexadecimal number and corresponds to the internal USB buffer (or endpoint) associated with USB reads. It is always set to 0x81 for StepperBee reads.  The number '6' is the number of bytes of data to read from the StepperBee .  The variable which we have called "status" will then hold the returned data.  i.e. "status" is a Python array with individual elements holding the returned 6 bytes of data. These bytes of data will now be described.

    status[0]
        8 bit byte where bit0 and bit2 correspond to the current state of the two motors. Logic '1' indicates "running" and '0' indicates "stopped".

    status[1] and status[2]
        These hold the number of steps remaining to be executed by motor 1 in the form of least significant and most significant bytes of a two byte number (respectively) exactly as described earlier for stepsLSB and stepsMSB.  i.e. steps remaining = status[1] + (status[2]-1) x 128

    status[3] and status[4]
        These hold the steps remaining for motor 2 (the format is exactly the same as described above)

    status[5]
        8 bit byte where bits 0,1,2,6 and 7 and correspond to the current state of the 5 digital inputs respectively.

    For example....

    # read and display the current status data
        data=[8]
        dev.write(2,data)
        status=dev.read(0x81, 6)
        print status

    SetStepMode
    mode = 0b00000000
    data=[16, mode]
    dev.write(2,data)

        These three lines of code send a message to the StepperBee with a message number of  '16' which tells the StepperBee to use the "mode" data supplied.  The mode data is a single 8 bit byte with individual bits corresponding to the setup required as shown below...

    Bit Meaning when '0' meaning when '1'
    0 motor 1 wavestep mode motor 1 full step mode
    1 motor 2 wavestep mode motor 2 full step mode
    2 motor 1 normal (active) motor 1 power off
    3 motor 2 normal (active) motor 2 power off
    4 -7
    not used
       

    For example:  set motor 1 to full step mode and motor 2 to power off..
        mode = 0b00001001
        data=[16, mode]
        dev.write(2,data)

     

      Disclaimer:   Please note that the above code and descriptions are designed to help our customers use our boards with the Raspberry Pi. We offer no warranty or guarantees to the suitability of the code for your application. We are also unable to enter into discussions about any errors your code may have and will not, under any curcumstances, attempt to look for programming errors in code sent to us. This applies equally to Python, PyUSB, LibUSB. Linux (all distros) and any Raspberry Pi specifics.

       
    Raspberry Pi is a trademark of the Raspberry Pi Foundation

     

     

     

    13366  

    Featured
    Items

     
    Just Text:
    New Software
    for the MotorBee



    ConText
    Control by Text


    Security Camera:
    A new article
    by Brian M



    Microscope Control:
    A new article
    by Harald K. A.



     Use our boards with
    Raspberry Pi.


    Pi-Mobile:
    A new article
    by Ava L (UK)