Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 

    Python based sensor evaluation script using APP2.0

    100% helpful (3/3)

    Purpose

    This document describes the steps that need to be undertaken to setup a running python environment (at the moment limited to Windows systems), with which sensors from Bosch Sensortec can be read out using the Application Board APP2.0 and the shuttle boards.

    Overview

    The Application Board APP2.0 runs a firmware that allows connecting to it via USB and interface to a host PC. APP2.0 mainly serves as a protocol translator (like usb to i2c/spi) and has a dedicated streaming functionality for accurate sensor readout using the real-time capabilities of the MCU on the APP2.0.

    On PC side, Bosch Sensortec provides a library for convenient access of the board using C# or python.

    Requirements and material

    Installation

    Windows Platform

    Assumption: the computer has a recent firefox web browser installed and has direct access to the internet. Furthermore, admin rights are required.

    1. Upgrade pip
    2. Install pip:
      conda install pip
    3. After installing the environment, it needs to be activated:
      activate my35env
    4. Create virtual environment (this is to prevent any issues with anaconda python and non-conda installed packages. For example name your virtual environment "my35env" with the command:
      conda create -n my35env anaconda python=3.5
      Note: the script should also work with other 3.x versions of python. However, using version 3.5 enables to add guiqwt to a later moment, which may be a required module for displaying sensor data in a GUI format.

    5. Run cmd.exe as admin
    6. Install the Anaconda python environment
    7. Install the Development Desktop 2.0 on the PC.
      The library UserApplicationBoard.dll that is required to access the APP2.0 can be found in this folder:
      C:\Program Files\Bosch Sensortec\Development Desktop 2.0\UserpApplicationBoard
      1. direct internet access: pip install --upgrade pip
      2. direct internet access: pip --proxy https://proxy.xyz.com:8080 install --upgrade pip
        Note: use the proxy settings for the rest of the commands as well if required
        Note: in some cases the proxy needs authentication, e.g. https://username:password@proxy.xyz.com:8080. In such a case, if the user uses special characters in his password, these characters must be written in html format, e.g. "%23" corresponds to the ASCII escape character of "#", details: https://www.ascii.cl/htmlcodes.htm
    8. Install pythonnet:
      pip install --pre pythonnet
    9. Copy the python script (see below) so some place

    Linux

    The board can also be interfaced using libusb, the required software is currently under development.

    Operation

    Based on the instructions and if the anaconda package is used, the following steps should be taken to run the script:

    1. Connect the APP2.0 to the PC, mount the shuttle board, switch the board on
    2. open cmd.exe
    3. Activate the environment, e.g.
      activate my35env
    4. Open the IDE spyder:
      spyder
    5. Open the script using the IDE
    6. Press the green triangle button (i.e. run the file)

     

    Code example

    # -*- coding: utf-8 -*-
    """
    ****************************************************************************
    * Copyright (C) 2018 Bosch Sensortec GmbH
    *
    * Created 15.12.2017
    * 
    * This script is intended to be used to check BMI085 using GenericAPI and
    * shuttle board on APP2.0.
    * 
    * Version changelog
    * =================
    * 0.9 (15.12.2017) 
    *  - Initial version based on previous sample scripts
    * 1.0 (18.12.2017) 
    *  - Released after testing, small code modifications
    *  - Test signal function does not work, reason unknown
    * 
    ****************************************************************************
    * BSD-3-Clause
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright
    *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in the
    *    documentation and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its
    *    contributors may be used to endorse or promote products derived from
    *    this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    * POSSIBILITY OF SUCH DAMAGE.
    **************************************************************************/ """ import sys import clr from time import sleep sys.path.append(r"C:\Program Files\Bosch Sensortec\Development Desktop 2.0\UserpApplicationBoard") # path of dll clr.AddReference("UserApplicationBoard") from System import Byte from System import UInt16 clr.AddReference('System.Collections') import numpy as np import BST # Pin descriptions and other constants PS_Gyro = 9 SCX = 6 SDX = 5 SDO = 4 BMI085_ShuttleID = 70 ACCEL_RANGE = 2 # BMI085: smallest Accel range is 2G (for BMI088 here would be 3G) GYRO_RANGE = 2000 # BMI08x: "standard" gyro range board = '' # This class contains the relevant information about the sensor. # In case of BMI08x, there are 2 class initializations neeeded, one # for accelerometer, the other one for the gyroscope. class Sensor: def __init__(self, sensor_ID, i2c_addr, interface, CSB, asic): self.sensor_ID = sensor_ID self.i2c_addr = i2c_addr self.interface = interface self.CSB = CSB self.asic = asic self.firstdatareg = 0 self.rangereg = 0 self.fullrange = 0 if asic == 'baa450': self.firstdatareg = 0x12 self.rangereg = 0x41 self.fullrange = ACCEL_RANGE if asic == 'bag160': self.firstdatareg = 0x02 self.rangereg = 0x0F self.fullrange = GYRO_RANGE def get_if_detail(self): if self.interface == 'spi': return self.CSB elif self.interface == 'i2c': return self.i2c_addr else: return -1 def set_if(self, interface): self.interface = interface # create single board instance over USB connection def bst_init_brd_app20(): global board board = BST.UserApplicationBoard() board.PCInterfaceConfig( BST.PCINTERFACE.USB ) # print board info bi = board.GetBoardInfo() print('BoardInfo: HW/SW ID: ' + str(bi.HardwareId) + '/' + \ str(bi.SoftwareId) + ', ShuttleID: ' + str(bi.ShuttleID)) if bi.HardwareId == 0: print('Seems like there is no board commincation. Stop') board.ClosePCInterface() sys.exit() # if bi.ShuttleID != BMI085_ShuttleID: # print('Seems like you are not using BMI085 shuttle board. Stop') # board.ClosePCInterface() # sys.exit() # Set SPI bus def brd_set_spi_if(sensor): board.PinConfig(SCX, BST.EONOFF.ON, BST.PINMODE.OUTPUT, BST.PINLEVEL.HIGH) board.PinConfig(SDX, BST.EONOFF.ON, BST.PINMODE.OUTPUT, BST.PINLEVEL.HIGH) board.PinConfig(SDO, BST.EONOFF.ON, BST.PINMODE.INPUT, BST.PINLEVEL.HIGH) board.SensorSPIConfig( Byte(sensor.sensor_ID), sensor.CSB, \ BST.SPISPEED.SPI1000KBIT, BST.SPIMODE.MODE0 ) board.PinConfig(sensor.CSB, BST.EONOFF.ON, BST.PINMODE.OUTPUT, \ BST.PINLEVEL.HIGH) if sensor.asic == 'bag160': board.PinConfig(PS_Gyro, BST.EONOFF.ON, BST.PINMODE.OUTPUT, \ BST.PINLEVEL.LOW) # ic2 select # Set I2C bus def brd_set_i2c_if(sensor): # selecz ic2 addr board.PinConfig(SDO, BST.EONOFF.ON, BST.PINMODE.OUTPUT, BST.PINLEVEL.LOW) board.PinConfig(sensor.CSB, BST.EONOFF.OFF, BST.PINMODE.INPUT, \ BST.PINLEVEL.LOW) if sensor.asic == 'bag160': # selecz ic2 mode board.PinConfig(PS_Gyro, BST.EONOFF.ON, BST.PINMODE.OUTPUT, \ BST.PINLEVEL.HIGH) board.SensorI2CConfig( Byte(sensor.sensor_ID), UInt16(sensor.i2c_addr), \ BST.I2CSPEED.STANDARDMODE) # Power up sequence fo the sensors def power_up(sensor): if sensor.asic == 'baa450': # Wait times according to datasheet sleep(.001) board.Write(0x7D, 4, sensor.get_if_detail()) # write 4 to ACC_PWR_CTRL board.Write(0x7C, 0, sensor.get_if_detail()) # Clear ACC_PWR_CONF sleep(.05) if sensor.asic == 'bag160': brd_write(sensor, 0x11, [0]) pwr = brd_read(sensor, 0x11, 1) print(pwr) # Function to read from the previous selected bus def brd_read(sensor, reg, range): # Consider the dummy byte if (sensor.asic == 'baa450') and (sensor.get_if_detail() == sensor.CSB): range += 1 data = board.Read(reg & 0x7F, UInt16(range), sensor.get_if_detail()) data = [int(i) for i in data] # data is in Int32[] format if (sensor.asic == 'baa450') and (sensor.get_if_detail() == sensor.CSB): data.pop(0) return data # Function to write on the previous selected bus def brd_write(sensor, reg, data): return board.Write(reg & 0x7F, data, sensor.get_if_detail()) # Calculate 2's complement out of given uint value def twos_comp(val, bits): """compute the 2's complement of int value val""" if (val & (1 << (bits - 1))) != 0: # if sign bit is set e.g., 8bit: 128-255 val = val - (1 << bits) # compute negative value return val # return positive value as is # This function reads a number of samples, calculates the average and the # standard deviation and outputs the result to the user def read_sensor_values_3D(sensor, num_of_samples = 25, delay_in_ms = 0): x = [] y = [] z = [] # Read in number of samples while(num_of_samples > 0): data = brd_read(sensor, sensor.firstdatareg, 6) x.append(twos_comp(data[1] * 256 + data[0], 16)) y.append(twos_comp(data[3] * 256 + data[2], 16)) z.append(twos_comp(data[5] * 256 + data[4], 16)) sleep(delay_in_ms) num_of_samples -= 1 return ([np.mean(x), np.mean(y), np.mean(z), np.std(x), np.std(y), np.std(z)]) # This function converts LSB to pyhsical measure (e.g G for accel or # dps for gyro) def convert_lsb_2_phys(sensor, data): sensrange = brd_read(sensor, sensor.rangereg, 1) print('Range is set to : ' + str(sensrange[0])) result = [] for d in data: result.append(d/32768. * sensor.fullrange * 2 ** (sensrange[0])) return result def read_temp_sensor_baa450(sensor): if sensor.asic == 'baa450': data = brd_read(sensor, 0x22, 2) return(twos_comp(data[0] * 8 + (data[1] >> 5), 11) * 0.125 + 23) # This function is not yet working reliably at the moment! (refers to V1.0) def trigger_selftest(sensor): if sensor.asic == 'baa450': # Set 16G measurement range brd_write(sensor, 0x41, 3) # Set ODR 1.6kHz, normal mode: brd_write(sensor, 0x40, 0xA7) # Wait 2ms (see datasheet) sleep(.003) print('-> Enabling positive selftest signal') brd_write(sensor, 0x6D, 0x0D) # Wait >50ms (see datasheet) sleep(0.051) data = read_sensor_values_3D(bmi08x_accel) data = convert_lsb_2_phys(bmi08x_accel, data) print(data) print('-> Enabling negative selftest signal') brd_write(sensor, 0x6D, 0x09) sleep(.1) data = read_sensor_values_3D(bmi08x_accel) data = convert_lsb_2_phys(bmi08x_accel, data) print(data) brd_write(sensor, 0x6D, 0x00) sleep(.1) # ############################################################################ # Main routine. if __name__ == "__main__": bst_init_brd_app20() try: # ##### SPI section ##### myif = 'spi' print('\n +++ Interface: ' + myif + ' +++') bmi08x_accel = Sensor(0x1F, 0x18, myif, 8, 'baa450') bmi08x_gyro = Sensor(0x0F, 0x68, myif, 14, 'bag160') board.SetVDD(0) board.SetVDDIO(0) brd_set_spi_if(bmi08x_gyro) brd_set_spi_if(bmi08x_accel) board.SetVDD(3.3) board.SetVDDIO(3.3) # Read chip-ID 2x for accelerometer to switch to spi mode chipid = brd_read(bmi08x_accel, 0, 1) # Read chip id chipid = brd_read(bmi08x_accel, 0, 1) print ('Chip ID accel: ' + str(chipid[0])) chipid = brd_read(bmi08x_gyro, 0, 1) print ('Chip ID gyro: ' + str(chipid[0])) board.SetVDD(0) board.SetVDDIO(0) # ##### I2C section ##### myif = 'i2c' print('\n +++ Interface: ' + myif + ' +++') bmi08x_accel = Sensor(0x1F, 0x18, myif, 8, 'baa450') bmi08x_gyro = Sensor(0x0F, 0x68, myif, 14, 'bag160') brd_set_i2c_if(bmi08x_accel) brd_set_i2c_if(bmi08x_gyro) board.SetVDD(3.3) board.SetVDDIO(3.3) # Read chip id chipid = brd_read(bmi08x_accel, 0, 1) print ('Chip ID accel: ' + str(chipid[0])) chipid = brd_read(bmi08x_gyro, 0, 1) print ('Chip ID gyro: ' + str(chipid[0])) # Read accel data power_up(bmi08x_accel) data = read_sensor_values_3D(bmi08x_accel) data = convert_lsb_2_phys(bmi08x_accel, data) print ('Accel x [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data[0] * 1000, data[3] * 1000)) print ('Accel y [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data[1] * 1000, data[4] * 1000)) print ('Accel z [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data[2] * 1000, data[5] * 1000)) # Read gyro data data = read_sensor_values_3D(bmi08x_gyro) data = convert_lsb_2_phys(bmi08x_gyro, data) print ('Gyro x [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data[0], data[3])) print ('Gyro y [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data[1], data[4])) print ('Gyro z [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data[2], data[5])) # Read temperature data data = read_temp_sensor_baa450(bmi08x_accel) print ('Temperature [degC]: %.2f' % data) # Trigger selftest not yet working for unknown reason, not a sensor, # but obvious a python/toolchain issue #trigger_selftest(bmi08x_accel) except Exception as e: print('Fehler: ' + str(e)) board.SetVDD(0) board.SetVDDIO(0) board.ClosePCInterface(
    Version history
    Revision #:
    3 of 3
    Last update:
    ‎06-19-2020 11:54 AM
    Updated by:
     
    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist