コード例 #1
0
ファイル: test_device.py プロジェクト: bopopescu/meerkat
    def __init__(self, output='json'):

        # TODO: make safe for MicroPython, leave here for now in Conda
        from collections import deque
        from math import sin, pi

        from meerkat.data import CSVWriter, JSONWriter

        # data bus placeholder
        self.bus = None
        self.bus_addr = None

        # what kind of data output to file
        self.output = output

        # types of verbose printing
        self.verbose = False
        self.verbose_data = False

        # thread safe deque for sharing and plotting
        self.q_maxlen = 300
        self.q = deque(maxlen=self.q_maxlen)
        self.q_prefill_zeros = False

        # realtime/stream options
        self.go = False
        self.unlimited = False
        self.max_samples = 1000

        # information about this device
        self.device = DeviceData('Software Test')
        self.device.description = 'Dummy data for software testing'
        self.device.urls = None
        self.device.manufacturer = None
        self.device.version_hw = None
        self.device.version_sw = None
        self.device.accuracy = None
        self.device.precision = None
        self.device.bus = None
        self.device.state = 'Test Not Running'
        self.device.active = False
        self.device.error = None
        self.device.dtype = None
        self.device.calibration_date = None

        # data writer
        if self.output == 'csv':
            self.writer = CSVWriter('Software Test')
            #self.writer.device = self.device.values()
        elif self.output == 'json':
            self.writer = JSONWriter('Software Test')

        self.writer.header = ['index', 'degrees', 'amplitude']
        self.writer.device = self.device.values()

        # example data of one 360 degree, -1 to 1 sine wave
        self._deg = [n for n in range(360)]
        self._amp = [sin(d * (pi / 180.0)) for d in self._deg]
        self._test_data = list(zip(self._deg, self._amp))
コード例 #2
0
ファイル: motor.py プロジェクト: bopopescu/meerkat
    def __init__(self, bus_n, bus_addr=0x0F, output='csv'):

        # i2c bus
        self.bus = I2C(bus_n=bus_n, bus_addr=bus_addr)

        # PWM clock frequency
        self.frequency = 31372

        # speed can be -255 to 255
        self.motor_1_speed = 0
        self.motor_2_speed = 0

        # direction of DC motor
        self.direction = ""

        # driver mode, 'dc' or 'step'
        self.mode = "dc"

        # phase of the motor being used, only applies in stepper mode
        self.phase = None

        # step code initialize
        self.step_codes_cw = None
        self.step_codes_ccw = None

        # motor phase steps, default to 2 phase
        self.set_phase(phase=2)

        # number of steps commanded
        self.steps = 0

        # running total steps, for positioning microsteps
        self.step_count = 0

        # information about this device
        self.device = DeviceData('Grove Motor Driver')
        self.device.description = ('I2C DC and stepper motor controller')
        self.device.urls = 'http://wiki.seeedstudio.com/Grove-I2C_Motor_Driver_V1.3/'
        self.device.active = None
        self.device.error = None
        self.device.bus = repr(self.bus)
        self.device.manufacturer = 'Seeed Studio'
        self.device.version_hw = '1.3'
        self.device.version_sw = '1.0'
        self.device.accuracy = None
        self.device.precision = '1 microstep'
        self.device.calibration_date = None

        # data recording method
        self.writer_output = output
        self.csv_writer = CSVWriter(self.device.name, time_format='std_time_ms')
        self.csv_writer.device = self.device.values()
        self.csv_writer.header = ['description', 'freq',
                                  'm1_speed', 'm2_speed', 'm_direction',
                                  'mode', 'phase', 'steps']

        self.json_writer = JSONWriter(self.device.name, time_format='std_time_ms')
        self.json_writer.device = self.device.values()
        self.json_writer.header = self.csv_writer.header
