Skip to content

Commit fcf21cf

Browse files
author
marcusw
committed
HiTechnic Compass Sensor support in the trunk. Anyone who wants to port this to v2 is welcome to!
1 parent c0e2644 commit fcf21cf

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

nxt/htcompass.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# hicompass module - for interfacing with
2+
# the HiTechnic Lego Mindstorms NXT compass sensor
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
14+
#Get the sensor library independent of whether hicompass is in the nxt directory
15+
try:
16+
import sensor
17+
except:
18+
import nxt.sensor as sensor
19+
import sys
20+
from nxt.error import DirProtError
21+
from time import sleep
22+
23+
# I2C addresses for a HiTechnic compass sensor
24+
I2C_ADDRESS_CMPS_NX = {
25+
0x00: ('version', 8, True),
26+
0x08: ('manufacturer', 8, True),
27+
0x10: ('sensor_type', 1, True),
28+
0x41: ('mode_control', 1, True),
29+
0x42: ('heading_msb', 1, False),
30+
0x43: ('heading_lsb', 1, False),
31+
0x44: ('heading', 2, True),
32+
}
33+
34+
class _MetaCMPS_Nx(sensor._Meta):
35+
'Metaclass which adds accessor methods for CMPS-Nx I2C addresses'
36+
37+
def __init__(cls, name, bases, dict):
38+
super(_MetaCMPS_Nx, cls).__init__(name, bases, dict)
39+
for address in I2C_ADDRESS_CMPS_NX:
40+
name, n_bytes, set_method = I2C_ADDRESS_CMPS_NX[address]
41+
q = sensor._make_query(address, n_bytes)
42+
setattr(cls, 'get_' + name, q)
43+
if set_method:
44+
c = sensor._make_command(address)
45+
setattr(cls, 'set_' + name, c)
46+
47+
class CompassSensor(sensor.DigitalSensor):
48+
49+
__metaclass__ = _MetaCMPS_Nx
50+
51+
def __init__(self, brick, port):
52+
super(CompassSensor, self).__init__(brick, port)
53+
self.sensor_type = sensor.Type.LOW_SPEED_9V
54+
self.mode = sensor.Mode.RAW
55+
self.set_input_mode()
56+
sleep(0.1) # Give I2C time to initialize
57+
58+
59+
def get_manufacturer(self):
60+
return string(self.i2c_query(0x00,8));
61+
62+
def get_sample(self,numtries=5):
63+
tries = numtries
64+
heading = 10000
65+
while heading > 360 or heading < 0:
66+
try:
67+
data = self.i2c_query(0x44,2)
68+
heading = ord(data[0]) + 255*ord(data[1])
69+
except DirProtError:
70+
heading = 10000
71+
tries -= 1
72+
if tries < 0:
73+
errstr = "Error: " + str(numtries) + " consecutive bus failures. \nCheck your compass's connection"
74+
sys.exit(errstr)
75+
76+
return heading
77+
78+
def get_relative_heading(self,target=0):
79+
rheading = self.get_sample()-target
80+
if rheading > 180:
81+
rheading -= 360
82+
elif rheading < -180:
83+
rheading += 360
84+
return rheading
85+
86+
#this deserves a little explanation:
87+
#if max > min, it's straightforward, but
88+
#if min < max, it switches the values of max and min
89+
#and returns true iff heading is NOT between the new max and min
90+
def is_in_range(self,min,max):
91+
reversed = False
92+
if min > max:
93+
(max,min) = (min,max)
94+
reversed = True
95+
heading = self.get_sample()
96+
in_range = (heading > min) and (heading < max)
97+
#an xor handles the reversal
98+
#a faster, more compact way of saying
99+
#if !reversed return in_range
100+
#if reversed return !in_range
101+
return bool(reversed) ^ bool(in_range)
102+
103+
def calibrate_mode(self):
104+
self.i2c_command(0x41,0x43)
105+
106+
def measure_mode(self):
107+
self.i2c_command(0x41,0x00)
108+

0 commit comments

Comments
 (0)