├── README.md ├── peripherals ├── bmp085.php ├── i2c_bus.php ├── lsm303_accelerometer.php └── lsm303_magnetometer.php ├── test_accelerometer.php ├── test_bmp085.php └── test_magnetometer.php /README.md: -------------------------------------------------------------------------------- 1 | TBJs Raspberry Pi PHP Tools 2 | =========================== 3 | - php software to interface a raspberry pi with various board level peripherals 4 | 5 | 6 | problems, bugs, and dev notes 7 | ----------------------------- 8 | - not sure how to trigger the accelerometer to start producing data. i currently need to trigger it with a third party c app ( ../LSM303DLHC/LSM303 ). 9 | 10 | 11 | notes about using this library 12 | ------------------------------ 13 | - applications need to be run as root to access the i2c bus 14 | 15 | 16 | required libraries 17 | ------------------ 18 | 19 | ### i2c-tools for i2c bus communication 20 | - installation: http://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c 21 | - documentation: http://www.acmesystems.it/i2c 22 | 23 | 24 | suggested hardware used with this repository 25 | -------------------------------------------- 26 | 27 | ### Raspberry Pi Model B Revision 2.0 (512MB) 28 | - purchase: http://www.amazon.com/gp/product/B009SQQF9C/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B009SQQF9C&linkCode=as2&tag=induinteinc-20 29 | 30 | ### LSM303 Triple-axis Accelerometer & Magnetometer Board 31 | - purchase: http://www.adafruit.com/products/1120 32 | - datasheet: http://www.pololu.com/file/download/LSM303DLHC.pdf?file_id=0J564 33 | - project files 34 | - peripherals/lsm303_accelerometer.php 35 | - peripherals/lsm303_magnetometer.php 36 | 37 | 38 | ### BMP085 Barometric Pressure / Temperature / Altitude Sensor 39 | - purchase: http://www.adafruit.com/products/391 40 | - datasheet: http://www.adafruit.com/datasheets/BMP085_DataSheet_Rev.1.0_01July2008.pdf -------------------------------------------------------------------------------- /peripherals/bmp085.php: -------------------------------------------------------------------------------- 1 | I2c = new i2c_bus( self::i2c_address ); 67 | 68 | // set operating mode ( don't know how to change on chip, so use default 'standard mode' ) 69 | $this->operating_mode = self::standard_mode; 70 | 71 | // get calibration data 72 | $this->read_calibration_data(); 73 | 74 | } 75 | 76 | 77 | // --- GETTERS -------------------------------------------------------------- 78 | 79 | 80 | // returns an array with temperature, pressure, and altitude 81 | // 82 | // - temperature is in celcius ( c ) 83 | // - pressure is in pascals ( Pa ) 84 | // - altitude is in meters ( m ) 85 | // 86 | public function get_readings() { 87 | 88 | // get data and make calculations 89 | $this->read_uncompensated_temperature(); 90 | $this->read_uncompensated_pressure(); 91 | $this->calculate_readings(); 92 | 93 | // return data in an array 94 | return array( 95 | 'temperature' => $this->t, 96 | 'pressure' => $this->p, 97 | 'altitude' => $this->a 98 | ); 99 | } 100 | 101 | 102 | // --- READERS -------------------------------------------------------------- 103 | 104 | 105 | private function read_calibration_data() 106 | { 107 | 108 | $this->ac1 = $this->I2c->read_signed_short( 0xaa ); 109 | $this->ac2 = $this->I2c->read_signed_short( 0xac ); 110 | $this->ac3 = $this->I2c->read_signed_short( 0xae ); 111 | $this->ac4 = $this->I2c->read_unsigned_short( 0xb0 ); 112 | $this->ac5 = $this->I2c->read_unsigned_short( 0xb2 ); 113 | $this->ac6 = $this->I2c->read_unsigned_short( 0xb4 ); 114 | $this->b1 = $this->I2c->read_signed_short( 0xb6 ); 115 | $this->b2 = $this->I2c->read_signed_short( 0xb8 ); 116 | $this->mb = $this->I2c->read_signed_short( 0xba ); 117 | $this->mc = $this->I2c->read_signed_short( 0xbc ); 118 | $this->md = $this->I2c->read_signed_short( 0xbe ); 119 | 120 | if( self::debug_mode ) { 121 | echo "\nac1: " . $this->ac1; 122 | echo "\nac2: " . $this->ac2; 123 | echo "\nac3: " . $this->ac3; 124 | echo "\nac4: " . $this->ac4; 125 | echo "\nac5: " . $this->ac5; 126 | echo "\nac6: " . $this->ac6; 127 | echo "\nb1: " . $this->b1; 128 | echo "\nb2: " . $this->b2; 129 | echo "\nmb: " . $this->mb; 130 | echo "\nmc: " . $this->mc; 131 | echo "\nmd: " . $this->md; 132 | } 133 | 134 | } 135 | 136 | private function read_uncompensated_temperature() { 137 | $this->I2c->write_register( 0xf4, 0x2e ); 138 | usleep( 4500 ); 139 | $this->ut = $this->I2c->read_unsigned_short( 0xf6 ); 140 | if( self::debug_mode ) 141 | echo "\nut: " . $this->ut; 142 | } 143 | 144 | private function read_uncompensated_pressure() { 145 | $this->I2c->write_register( 0xf4, 0x34 + ( $this->operating_mode << 6 ) ); 146 | usleep( 4500 ); 147 | $this->up = $this->I2c->read_unsigned_long( 0xf6 ) >> ( 8 - $this->operating_mode ); 148 | if( self::debug_mode ) 149 | echo "\nup: " . $this->up; 150 | } 151 | 152 | private function calculate_readings() { 153 | 154 | // set to true to use datasheet sample calibration data to test math operations 155 | if( false ) { 156 | $this->ac1 = 408; 157 | $this->ac2 = -72; 158 | $this->ac3 = -14383; 159 | $this->ac4 = 32741; 160 | $this->ac5 = 32757; 161 | $this->ac6 = 23153; 162 | $this->b1 = 6190; 163 | $this->b2 = 4; 164 | $this->mb = -32767; 165 | $this->mc = -8711; 166 | $this->md = 2868; 167 | $this->operating_mode = self::ultra_low_power_mode; 168 | $this->ut = 27898; 169 | $this->up = 23843; 170 | } 171 | 172 | // calculate true temperature 173 | $x1 = ( $this->ut - $this->ac6 ) * $this->ac5 >> 15; 174 | $x2 = ( $this->mc << 11 ) / ( $x1 + $this->md ); 175 | $b5 = $x1 + $x2; 176 | $this->t = ( $b5 + 8 ) >> 4; 177 | $this->t = $this->t * 0.1; // convert to celcius 178 | if( self::debug_mode ) { 179 | echo "\nx1: $x1"; 180 | echo "\nx2: $x2"; 181 | echo "\nb5: $b5"; 182 | echo "\nt: " . $this->t; 183 | } 184 | 185 | // calculate true pressure 186 | $b6 = $b5 - 4000; 187 | $x1 = ( $this->b2 * ( $b6 * $b6 ) >> 12 ) >> 11; 188 | $x2 = ( $this->ac2 * $b6 ) >> 11; 189 | $x3 = $x1 + $x2; 190 | $b3 = ( ( ( $this->ac1 * 4 + $x3 ) << $this->operating_mode ) + 2 ) / 4; 191 | if( self::debug_mode ) { 192 | echo "\nb6: $b6"; 193 | echo "\nx1: $x1"; 194 | echo "\nx2: $x2"; 195 | echo "\nx3: $x3"; 196 | echo "\nb3: $b3"; 197 | } 198 | $x1 = ( $this->ac3 * $b6 ) >> 13; 199 | $x2 = ( $this->b1 * ( ( $b6 * $b6 ) >> 12 ) ) >> 16; 200 | $x3 = ( ( $x1 + $x2 ) + 2 ) >> 2; 201 | $b4 = ( $this->ac4 * ( $x3 + 32768 ) ) >> 15; 202 | $b7 = ( $this->up - $b3 ) * ( 50000 >> $this->operating_mode ); 203 | if( $b7 < 0x80000000 ) 204 | $p = ( $b7 * 2 ) / $b4; 205 | else 206 | $p = ( $b7 / $b4 ) * 2; 207 | if( self::debug_mode ) { 208 | echo "\nx1: $x1"; 209 | echo "\nx2: $x2"; 210 | echo "\nx3: $x3"; 211 | echo "\nb4: $b4"; 212 | echo "\nb7: $b7"; 213 | echo "\np: $p"; 214 | } 215 | $x1 = ( $p >> 8 ) * ( $p >> 8 ); 216 | if( self::debug_mode ) 217 | echo "\nx1: $x1"; 218 | $x1 = ( $x1 * 3038 ) >> 16; 219 | $x2 = ( -7357 * $p ) >> 16; 220 | $this->p = $p + ( ( $x1 + $x2 + 3791 ) >> 4 ); 221 | if( self::debug_mode ) { 222 | echo "\nx1: $x1"; 223 | echo "\nx2: $x2"; 224 | echo "\np: " . $this->p; 225 | } 226 | 227 | // calculate altitude 228 | $this->a = 44330 * ( 1 - pow( ( $this->p / 101325 ), ( 0.1903 ) ) ); 229 | if( self::debug_mode ) 230 | echo "\na: " . $this->a; 231 | 232 | } 233 | 234 | } 235 | 236 | ?> -------------------------------------------------------------------------------- /peripherals/i2c_bus.php: -------------------------------------------------------------------------------- 1 | i2c_address = $i2c_address; 20 | 21 | ///$this->i2c = fopen( '/dev/i2c-' . $this->block, "w+b" ); 22 | 23 | /* // read 24 | $address = ($address | 0x01) << 8 & $registry; 25 | $i2c = fopen("/dev/i2c-2", "w+b"); 26 | fseek($i2c, $address) 27 | $rtn = fread($i2c, $length) 28 | fclose($i2c); 29 | 30 | // write to chip 31 | $address = ($address & 0xFE) << 8 & $registry; 32 | $i2c = fopen("/dev/i2c-2", "w+b"); 33 | fseek($i2c, $address) 34 | fwrite($i2c, $data, $length) 35 | fclose($i2c); 36 | */ 37 | 38 | } 39 | 40 | function __destruct() { 41 | //pclose( $this->i2c ); 42 | } 43 | 44 | 45 | // --- READERS -------------------------------------------------------------------- 46 | 47 | 48 | public function read_register( 49 | $register // register location ( eg. 0x29 ) 50 | ) { 51 | return trim( shell_exec( 'i2cget -y ' . $this->block . ' ' . $this->i2c_address . ' ' . $register ) ); 52 | } 53 | 54 | public function read_signed_short( 55 | $msb_register // most significant byte register location 56 | ) { 57 | $msb = intval( $this->read_register( $msb_register ), 16 ); 58 | $lsb = intval( $this->read_register( $msb_register + 1 ), 16 ); 59 | $val = ( $msb << 8 ) + $lsb; 60 | $array = unpack( 's', pack( 'v', $val ) ); 61 | $decimal_value = $array[1]; 62 | return $decimal_value; 63 | } 64 | 65 | public function read_unsigned_short( 66 | $msb_register // most significant byte register location 67 | ) { 68 | $msb = intval( $this->read_register( $msb_register ), 16 ); 69 | $lsb = intval( $this->read_register( $msb_register + 1 ), 16 ); 70 | $val = ( $msb << 8 ) + $lsb; 71 | $array = unpack( 'S', pack( 'v', $val ) ); 72 | $decimal_value = $array[1]; 73 | return $decimal_value; 74 | } 75 | 76 | public function read_unsigned_long( 77 | $msb_register // most significant byte register location 78 | ) { 79 | $msb = intval( $this->read_register( $msb_register ), 16 ); 80 | $lsb = intval( $this->read_register( $msb_register + 1 ), 16 ); 81 | $xlsb = intval( $this->read_register( $msb_register + 2 ), 16 ); 82 | $val = ( $msb << 16 ) + ( $lsb << 8 ) + $xlsb; 83 | $array = unpack( 'l', pack( 'V', $val ) ); 84 | $decimal_value = $array[1]; 85 | return $decimal_value; 86 | } 87 | 88 | 89 | // --- WRITERS -------------------------------------------------------------------- 90 | 91 | 92 | public function write_register( 93 | $register, // register address ( eg. 0x29 ) 94 | $value // value to set at register address ( must be a decimal value, eg. 10001001 should be passed as 95 | ) { 96 | shell_exec( 'i2cset -y ' . $this->block . ' ' . $this->i2c_address . ' ' . $register . ' ' . $value ); 97 | } 98 | 99 | 100 | } 101 | 102 | ?> 103 | -------------------------------------------------------------------------------- /peripherals/lsm303_accelerometer.php: -------------------------------------------------------------------------------- 1 | I2c = new i2c_bus( self::i2c_address ); 52 | 53 | } 54 | 55 | public function get_resolution() { 56 | 57 | // read settings from register 58 | $settings = str_pad( base_convert( $this->I2c->read_register( self::ctrl_reg4 ), 16, 2 ), 8, 0, STR_PAD_LEFT ); 59 | 60 | // get resolution bits and translate them 61 | $resolution = substr( $settings, 2, 2 ); 62 | if( $resolution == '00' ) 63 | $this->resolution = 2; 64 | else if( $resolution == '01' ) 65 | $this->resolution = 4; 66 | else if( $resolution == '10' ) 67 | $this->resolution = 8; 68 | else if( $resolution == '11' ) 69 | $this->resolution = 16; 70 | 71 | // return resolution ( +/- Gs ) 72 | return $this->resolution; 73 | 74 | } 75 | 76 | public function set_resolution( 77 | $resolution // ( +/- Gs, options are 2, 4, 8, 16 ) 78 | ) { 79 | 80 | // convert resolution to binary value 81 | if( $resolution == 2 ) 82 | $value = 00; 83 | else if( $resolution == 4 ) 84 | $value = 01; 85 | else if( $resolution == 8 ) 86 | $value = 10; 87 | else if( $resolution == 16 ) 88 | $value = 11; 89 | else 90 | throw new Exception( 'invalid resolution value for accelerometer' ); 91 | 92 | // update resolution class value 93 | $this->resolution = $resolution; 94 | 95 | // update the settings on the lsm303 96 | $settings = str_pad( base_convert( $this->I2c->read_register( self::ctrl_reg4 ), 16, 2 ), 8, 0, STR_PAD_LEFT ); 97 | $settings = substr( $settings, 0, 2 ) . $value . substr( $settings, 4, 4 ); 98 | $this->I2c->write_register( self::ctrl_reg4, base_convert( $settings, 2, 10 ) ); 99 | 100 | } 101 | 102 | public function get_acceleration() { 103 | $accel['x'] = $this->I2c->read_signed_short( self::out_x_h ) / ( self::resolution_marks / $this->resolution ); 104 | $accel['y'] = $this->I2c->read_signed_short( self::out_y_h ) / ( self::resolution_marks / $this->resolution ); 105 | $accel['z'] = $this->I2c->read_signed_short( self::out_z_h ) / ( self::resolution_marks / $this->resolution ); 106 | $this->acceleration = $accel; 107 | return $this->acceleration; 108 | } 109 | 110 | public function get_roll() { 111 | return atan2( $this->acceleration['y'], sqrt( pow( $this->acceleration['x'], 2 ) + pow( $this->acceleration['z'], 2 ) ) ) * 180 / pi(); 112 | } 113 | 114 | public function get_pitch() { 115 | return -1 * atan2( $this->acceleration['x'], sqrt( pow( $this->acceleration['y'], 2 ) + pow( $this->acceleration['z'], 2 ) ) ) * 180 / pi(); 116 | } 117 | 118 | } 119 | 120 | ?> -------------------------------------------------------------------------------- /peripherals/lsm303_magnetometer.php: -------------------------------------------------------------------------------- 1 | I2c = new i2c_bus( self::i2c_address ); 44 | 45 | } 46 | 47 | public function get_resolution() { 48 | 49 | // read settings from register 50 | $settings = str_pad( base_convert( $this->I2c->read_register( self::crb_reg ), 16, 2 ), 8, 0, STR_PAD_LEFT ); 51 | 52 | // get resolution bits and translate them 53 | $resolution = substr( $settings, 0, 3 ); 54 | switch( $resolution ) { 55 | case '001': 56 | $this->resolution = 1.3; 57 | case '010': 58 | $this->resolution = 1.9; 59 | case '011': 60 | $this->resolution = 2.5; 61 | case '100': 62 | $this->resolution = 4.0; 63 | case '101': 64 | $this->resolution = 4.7; 65 | case '110': 66 | $this->resolution = 5.6; 67 | case '111': 68 | $this->resolution = 8.1; 69 | } 70 | 71 | // return resolution ( +/- Gauss ) 72 | return $this->resolution; 73 | 74 | } 75 | 76 | public function set_resolution( 77 | $resolution // ( +/- Gs, options are 2, 4, 8, 16 ) 78 | ) { 79 | 80 | // convert resolution to binary value 81 | if( $resolution == 2 ) 82 | $value = 00; 83 | else if( $resolution == 4 ) 84 | $value = 01; 85 | else if( $resolution == 8 ) 86 | $value = 10; 87 | else if( $resolution == 16 ) 88 | $value = 11; 89 | else 90 | throw new Exception( 'invalid resolution value for accelerometer' ); 91 | 92 | // update resolution class value 93 | $this->resolution = $resolution; 94 | 95 | // update the settings on the lsm303 96 | $settings = str_pad( base_convert( $this->I2c->read_register( self::crb_reg ), 16, 2 ), 8, 0, STR_PAD_LEFT ); 97 | $settings = substr( $settings, 0, 2 ) . $value . substr( $settings, 4, 4 ); 98 | $this->write_register( self::crb_reg, base_convert( $settings, 2, 10 ) ); 99 | 100 | } 101 | 102 | public function get_fields() { 103 | $this->fields['x'] = $this->I2c->read_signed_short( self::out_x_h ); 104 | $this->fields['y'] = $this->I2c->read_signed_short( self::out_y_h ); 105 | $this->fields['z'] = $this->I2c->read_signed_short( self::out_z_h ); 106 | return $this->fields; 107 | } 108 | 109 | public function get_heading() { 110 | return atan2( $this->fields['y'], $this->fields['y'] ); 111 | } 112 | 113 | } 114 | 115 | ?> -------------------------------------------------------------------------------- /test_accelerometer.php: -------------------------------------------------------------------------------- 1 | set_resolution( 2 ); 8 | echo "\nAccelerometer Resolution: " . $Accel->get_resolution(); 9 | 10 | // read accelerometer 11 | while( 1 ) { 12 | $accel = $Accel->get_acceleration(); 13 | echo "\nACCEL: " . number_format( $accel['x'], 2 ) . ', ' . number_format( $accel['y'], 2 ) . ', ' . number_format( $accel['z'], 2 ); 14 | echo " - ROLL (x): " . number_format( $Accel->get_roll(), 2 ); 15 | echo " - PITCH (y): " . number_format( $Accel->get_pitch(), 2 ); 16 | } 17 | 18 | ?> -------------------------------------------------------------------------------- /test_bmp085.php: -------------------------------------------------------------------------------- 1 | get_readings(); 7 | 8 | ?> -------------------------------------------------------------------------------- /test_magnetometer.php: -------------------------------------------------------------------------------- 1 | set_resolution( 2 ); 8 | echo "\nMagnetometer Resolution: " . $Magnet->get_resolution(); 9 | 10 | // read magnetometer 11 | while( 1 ) { 12 | $fields = $Magnet->get_fields(); 13 | echo "\nFIELDS: " . number_format( $fields['x'], 2 ) . ', ' . number_format( $fields['y'], 2 ) . ', ' . number_format( $fields['z'], 2 ); 14 | echo " - HEADING: " . number_format( $Magnet->get_heading(), 2 ); 15 | } 16 | 17 | ?> --------------------------------------------------------------------------------