コード例 #3
0
ファイル: relay.py プロジェクト: bopopescu/meerkat
    def __init__(self, bus_n, bus_addr=0x18, output='csv'):

        # i2c bus
        self.bus = I2C(bus_n=bus_n, bus_addr=bus_addr)

        self.state_mapper = {0: "closed", 1: "open"}

        # information about this device
        self.device = DeviceData("Qwiic Relay")
        self.device.description = ("Sparkfun Single Pole Double Throw Relay")
        self.device.urls = "https://learn.sparkfun.com/tutorials/qwiic-single-relay-hookup-guide/all"
        self.device.active = None
        self.device.error = None
        self.device.bus = repr(self.bus)
        self.device.manufacturer = "Sparkfun"
        self.device.version_hw = "1"
        self.device.version_sw = "1"

        self.application = "test"

        del self.device.accuracy
        del self.device.precision
        del self.device.dtype

        # data recording method

        self.writer_output = output
        self.csv_writer = CSVWriter("Qwiic Relay", time_format='std_time_ms')
        self.csv_writer.device = self.device.__dict__
        self.csv_writer.header = ["sample_id", "state"]

        self.json_writer = JSONWriter("Qwiic Relay", time_format='std_time_ms')
        self.json_writer.device = self.device.__dict__
        self.json_writer.header = ["sample_id", "state"]
コード例 #4
0
    def __init__(self, bus_n, bus_addr, output='csv'):
        """Initialize worker device on i2c bus.

        Parameters
        ----------
        bus_n : int, i2c bus number on Controller
        bus_addr : int, i2c bus number of this Worker device
        """

        # i2c bus
        self.bus = I2C(bus_n=bus_n, bus_addr=bus_addr)


        # time to wait for conversions to finish
        self.short_delay   = 0.3  # seconds for regular commands
        self.long_delay    = 1.5  # seconds for readings
        self.cal_delay     = 3.0  # seconds for calibrations

        # information about this device
        self.device = DeviceData('Atlas_Base')
        self.device.description = ('')
        self.device.urls = 'www.atlas-scientific.com'
        self.device.active = None
        self.device.error = None
        self.device.bus = repr(self.bus)
        self.device.manufacturer = 'Atlas Scientific'
        self.device.version_hw = '1.0'
        self.device.version_sw = '1.0'
        self.device.accuracy = None
        self.device.precision = 'Varies'
        self.device.calibration_date = None

        """
        # data recording method
        if output == 'csv':
            self.writer = CSVWriter('Atlas_Base', time_format='std_time_ms')

        elif output == 'json':
            self.writer = JSONWriter('Atlas_Base', time_format='std_time_ms')
        else:
            pass  # holder for another writer or change in default
        self.writer.header = ['description', 'sample_n', 'not_set']
        self.writer.device = self.device.values()
        """

        # data recording information
        self.sample_id = None

        # data recording method
        self.writer_output = output
        self.csv_writer = CSVWriter("Atlas_Base", time_format='std_time_ms')
        self.csv_writer.device = self.device.__dict__
        self.csv_writer.header = ['description', 'sample_n', 'not_set']

        self.json_writer = JSONWriter("Atlas_Base", time_format='std_time_ms')
        self.json_writer.device = self.device.__dict__
        self.json_writer.header = self.csv_writer.header
