Some games are controlled by tilting a phone in the air, using the accelerometer. The popular Wii game console uses an accelerometer for its controllers. In this chapter, you will hack a Wii controller to use its sensors. We used a phone accelerometer for control in the Football Robot from Make: Arduino Bots and Gadgets.
Hard disks found in laptops and desktops can now take a lot of punishment. Many are rated to take a shock of 150 g (when off), an acceleration that would immediately kill any human. To brace for impact, some drives will turn themselves off: when the hard disk accelerometer detects it’s in free fall, it automatically moves the actuator arm away from the sensitive plates.
Have you ever tried to ride a self-balancing device, like a Segway or a Solowheel? After perhaps a shaky start, it almost feels like a miracle that the device stays upright.
When a self-balancing device detects that it’s about to fall over forward, it quickly moves its wheels forward, turning itself upright again. Self-balancers measure angular velocity with a gyroscope. (An accelerometer would gather too many cumulative errors to work in a self-balancing device.)
Acceleration is the rate at which an object’s velocity changes (when it’s slowing down or speeding up). Angular velocity measures the rotational speed of an object, as well as the axis that it’s rotating around. Depending on your project, you might need acceleration, angular velocity, or even both.
Acceleration is measured in g, as a multiple of the acceleration caused by Earth’s gravity. Another commonly used unit of acceleration is meters per second squared (m/s2). Free-fall acceleration (1 g) is 9.81 m/s2.
Why are the seconds squared in acceleration? Acceleration is change in speed. If you’re using meters per second (m/s) as a unit of speed, then the unit of acceleration (change of speed) is meters per second per second, or m/s2.
Gyroscopes measure angular velocity, or how fast the sensor is rotating around an axis. For example, a gyroscope might report it’s rotating at 10 degrees per second. They are used in self-balancers and airplane gyrocompasses.
MX2125 is a simple two-axis acceleration sensor (see Figure 8-1). It reports acceleration as a pulse length, making the interface and code simple.
The real, physical world is three dimensional. Objects can go up and down (y), left and right (x), and back and forth (z). A two-axis sensor only measures two of these axes.
The MX2125 only measures up to 3 g per axis. But some sensors can measure extreme acceleration. For example, the maximum measured acceleration of the ADXL377 (200 g), is much more than would kill any human. Thus, it’s more than is experienced in a shuttle launch or high-g maneuvers in fighter jets. It could measure an object accelerating faster than a bullet fired from a pistol. When we made an early prototype for an Aalto-1 satellite sun sensor, even the satellite spec did not require acceleration this tough.
It’s unlikely that you would need to measure such an extreme acceleration, and it would probably not be possible with a breadboard setup (because the acceleration needed to test would shake your project apart!). The cost is quite minimal, though. However, the wider the area of measured acceleration (from -250 g to +250 g), the less precise the device is.
Usually, an accelerometer’s conversion formulas are found on data sheets. In this case, it required some more searching.
MX2125 works by heating a bubble of gas inside the device, and then measuring how the air bubble moves.
When power is on, the MX2125 reports the acceleration on each axis, 100 pulses a second. Consecutive HIGH and LOW signals form a 100 Hz square wave. The more acceleration there is, the more time the wave spends in the HIGH portion, and the less time in the LOW portion. You can read these pulses to determine acceleration.
One full wave contains one HIGH and one LOW. The time taken by one wave (HIGH+LOW) is called period (T). Let’s call the time of HIGH part tHIGH (time of HIGH).
The duty cycle tells you how much of the wave is HIGH. The duty cycle is a percentage, for example 50% (0.50) or 80% (0.80).
dutyCycle = tHIGH / T
According to the data sheet and other documents, the period T is set to 10 ms by default:
dutyCycle = tHIGH / 10 ms
Here’s the acceleration formula from the data sheet:
A = (tHIGH/T-0.50)/20%
Or, replacing tHIGH/T
with dutyCycle
and 20%
with .2
:
A = (dutyCycle-0.50)/.2
Now it can be written as follows (because x/.2
is 5*x
):
A = 5*(dutyCycle-0.50)
or:
A = 5*(tHIGH/T-0.50)
When there is no acceleration (0 g), the duty cycle is 50%:
0 = 5*(dutyCycle-0.50) 0/5 = dutyCycle-0.50 0 = dutyCycle-0.50 .50 = dutyCycle
At the time we originally checked, the Parallax and Memsic documentation conflicted on the multiplier: the Memsic documentation used 1/20% (5), and Parallax used 1/12.5% (8). In our experiments, we found 1/12.5% (8) to give proper readings with the breakout board from Parallax. And in fact, when we later examined the MXD2125 data sheet from Memsic that was hosted on Parallax’s site, both agreed on 1/12.5%. This is why you need to be careful with data sheets you find online: always verify the values with experimentation. So we will use 8 as the multiplier:
A = 8*(tHIGH/T-0.50)
Because Arduino pulseIn()
returns the pulse length in microseconds (1 µs = 0.001 ms = 1e-6 s), the formula could be modified to use microseconds:
A = 8 * ( tHIGH/(10*1000) - 0.5)
The unit of A is then g, which equals 9.81 m/s2.
For example, if tHIGH is 5,000 µs (5 ms), the duty cycle is
dutyCycle = 5 ms / 10 ms = 0.50 = 50%
Which equals 0 g:
A = 8*(0.50-0.5) = 8*0 = 0 // g
To show another example, consider tHIGH of 6250 µs (6.25 ms)
A = 8*(6250/10000-0.5) = 8*(0.625-0.5) = 8*0.125 = 1 // g
Thus, a 6.25 ms pulse means 1 g acceleration.
Figure 8-2 shows the circuit diagram for Arduino. Wire it up as shown, and load the code from Example 8-1.
// mx2125.ino - measure acceleration on two axes using MX2125 and print to serial
// (c) BotBook.com - Karvinen, Karvinen, Valtokari
const
int
xPin
=
8
;
const
int
yPin
=
9
;
void
setup
(
)
{
Serial
.
begin
(
115200
)
;
pinMode
(
xPin
,
INPUT
)
;
pinMode
(
yPin
,
INPUT
)
;
}
void
loop
(
)
{
int
x
=
pulseIn
(
xPin
,
HIGH
)
;
//
int
y
=
pulseIn
(
yPin
,
HIGH
)
;
int
x_mg
=
(
(
x
/
10
)
-
500
)
*
8
;
//
int
y_mg
=
(
(
y
/
10
)
-
500
)
*
8
;
Serial
.
(
"
Axels x:
"
)
;
Serial
.
(
x_mg
)
;
Serial
.
(
"
y:
"
)
;
Serial
.
println
(
y_mg
)
;
delay
(
10
)
;
}
Figure 8-3 shows the wiring diagram for the Raspberry Pi. Hook everything up as shown, and then run the code shown in Example 8-2.
# mx2125.py - print acceleration axel values.
# (c) BotBook.com - Karvinen, Karvinen, Valtokari
import
time
import
botbook_gpio
as
gpio
xPin
=
24
yPin
=
23
def
readAxel
(
pin
)
:
gpio
.
mode
(
pin
,
"
in
"
)
gpio
.
interruptMode
(
pin
,
"
both
"
)
return
gpio
.
pulseInHigh
(
pin
)
#
def
main
(
)
:
x_g
=
0
y_g
=
0
while
True
:
x
=
readAxel
(
xPin
)
*
1000
y
=
readAxel
(
yPin
)
*
1000
if
(
x
<
10
)
:
#
x_g
=
(
(
x
/
10
)
-
0.5
)
*
8
#
if
(
y
<
10
)
:
y_g
=
(
(
y
/
10
)
-
0.5
)
*
8
(
"
Axels x:
%f
g, y:
%f
g
"
%
(
x_g
,
y_g
)
)
#
time
.
sleep
(
0.5
)
if
__name__
==
"
__main__
"
:
main
(
)
When an accelerometer is not moving, it detects gravity and can tell where down is. A gyroscope can tell the orientation reliably, even if you spin it around and around. A gyroscope ignores gravity, though.
Could we combine an accelerometer and gyroscope to get both benefits? Yes.
An IMU (inertial measurement unit) combines multiple sensors and (optionally) some logic to get more precise and reliable motion information. In this experiment, you’ll work hands-on with the basic features of the MPU 6050.
In general, IMUs are more expensive and more precise than plain accelerometers and gyros. They also use more advanced protocols to communicate, such as I2C, instead of a simple pulse width signaling protocol.
The MPU 6050 (Figure 8-4) has an accelerometer, gyro, and microcontroller on the same chip. Even though space isn’t a premium when you’re in the breadboard prototyping stage, it’s nice to know that all this functionality fits in a tiny surface-mounted component, just in case you ever run short of circuit real estate. For example, an early prototype of a sun sensor we designed barely fit into a box of about 10 × 10 × 10 cm. The final part had to fit into a very flat 5 mm × 5 mm area on the satellite surface.
The MPU 6050 uses the I2C protocol. Thanks to the python-smbus library, Raspberry Pi code is much simpler and easier than the equivalent Arduino code. In general, Raspberry Pi handles complicated protocols in less code than Arduino.
Figure 8-5 shows the wiring diagram for Arduino. Hook everything up, and then run the code in Example 8-3.
Difficult code! The code for MPU 6050 contains more difficult programming concepts than most other code examples in this book. If you find endianness, bit shifting, and structs difficult, you can simply use the code and play with the values. You don’t need to deeply understand the code to use it.
If you want to understand the code, see the explanations after the code, such as Hexadecimal, Binary, and Other Numbering Systems and Bitwise Operations.
// mpu_6050.ino - print acceleration (m/s**2) and angular velocity (gyro, deg/s)
// (c) BotBook.com - Karvinen, Karvinen, Valtokari
#
include <Wire.h>
//
const
char
i2c_address
=
0x68
;
//
const
unsigned
char
sleep_mgmt
=
0x6B
;
//
const
unsigned
char
accel_x_out
=
0x3B
;
struct
data_pdu
//
{
int16_t
x_accel
;
//
int16_t
y_accel
;
int16_t
z_accel
;
int16_t
temperature
;
//
int16_t
x_gyro
;
//
int16_t
y_gyro
;
int16_t
z_gyro
;
}
;
void
setup
(
)
{
Serial
.
begin
(
115200
)
;
Wire
.
begin
(
)
;
//
write_i2c
(
sleep_mgmt
,
0x00
)
;
//
}
int16_t
swap_int16_t
(
int16_t
value
)
//
{
int16_t
left
=
value
<
<
8
;
//
int16_t
right
=
value
>
>
8
;
//
right
=
right
&
0xFF
;
//
return
left
|
right
;
//
}
void
loop
(
)
{
data_pdu
pdu
;
//
read_i2c
(
accel_x_out
,
(
uint8_t
*
)
&
pdu
,
sizeof
(
data_pdu
)
)
;
//
pdu
.
x_accel
=
swap_int16_t
(
pdu
.
x_accel
)
;
//
pdu
.
y_accel
=
swap_int16_t
(
pdu
.
y_accel
)
;
pdu
.
z_accel
=
swap_int16_t
(
pdu
.
z_accel
)
;
pdu
.
temperature
=
swap_int16_t
(
pdu
.
temperature
)
;
//
pdu
.
x_gyro
=
swap_int16_t
(
pdu
.
x_gyro
)
;
pdu
.
y_gyro
=
swap_int16_t
(
pdu
.
y_gyro
)
;
pdu
.
z_gyro
=
swap_int16_t
(
pdu
.
z_gyro
)
;
float
acc_x
=
pdu
.
x_accel
/
16384.0f
;
//
float
acc_y
=
pdu
.
y_accel
/
16384.0f
;
float
acc_z
=
pdu
.
z_accel
/
16384.0f
;
Serial
.
(
"
Accelerometer: x,y,z (
"
)
;
Serial
.
(
acc_x
,
3
)
;
Serial
.
(
"
g,
"
)
;
//
Serial
.
(
acc_y
,
3
)
;
Serial
.
(
"
g,
"
)
;
Serial
.
(
acc_z
,
3
)
;
Serial
.
println
(
"
g)
"
)
;
int
zero_point
=
-
512
-
(
340
*
35
)
;
//
double
temperature
=
(
pdu
.
temperature
-
zero_point
)
/
340.0
;
//
Serial
.
(
"
Temperature (C):
"
)
;
Serial
.
println
(
temperature
,
2
)
;
Serial
.
(
"
Gyro: x,y,z (
"
)
;
Serial
.
(
pdu
.
x_gyro
/
131.0f
)
;
Serial
.
(
"
deg/s,
"
)
;
//
Serial
.
(
pdu
.
y_gyro
/
131.0f
)
;
Serial
.
(
"
deg/s,
"
)
;
Serial
.
(
pdu
.
z_gyro
/
131.0f
)
;
Serial
.
println
(
"
deg/s)
"
)
;
delay
(
1000
)
;
}
void
read_i2c
(
unsigned
char
reg
,
uint8_t
*
buffer
,
int
size
)
//
{
Wire
.
beginTransmission
(
i2c_address
)
;
//
Wire
.
write
(
reg
)
;
//
Wire
.
endTransmission
(
false
)
;
//
Wire
.
requestFrom
(
i2c_address
,
size
,
true
)
;
//
int
i
=
0
;
//
while
(
Wire
.
available
(
)
&
&
i
<
size
)
{
//
buffer
[
i
]
=
Wire
.
read
(
)
;
//
i
+
+
;
}
if
(
i
!
=
size
)
{
//
Serial
.
println
(
"
Error reading from i2c
"
)
;
}
}
void
write_i2c
(
unsigned
char
reg
,
const
uint8_t
data
)
//
{
Wire
.
beginTransmission
(
i2c_address
)
;
//
Wire
.
write
(
reg
)
;
Wire
.
write
(
data
)
;
Wire
.
endTransmission
(
true
)
;
}
Wire.h is the Arduino library for the I2C protocol. Wire.h comes with the Arduino IDE, so you can just include the library in your code. You don’t need to separately install the library or copy any library files manually.
The I2C address of the MPU 6050 sensor. One three-wire bus can have many slaves. Each slave is recognized by its address. Typically, an I2C bus can have 128 (27) slaves. The I2C wires can be only a couple of meters long, so that also puts a practical limit to wire length. The number is represented in hexadecimal, see Hexadecimal, Binary, and Other Numbering Systems for an explanation of this notation.
The registers for commands are from MPU 6050 documentation. If you need a complete list of commands, search the Web for “MPU 6050 data sheet” and “MPU 6050 register map.” The numbers are in hex but could be expressed in decimal if you prefer.
The struct for decoding the answer from the sensor. A struct combines multiple values together. The C struct is only for data, and a struct can’t contain any functions. This makes structs different from objects and classes you may be familiar with from other languages. struct data_pdu
declares a new data type, which you’ll later use for declaring variables of type data_pdu
. This struct has variables that are exactly the same size as the data fields in the protocol used by the sensor. Later, you will read bytes from the sensor directly into the struct. Then you’ll go through the variables embedded in the struct to get at the values. Yes, it’s a neat trick!
A variable for storing acceleration across the horizontal x-axis. The type int16_t
is a specifically sized integer defined by avr-libc (the C library used by the Arduino compiler). It’s a signed (negative or positive) 16-bit (two-byte) integer. Because the struct is used for decoding raw data from the sensor, the exact sized data types are required.
The sensor also reports temperature. Even if you don’t need it, you must have a variable for it so that the data_pdu
struct ends up being the right size.
Angular velocity around x-axis (roll), read by the gyroscope portion of the MPU 6050.
Initialize I2C communication using the Wire.h library.
Wake up the sensor by writing the command 0
to the sleep management register 0x6B
. The MPU 6050 starts out in sleep mode, so this is a required step.
Swap the two bytes in parameter value. MPU 6050 is big endian. Arduino is little endian like most processors. The endianness must be converted between the platforms. See Endianness—Typically on the Small Side for more details.
This new two-byte (16 bit) variable left
ends up being the rightmost byte of the parameter value
. After a one-byte (8 bit) left shift (<<
), the leftmost byte of value
is dropped, as it doesn’t fit the two bytes of left
. The right byte of left
is filled with zeroes in the bit shift.
This new two-byte (16 bit) variable right
is now the leftmost byte of value
. The leftmost byte of right
is zeroes.
Zero out the leftmost byte of right
, just to make sure it’s empty. See also Bit Masking with Bitwise AND &
Combine the left and right bytes. The variable left
is actually two bytes (16 bits), with the rightmost byte (8 bits) full of zeroes. See also Bitwise OR |
Create a new variable pdu
of type data_pdu
. This is the struct type you created earlier.
Fill the pdu
struct with data from the sensor. The first parameter is the register to read (accel_x_out, 0x3B)
. The second parameter is a reference to the pdu
struct. It is passed as a reference, so that the function can modify the struct itself instead of returning a value. The last parameter is how many bytes to read. Conveniently, you can use the size of the struct to specify the number of bytes to read.
Convert the number from the sensor’s big endian format to little endian used in Arduino.
You can refer to the variables in the struct with structname.var
, such as pdu.temperature
.
The raw acceleration value is converted to the real-life unit g. The standard gravity g
is 9.81 m/s2
. The conversion factor is from the data sheet. To get a floating point (decimal) result, the divider must be floating point.
Print the acceleration to the serial monitor. The unit is g, the acceleration from gravity. 1 g = 9.81 m/s2.
Calculate the zero point for converting raw measurement to temperature in Celsius, using information from the data sheet. The temperature is from -40 C to +85 C. A raw value of -512 indicates 35 C. From that point, every 1 C change is represented by a raw value change of 340. Thus, to find the 0 C point raw value, you take -512 and subtract the product 340 * 35 (deducting 35 C worth of raw values at 340 per C). The calculation is -512 - (340 * 35)
, which is -12412. But instead of writing the calculated value -12412, you should write the calculation from the datasheet so that the code is more clear.
Convert raw measurement to temperature in Celsius, using the formula from the data sheet.
Print angular velocity as measured by gyroscope. The raw to degree/s conversion factor 1/131.0 is from the data sheet. To get a floating point (decimal) result, the divider must be floating point, too.
A function to read size
number of bytes from register point
. The result is written over the struct, which is represented by the *buffer
pointer. Because of the pointer, the actual value of the struct is modified, instead of returning a value.
Send the I2C command to the device (the MPU 6050 sensor in the address 0x69).
Specify the register address to read. In this program, read_i2c()
is only used to read from accel_x_out
(0x3B).
Keep the connection open, so that you can read data on the next lines.
Request size
bytes of data from the sensor. Earlier, you stated you want to start from register accel_x_out
(0x3B). The true
parameter (the third argument, which is named stop
in the Arduino documentation) means that the connection is closed after the read ends, which releases the I2C bus for future use.
Declare a new variable for the upcoming while
loop. The loop variable i
holds the count of how many bytes have been read. This count i
equals the number of iterations the loop has run.
Enter the loop only if there are bytes available for reading and you have not yet read all the bytes requested. In the way read_i2c()
is called in this program, the variable size
will always be the length of data_pdu
struct.
Read a byte (8 bits) and store it into the buffer. Considering how read_i2c()
is called in this program, we can walk through the first iterations. The pointer *buffer
points to the first byte of pdu
, which is of struct type data_pdu
. On the first iteration, i
is 0, so buffer[i]
points to the first byte of pdu
. Because pdu
was passed to the function with a pointer, the contents of the actual pdu
(the variable in the main program) are overwritten. No return is needed, so the type of read_i2c()
is void. On the second iteration, buffer[1]
points to the second byte of pdu
. This continues for the whole buffer (pdu
). When i == size
, the while
loop is not re-entered, and execution continues with the code that comes after the while
loop.
If not enough bytes were available, the loop variable i
is less than size
. As i
was declared outside the loop, it is available to you after the loop.
Write one byte data
to register reg
on the sensor.
The address of the sensor comes from the global variable i2c_address
.
Figure 8-6 shows the wiring diagram for Raspberry Pi. Hook it up as shown, and then run the code from Example 8-4.
# mpu_6050.py - print acceleration (m/s**2) and angular velocity (gyro, deg/s)
# (c) BotBook.com - Karvinen, Karvinen, Valtokari
import
time
import
smbus
# sudo apt-get -y install python-smbus #
import
struct
i2c_address
=
0x68
#
sleep_mgmt
=
0x6B
#
accel_x_out
=
0x3B
#
bus
=
None
#
acc_x
=
0
acc_y
=
0
acc_z
=
0
temp
=
0
gyro_x
=
0
gyro_y
=
0
gyro_z
=
0
def
initmpu
(
)
:
global
bus
#
bus
=
smbus
.
SMBus
(
1
)
#
bus
.
write_byte_data
(
i2c_address
,
sleep_mgmt
,
0x00
)
#
def
get_data
(
)
:
global
acc_x
,
acc_y
,
acc_z
,
temp
,
gyro_x
,
gyro_y
,
gyro_z
bus
.
write_byte
(
i2c_address
,
accel_x_out
)
#
rawData
=
"
"
for
i
in
range
(
14
)
:
#
rawData
+
=
chr
(
bus
.
read_byte_data
(
i2c_address
,
accel_x_out
+
i
)
)
#
data
=
struct
.
unpack
(
'
>hhhhhhh
'
,
rawData
)
#
acc_x
=
data
[
0
]
/
16384.0
#
acc_y
=
data
[
1
]
/
16384.0
acc_z
=
data
[
2
]
/
16384.0
zero_point
=
-
512
-
(
340
*
35
)
#
temp
=
(
data
[
3
]
-
zero_point
)
/
340.0
#
gyro_x
=
data
[
4
]
/
131.0
#
gyro_y
=
data
[
5
]
/
131.0
gyro_z
=
data
[
6
]
/
131.0
def
main
(
)
:
initmpu
(
)
while
True
:
#
get_data
(
)
#
(
"
DATA:
"
)
(
"
Acc (
%.3f
,
%.3f
,
%.3f
) g,
"
%
(
acc_x
,
acc_y
,
acc_z
)
)
#
(
"
temp
%.1f
C,
"
%
temp
)
(
"
gyro (
%.3f
,
%.3f
,
%.3f
) deg/s
"
%
(
gyro_x
,
gyro_y
,
gyro_z
)
)
time
.
sleep
(
0.5
)
# s #
if
__name__
==
"
__main__
"
:
main
(
)
SMBus implements a subset of the I2C industry standard protocol. The SMBus library makes the Raspberry Pi program much shorter than the Arduino equivalent. The python-smbus
package must be installed on Raspberry Pi (see SMBus and I2C Without Root for instructions).
The I2C address of MPU 6050 sensor, found on the data sheet. The number is represented in hexadecimal (see Hexadecimal, Binary, and Other Numbering Systems).
The register address for commands. You can find the register map by searching the Web for “MPU 6050 register map”.
The X acceleration register address is the starting address for the values you’re interested in: acceleration, temperature, and angular velocity.
Make bus
a global variable visible to all functions.
To modify the value of a global variable in a function, you must indicate that it’s global in the beginning of the function.
Initialize the SMBus (I2C). Store the new object of the SMBus class into the global bus
variable.
MPU 6050 starts in sleep mode. Wake it up before doing anything with it. The commands to the sensor are given over I2C (SMBus) with the device address, the register, and the value to write to the register.
Request data, starting from the X acceleration address.
Repeat 14 times, with values of i
, from 0 to 13.
Read the current byte, convert it to ASCII, and add it to rawData
string.
Convert the rawData
string to a Python tuple. The format string characters indicate little endian <
, short signed 2 byte (16 bit) integer h
.
Convert raw acceleration to real-life g units. The standard gravity g is equal to 9.81 m/s2.
Calculate the temperature zero point. The Pi does it very quickly, and writing the whole formula here makes code easier to read and typos less likely.
Convert raw temperature to Celsius. To get a floating point result, the divider must also be floating point. Conversion formulas are from the data sheet (Google “MPU 6050 data sheet”).
Convert raw angular velocity to real-life units (degrees per second).
The program runs until you press Control-C.
get_data()
updates global variables, so it doesn’t need to return values from the function.
Print acceleration using the format string. The replacement %.3f
indicates a floating point value with three decimal places.
To let the user read the printed values and avoid taking 100% of CPU time, we add a small delay here.
Find out what walking, running, or skipping does to readings. How about twitching or squirming?
The Raspberry Pi code uses the Python smbus library for I2C. Luckily, installing software in Linux is a breeze. You can install any software to Raspbian just like you would install it in Debian, Ubuntu, or Mint. Double-click the LXTerminal icon on the left side of your Raspbian desktop. Then:
$ sudo apt-get update $ sudo apt-get install python-smbus
To enable I2C support, you’ll need to enable the i2c modules. First, make sure they are not disabled. Edit the /etc/modprobe.d/raspi-blacklist.conf with the command sudoedit /etc/modprobe.d/raspi-blacklist.conf
and delete this line:
blacklist i2c-bcm2708
Save the file: press Control-X, type y, and then press Enter or Return.
Next, edit the /etc/modules with the command sudoedit /etc/modules
and add these two lines:
i2c-bcm2708 i2c-dev
Save the file: press Control-X, type y, and then press Enter or Return.
To use I2C without needing to be root, create the udev rule file 99-i2c.rules (shown in Example 8-5) and put it in place. (To avoid typing and inevitable typos, you can download a copy of 99-i2c.rules file from http://botbook.com.)
$ sudo cp 99-i2c.rules /etc/udev/rules.d/99-i2c.rules
# /etc/udev/rules.d/99-i2c.rules - I2C without root on Raspberry Pi
# Copyright 2013 http://BotBook.com
SUBSYSTEM
==
"i2c-dev"
,
MODE
=
"0666"
Reboot your Raspberry Pi, open LXTerminal, and confirm that you can see the I2C devices and that the ownership is correct:
$
ls -l /dev/i2c*
The listing should show two files, and they should list permissions of crw-rw-rwT
. If not, go over the preceding steps again.
The same number can be represented multiple ways. For example, the decimal number 65 is 0x41 in hexadecimal and 0b1000001 in binary. You are probably most familiar with the normal decimal system, where 5+5 is 10.
The different representations are marked with a prefix before the number. Normal decimal numbers don’t have a prefix. Hexadecimal numbers start with 0x
, binary numbers start with 0b
, and octal numbers start with 0
.
The different numbering systems are compared in Table 8-2.
Prefix | Representation system | Base | Use | Example | Calculation |
Decimal | 10 | The normal system | 10 | 0*100 + 1*101 | |
0x | Hexadecimal | 16 | C and C++ code, datasheets | 0xA | 10*160 |
0b | Binary | 2 | Low-level protocols, bit-banging | 0b1010 | 0*20 + 1*21 + 0*22 + 1*23 |
0 | Octal | 8 | Chmod permissions in Linux | 012 | 2*80 + 1*81 |
Consider the number 42. It is the exact same number in any representation system, so
42 = 0x2a = 0b101010 = 052
Only the base number changes. With the familiar, normal decimal system, the base is 10. Starting from the right, you first count ones and then tens.
2*1 + 4*10 = 42
If there is a big number, such as 1917, the ten is obvious. After ones, it’s tens (10), hundreds (10*10) and thousands (10*10*10). You can easily write these numbers as powers:
10*10 = 102 10*10*10 = 103
What about ones? Any number to zeroth power is 1, so it’s:
100 = 1
Thus, the number 42 becomes:
42 = 4*101 + 2*100
The hex representation of 42 is 0x2A. In hex, numbers bigger than 9 are shown with letters: A=10, B=11 … F=15. Starting from the right, note that A is 10 and count:
0x2A = 10*1 + 2*16 = 10 + 32 = 42
To play with powers, this can be written
10*160 + 2*161 = 0x2A
Try some other numbers. To check your calculations, use the Python console (see The Python Console or Table 8-3). Can you apply your skills to convert to binary numbers, too?
You can practice working with numbers in the Python console. The number representation (1 == 0x1 == 0b1) is the same in Python, C, and C++. You can run any Python commands in the console:
>>> print("Botbook.com") Botbook.com >>> 2+2 4
Any numbers you enter are converted to decimal system for display:
>>> 0x42 66 >>> 66 66 >>> 0b1000010 66
There are functions to convert any number to binary, hexadecimal, octal, and ASCII characters:
>>> bin(3) '0b11' >>> hex(10) '0xa' >>> oct(8) '010' >>> chr(0x42) 'B'