コード例 #5
0
ファイル: mpu6050.py プロジェクト: bopopescu/meerkat
    def __init__(self, bus_n, bus_addr=0x68, output='csv'):

        # i2c bus
        self.bus = I2C(bus_n=bus_n, bus_addr=bus_addr)

        # Wake up the MPU-6050 since it starts in sleep mode
        # by toggling bit6 from 1 to 0, see pg 40 of RM-MPU-6000A-00 v4.2
        self.bus.write_register_8bit(self.PWR_MGMT_1, 0x00)

        # information about this device
        self.device = DeviceData('MPU-6050')
        self.device.description = ('TDK InvenSense Gyro & Accelerometer')
        self.device.urls = 'https://www.invensense.com/products/motion-tracking/6-axis/mpu-6050/'
        self.device.active = None
        self.device.error = None
        self.device.bus = repr(self.bus)
        self.device.manufacturer = 'TDK'
        self.device.version_hw = '0.1'
        self.device.version_sw = '0.1'
        self.device.gyro_accuracy = '+/-3%, +/-2% cross axis'
        self.device.gyro_precision = '16bit'
        self.device.gyro_noise = '0.05 deg/s-rms'
        self.device.accel_accuracy = '+/-0.5%, +/-2 cross axis'
        self.device.accel_precision = '16bit'
        self.device.accel_noise = 'PSD 400 ug / Hz**1/2'
        self.device.calibration_date = None
        '''
        # data recording method
        if output == 'csv':
            self.writer = CSVWriter('MPU-6050', time_format='std_time_ms')
            self.writer.header = ['description', 'sample_n', 'arange', 'grange',
                                  'ax', 'ay', 'az', 'gx', 'gy', 'gz', 'temp_C']
        elif output == 'json':
            self.writer = JSONWriter('MPU-6050', time_format='std_time_ms')
        else:
            pass  # holder for another writer or change in default
        self.writer.device = self.device.values()
        '''

        # data recording information
        self.sample_id = None

        # data recording method
        self.writer_output = output
        self.csv_writer = CSVWriter("MPU-6050", time_format='std_time_ms')
        self.csv_writer.device = self.device.__dict__
        self.csv_writer.header = [
            'description', 'sample_n', 'ax', 'ay', 'az', 'gx', 'gy', 'gz'
        ]

        self.json_writer = JSONWriter("MCP9808", time_format='std_time_ms')
        self.json_writer.device = self.device.__dict__
        self.json_writer.header = self.csv_writer.header
コード例 #6
0
    def __init__(self, bus_n, bus_addr=0x18, output='csv'):
        """Initialize worker device on i2c bus.

        Parameters
        ----------
        bus_n : int, i2c bus number on Controller
        bus_addr : int, i2c bus number of this Worker device
        """

        # i2c bus
        self.bus = I2C(bus_n=bus_n, bus_addr=bus_addr)

        # register values and defaults
        # TODO: do the constant values need to be specified?
        self.reg_map = {
            'config': REG_CONFIG,
            'upper_temp': REG_UPPER_TEMP,
            'lower_temp': REG_LOWER_TEMP,
            'crit_temp': REG_CRIT_TEMP,
            'ambient': REG_AMBIENT_TEMP,
            'manufacturer': REG_MANUF_ID,
            'device_id': REG_DEVICE_ID
        }

        self.alert_critial = None
        self.alert_upper = None
        self.alert_lower = None

        self.manufacturer_id = None
        self.device_id = None
        self.revision = None

        # information about this device
        self.device = DeviceData('MCP9808')
        self.device.description = (
            '+/-0.5 degrees Celcius ' +
            'maximum accuracy digital temperature sensor')
        self.device.urls = 'https://www.microchip.com/datasheet/MCP9808'
        self.device.active = None
        self.device.error = None
        self.device.bus = repr(self.bus)
        self.device.manufacturer = 'Microchip'
        self.device.version_hw = '0.1'
        self.device.version_sw = '0.1'
        self.device.accuracy = '+/-0.25 (typical) C'
        self.device.precision = '0.0625 C maximum'
        self.device.units = 'Degrees Celcius'
        self.device.calibration_date = None

        # data recording information
        self.sample_id = None

        # data recording method
        self.writer_output = output
        self.csv_writer = CSVWriter("MCP9808", time_format='std_time_ms')
        self.csv_writer.device = self.device.__dict__
        self.csv_writer.header = ['description', 'sample_n', 'temperature']

        self.json_writer = JSONWriter("MCP9808", time_format='std_time_ms')
        self.json_writer.device = self.device.__dict__
        self.json_writer.header = ['description', 'sample_n', 'temperature']
コード例 #7
0
ファイル: test_device.py プロジェクト: bopopescu/meerkat
class TestDevice(Base):
    """Non-hardware test class"""
    def __init__(self, output='json'):

        # TODO: make safe for MicroPython, leave here for now in Conda
        from collections import deque
        from math import sin, pi

        from meerkat.data import CSVWriter, JSONWriter

        # data bus placeholder
        self.bus = None
        self.bus_addr = None

        # what kind of data output to file
        self.output = output

        # types of verbose printing
        self.verbose = False
        self.verbose_data = False

        # thread safe deque for sharing and plotting
        self.q_maxlen = 300
        self.q = deque(maxlen=self.q_maxlen)
        self.q_prefill_zeros = False

        # realtime/stream options
        self.go = False
        self.unlimited = False
        self.max_samples = 1000

        # information about this device
        self.device = DeviceData('Software Test')
        self.device.description = 'Dummy data for software testing'
        self.device.urls = None
        self.device.manufacturer = None
        self.device.version_hw = None
        self.device.version_sw = None
        self.device.accuracy = None
        self.device.precision = None
        self.device.bus = None
        self.device.state = 'Test Not Running'
        self.device.active = False
        self.device.error = None
        self.device.dtype = None
        self.device.calibration_date = None

        # data writer
        if self.output == 'csv':
            self.writer = CSVWriter('Software Test')
            #self.writer.device = self.device.values()
        elif self.output == 'json':
            self.writer = JSONWriter('Software Test')

        self.writer.header = ['index', 'degrees', 'amplitude']
        self.writer.device = self.device.values()

        # example data of one 360 degree, -1 to 1 sine wave
        self._deg = [n for n in range(360)]
        self._amp = [sin(d * (pi / 180.0)) for d in self._deg]
        self._test_data = list(zip(self._deg, self._amp))

    @staticmethod
    def _cycle(iterable):
        """Copied from Python 3.7 itertools.cycle example"""
        saved = []
        for element in iterable:
            yield element
            saved.append(element)
        while saved:
            for element in saved:
                yield element

    def run(self, delay=0, index='count'):
        """Run data collection"""

        # TODO: make safe for MicroPython, leave here for now in Conda
        from time import sleep, time, ctime

        if self.verbose:
            print('Test Started')

        # used in non-unlimited acquisition
        count = 0

        self.q.clear()

        if self.q_prefill_zeros:
            for _ in range(self.q_maxlen):
                self.q.append((0, 0))

        if index == 'time':

            def get_index():
                return time()
        elif index == 'ctime':

            def get_index():
                return ctime()
        else:

            def get_index():
                return count

        for d, a in self._cycle(self._test_data):

            if not self.go:
                if self.verbose:
                    print('Test Stopped')
                break

            self.device.state = 'Test run() method'

            i = get_index()

            data = [i, d, a]

            if self.output is not None:
                self.writer.write(data)

            q_out = self.writer.stream(data)
            self.q.append(q_out)

            if self.verbose_data:
                print(q_out)

            if not self.unlimited:
                count += 1
                if count == self.max_samples:
                    self.go = False

            sleep(delay)
コード例 #8
0
ファイル: ads.py プロジェクト: bopopescu/meerkat
    def __init__(self, bus_n, bus_addr=0x48, output='csv'):
        """Initialize worker device on i2c bus.

        Parameters
        ----------
        bus_n : int, i2c bus number on Controller
        bus_addr : int, i2c bus number of this Worker device
        """

        # i2c bus
        self.bus = I2C(bus_n=bus_n, bus_addr=bus_addr)

        # time to wait for conversion to finish
        self.delay = 0.009  # units = seconds

        # register values and defaults
        self.conversion_value = 40000  # higher than any conversion result
        self.config_value = None  # 0x8583 default
        self.lo_thres_value = None  # 0x8000 default
        self.hi_thres_value = None  # 0x7fff default

        self.reg_map = {
            'conversion': 0b00,
            'config': 0b01,
            'lo_thresh': 0b10,
            'hi_thresh': 0b11
        }

        # config register attributes and chip defaults
        self.comp_que_value = 0b11
        self.comp_lat_value = 0b0
        self.comp_pol_value = 0b0
        self.comp_mode_value = 0b0
        self.dr_value = 0b100
        self.mode_value = 0b1
        self.pga_value = 0b010
        self.mux_value = 0b000
        self.os_value = 0b0

        # voltage measurement
        self.pga_float = -999
        self.volts = -999

        # attribute converters
        self.str_mux = {
            '01': 0b000,
            '03': 0b001,
            '13': 0b010,
            '23': 0b011,
            '0G': 0b100,
            '1G': 0b101,
            '2G': 0b110,
            '3G': 0b111
        }
        self.bin_mux = {v: k for k, v in self.str_mux.items()}

        self.str_pga = {
            '6.144': 0b000,
            '4.096': 0b001,
            '2.048': 0b010,
            '1.024': 0b011,
            '0.512': 0b100,
            '0.256': 0b101
        }
        self.bin_pga = {v: float(k) for k, v in self.str_pga.items()}
        self.str_mode = {'continuous': 0b0, 'single': 0b1}
        self.bin_mode = {v: k for k, v in self.str_mode.items()}
        self.str_data_rate = {
            8: 0b000,
            16: 0b001,
            32: 0b010,
            64: 0b011,
            128: 0b100,
            250: 0b101,
            475: 0b110,
            860: 0b111
        }
        self.bin_data_rate = {v: k for k, v in self.str_data_rate.items()}
        self.str_comp_mode = {'trad': 0b0, 'window': 0b1}
        self.bin_comp_mode = {v: k for k, v in self.str_comp_mode.items()}
        self.str_comp_pol = {'1': 0b00, '2': 0b01, '3': 0b10, 'off': 0b11}
        self.bin_comp_pol = {v: k for k, v in self.str_comp_pol.items()}
        self.str_comp_lat = {'off': 0b0, 'on': 0b1}
        self.bin_comp_lat = {v: k for k, v in self.str_comp_lat.items()}
        self.str_comp_que = {'1': 0b00, '2': 0b01, '3': 0b10, 'off': 0b11}
        self.bin_comp_que = {v: k for k, v in self.str_comp_que.items()}

        # information about this device
        self.device = DeviceData('ADS1115')
        self.device.description = ('Texas Instruments 16-bit 860SPS' +
                                   ' 4-Ch Delta-Sigma ADC with PGA')
        self.device.urls = 'www.ti.com/product/ADS1115'
        self.device.active = None
        self.device.error = None
        self.device.bus = repr(self.bus)
        self.device.manufacturer = 'Texas Instruments'
        self.device.version_hw = '1.0'
        self.device.version_sw = '1.0'
        self.device.accuracy = None
        self.device.precision = '16bit'
        self.device.calibration_date = None

        # current settings of this device
        self.device.pga_gain = self.pga_float
        '''
        # data recording method
        if output == 'csv':
            self.writer = CSVWriter('ADS1115', time_format='std_time_ms')
            self.writer.header = ['description', 'sample_n', 'mux', 'voltage']
        elif output == 'json':
            self.writer = JSONWriter('ADS1115', time_format='std_time_ms')
        else:
            pass  # holder for another writer or change in default
        self.writer.device = self.device.values()

        # data recording information
        self.sample_id = None
        '''

        # data recording information
        self.sample_id = None

        # data recording method
        self.writer_output = output
        self.csv_writer = CSVWriter("ADS1115", time_format='std_time_ms')
        self.csv_writer.device = self.device.__dict__
        self.csv_writer.header = ['description', 'sample_n', 'mux', 'voltage']

        self.json_writer = JSONWriter("ADS1115", time_format='std_time_ms')
        self.json_writer.device = self.device.__dict__
        self.json_writer.header = self.csv_writer.header

        # initialize class attributes from device registry
        self.get_config()
コード例 #9
0
ファイル: motor.py プロジェクト: bopopescu/meerkat
class GroveMotor:

    def __init__(self, bus_n, bus_addr=0x0F, output='csv'):

        # i2c bus
        self.bus = I2C(bus_n=bus_n, bus_addr=bus_addr)

        # PWM clock frequency
        self.frequency = 31372

        # speed can be -255 to 255
        self.motor_1_speed = 0
        self.motor_2_speed = 0

        # direction of DC motor
        self.direction = ""

        # driver mode, 'dc' or 'step'
        self.mode = "dc"

        # phase of the motor being used, only applies in stepper mode
        self.phase = None

        # step code initialize
        self.step_codes_cw = None
        self.step_codes_ccw = None

        # motor phase steps, default to 2 phase
        self.set_phase(phase=2)

        # number of steps commanded
        self.steps = 0

        # running total steps, for positioning microsteps
        self.step_count = 0

        # information about this device
        self.device = DeviceData('Grove Motor Driver')
        self.device.description = ('I2C DC and stepper motor controller')
        self.device.urls = 'http://wiki.seeedstudio.com/Grove-I2C_Motor_Driver_V1.3/'
        self.device.active = None
        self.device.error = None
        self.device.bus = repr(self.bus)
        self.device.manufacturer = 'Seeed Studio'
        self.device.version_hw = '1.3'
        self.device.version_sw = '1.0'
        self.device.accuracy = None
        self.device.precision = '1 microstep'
        self.device.calibration_date = None

        # data recording method
        self.writer_output = output
        self.csv_writer = CSVWriter(self.device.name, time_format='std_time_ms')
        self.csv_writer.device = self.device.values()
        self.csv_writer.header = ['description', 'freq',
                                  'm1_speed', 'm2_speed', 'm_direction',
                                  'mode', 'phase', 'steps']

        self.json_writer = JSONWriter(self.device.name, time_format='std_time_ms')
        self.json_writer.device = self.device.values()
        self.json_writer.header = self.csv_writer.header

    def get_info(self):
        pid = self.bus.read_register_16bit(0x00)
        return pid

    def set_phase(self, phase=2):
        """Set the phase of the stepper motor being used.
        Defaults to a 2 phase.

        Parameters
        ----------
        phase : int, either 2 or 4 for the phase of the motor design
        """

        if phase == 4:
            # 4 phase motor
            self.step_codes_cw  = [0b0001, 0b0011, 0b0010, 0b0110,
                                   0b0100, 0b1100, 0b1000, 0b1001]
            self.step_codes_ccw = [0b1000, 0b1100, 0b0100, 0b0110,
                                   0b0010, 0b0011, 0b0001, 0b1001]
            self.phase = 4
        else:
            # default to 2 phase motor
            self.step_codes_cw  = [0b0001, 0b0101, 0b0100, 0b0110,
                                   0b0010, 0b1010, 0b1000, 0b1001]
            self.step_codes_ccw = [0b1000, 0b1010, 0b0010, 0b0110,
                                   0b0100, 0b0101, 0b0001, 0b1001]
            self.phase = 2

    def set_frequency(self, f_Hz=31372):
        """Set the frequency of the PWM cycle where
            cycle length = 510
            system_clock = 16MHz

        Available frequencies in Hz: 31372, 3921, 490, 122, 30

        Parameters
        ----------
        f_Hz : int, frequencey in Hertz (Hz).  Default is 31372
        """
        freq_mapper = {31372: 0x01, 3921: 0x02, 490: 0x03, 122: 0x04, 30: 0x05}
        self.frequency = freq_mapper[f_Hz]
        self.bus.write_n_bytes([0x84, self.frequency, 0x01])

    def set_speed(self, motor_id, motor_speed):
        """Set the speed (duty cycle) of motor

        Parameters
        ----------
        motor_id : int, either 1 or 2 where 1 = J1 and 2 = J5 on the board
        motor_speed : int, between -255 and 255 where > 0 is clockwise
        """
        assert (motor_speed > -256) & (motor_speed < 256)
        if motor_id == 1:
            self.motor_1_speed = motor_speed
        if motor_id == 2:
            self.motor_2_speed = motor_speed

        self.bus.write_n_bytes([0x82, self.motor_1_speed, self.motor_2_speed])

    def stop(self, motor_id=None):
        """Stop one or both motors.  Alias for set_speed(motor_id, motor_speed=0).

        Parameters
        ----------
        motor_id : int, (optional) 1 or 2 where 1 = J1 and 2 = J5 on the board.
            If not set, defaults to stopping both.
        """

        if (motor_id == 1) or (motor_id == 2):
            self.set_speed(motor_id=motor_id, motor_speed=0)
        else:
            self.set_speed(motor_id=1, motor_speed=0)
            self.set_speed(motor_id=2, motor_speed=0)

    def set_direction(self, code='cw'):
        """Set the direction of one or both motors in dc mode.

        Accepted string command codes are:
            'cw' : clockwise
            'ccw' : counter clockwise
            'm1m2cw' : motor 1 and motor 2 clockwise
            'm1m2cc' : motor 1 and motor 2 counter clockwise
            'm1cw_m2ccw' : motor 1 clockwise and motor 2 counter clockwise
            'm1ccw_m2cw' : motor 1 counter clockwise and motor 2 clockwise

        Parameters
        ----------
        code : str, command code, default is 'cw'
        """
        direction_mapper = {'cw': 0x0a, 'ccw': 0x05,
                            'm1m2cw': 0x0a, 'm1m2cc': 0x05,
                            'm1cw_m2ccw': 0x06, 'm1ccw_m2cw': 0x09}
        self.direction = direction_mapper[code]
        self.bus.write_n_bytes([0xaa, self.direction, 0x01])

    def set_mode(self, mode_type="dc"):
        if (mode_type == "full_step") or (mode_type == "micro_step"):
            self.set_speed(motor_id=1, motor_speed=255)
            self.set_speed(motor_id=2, motor_speed=255)
            self.mode = mode_type
        else:
            self.mode = "dc"

    def step_full(self, steps, delay=0.0001, verbose=False):
        """Stepper motor motion in full steps
        (four steps per step commanded)

        Parameters
        ----------
        steps : int, number of motor steps where
            positive numbers are clockwise
            negative numbers are counter clockwise
        delay : float, seconds to delay between step commands,
            default is 0.0001 seconds which smooths operation on the pi
        verbose : bool, print debug statements
        """

        self.steps = steps

        if steps > 0:
            step_codes = self.step_codes_cw
            self.direction = "step_cw"
        if steps < 0:
            step_codes = self.step_codes_ccw
            self.direction = "step_ccw"
        if steps == 0:
            self.stop()
            return

        self.set_mode(mode_type="full_step")  # set speed to 255, i.e. full current

        for _ in range(abs(steps)):
            for sc in step_codes:
                if verbose: print("{0:04b}".format(sc))
                self.bus.write_n_bytes([0xaa, sc, 0x01])
                time.sleep(delay)

        self.stop()  # set speed to 0, i.e. current off

    def step_micro(self, steps, delay=0.0001, verbose=False):
        """Stepper motor motion in micro steps
        (one step per step commanded)

        Parameters
        ----------
        steps : int, number of motor steps where
            positive numbers are clockwise
            negative numbers are counter clockwise
        delay : float, seconds to delay between step commands,
            default is 0.0001 seconds which smooths operation on the pi
        verbose : bool, print debug statements
        """

        self.steps = steps

        if steps > 0:
            step_codes = self.step_codes_cw
            self.direction = "step_cw"
        if steps < 0:
            step_codes = self.step_codes_ccw
            self.direction = "step_ccw"
        if steps == 0:
            self.stop()
            return

        self.set_mode(mode_type="micro_step")  # set speed to 255, i.e. full current

        for _ in range(abs(steps)):
            if verbose: print("n >>", _)
            ix = self.step_count * 2
            if verbose: print("ix >> ", ix)
            for sc in step_codes[ix:ix + 2]:
                if verbose: print("bin >> {0:04b}".format(sc))
                self.bus.write_n_bytes([0xaa, sc, 0x01])
                time.sleep(delay)
            self.step_count = (self.step_count + 1) % 4

        self.stop()  # set speed to 0, i.e. current off

    def get(self, description='no_description'):
        """Get formatted output.

        Parameters
        ----------
        description : char, description of data sample collected

        Returns
        -------
        data : list, data that will be saved to disk with self.write containing:
            description : str
        """
        return [description, self.frequency,
                self.motor_1_speed, self.motor_2_speed,
                self.direction, self.mode,
                self.phase, self.steps]

    def publish(self, description='no_description'):
        """Format output and save to file, formatted as either .csv or .json.

        Parameters
        ----------
        description : char, description of data sample collected

        Returns
        -------
        None, writes to disk the following data:
            description : str, description of sample
        """
        return self.json_writer.publish(self.get(description=description))

    def write(self, description='no_description'):
        """Format output and save to file, formatted as either .csv or .json.

        Parameters
        ----------
        description : char, description of data sample collected

        Returns
        -------
        None, writes to disk the following data:
            description : str, description of sample
        """
        wr = {"csv": self.csv_writer,
              "json": self.json_writer}[self.writer_output]
        wr.write(self.get(description=description))