Spis treści

Opis

Paweł Konas, pawelkonas@gmail.com

NXT_sensors Build extra sensors from the Extreme NXT Book (available for us!) warning: requires some hardware and experience!

Spotkania

20090219

20090305

W planie dostarczenie prototypu czujnika.

20090416

Próba skonstruowania czujnika od początku w oparciu o mikrokontroler AVR ATmega8. Zalety: zwarta konstrukcja, tańszy, możliwość przeprogramowania. Zastanowić się jak podłączyć czujnik od strony PC (widoczność w sofcie NXT).

Projekt - STAN AKTUALNY

W skrócie zamieszczam aktualny stan projektu.
Zlutowany prototypowy czujnik odległości działający w zakresie 0 - 200cm z dokładnością około 5cm (dla odległości 10 do 15cm wyświetla 15cm itd.). Dodatkowo dołączona gotowa biblioteka do komunikacji za pomocą protokołu I2C i przygotowane połączenia dla tejże (podpięte piny).
Oprócz tego dołączony programator pod LPT.

Projekt - TODO

1) Poprawić jakość czujnika - łatwiejsze jeśli ma się oscyloskop. Większy zasięg/dokładność?,
2) Zaimplementować komunikację przez I2C,
3) Zaprojektować i zaimplementować komunikację z aplikacjami na PC (np. zrobić osobny bloczek w programie Mindstorms NXT odpowiadający za ten czujnik?).

Projekt - wersja pierwotna

Na początek proponuję laserowy czujnik odległości zaczerpnięty ze strony:
http://www.philohome.com/sensors/lasersensor.htm

Jednak mogą wystąpić - jak zwykle to bywa :) - pewne problemy.
1) W Polsce ciężko będzie dostać zastosowany czujnik odległości Hamamatsu S6986,
2) Jeszcze nie wiem gdzie kupić soczewki i odpowiednią taśmę odblaskową albo odpowiednik,
3) 1 i 2 muszę w praktyce przetestować i dostroić z hardware'm wyjętym ze wsk. laserowych dostępnych na polskim rynku, 4) Jak się okazało krótka żywotność.

Z powyższą propozycją wiążą się jednak pewne kwestie i dodatkowe komplikacje, które chciałbym omówić na konsultacjach. Drugi proponowany czujnik odległości - tym razem ultradźwiękowy - można znaleźć tutaj:
http://www.interq.or.jp/japan/se-inoue/e_srm.htm
Plusy:


Ostatecznie z wersji tej zrezygnowałem - z trzech zasadniczych powodów:
1) Duży rozmiar - wbrew pozorom bardzo istotny powód patrząc na rozmiar choćby jednostki centralnej NXT,
2) Początkowo nie uwzględniałem kolejnych elementów koniecznych m.in. do komunikacji przy pomocy I2C,
3) Mała 'elastyczność' (w porównaniu do programowalnych mikrokontrolerów).

Projekt - wersja końcowa

Po skonstruowaniu czujnika opisanego powyżej i problemach z jego debuggingiem zdecydowałem się na projekt od zera. Tym razem - i ostatecznie - sonar skonstruowałem w oparciu o tani (około 6zł w momencie pisania tego tekstu) i powszechnie dostępny mikrokontroler Atmega8. Dzięki m.in. posiadaniu komparatora analogowego, wewnętrznego zegara (1MHz) oraz programowalności samego układu udało się otrzymać konstrukcję zwartą i elastyczną.

Poniżej zamieszczam schemat układu (stworzony przy pomocy programu Eagle):

Poniżej zdjęcie wykonanego czujnika:

Dodatkowo zamieszczam pliki projektu wykonanego w programie (wersja ograniczona jest darmowa) Eagle - tj. powyższy plik schematu a także przygotowany do wydruku/zamówienia w firmie projekt płytki.
Spakowane pliki projektu w Eagle:
nxtsensor_eagle_projekt.rar

Wykaz użytych elementów

Podłączenie wyświetlaczy 7-segmentowych

Z uwagi na być może niezbyt czytelny fragment schematu odpowiadający za podłączenie pinów Atmegi do wyświetlaczy poniżej przedstawiam to połączenie raz jeszcze. Zaznaczam przy tym, że z uwagi na różne modele 7-segmentowych wyświetlaczy napiszę jedynie nazwy segmentów typu a,b, etc. zamiast konkretnych pinów zależnych od danego egzemplarza (powtarzam - wyświetlacze są ze wspólną katodą).
Rozmieszczenie segmentów jest jak na poniższym obrazku:

Zatem:

nazwa segmentu - pin atmegi

Dodatkowo wspólna katoda wyświetlaczy jest podłączona do pinu 23 (PC0) i 24 (PC1).

Opis złącza 2x5pin

W prawym górnym rogu płytki (wg orientacji na zdjęciu) znajduje się gniazdo do podłączenia zasilania/masy czy też (obecnie nie wykorzystywane) komunikacji I2C. Piny podłączone są następująco (orientacja tak jak na zdjęciu.):
1 X 2 X X
3 4 5 X X

Legenda:
1 - VCC
2 - SCL
3 - GND
4 - GND
5 - SDA
x - pin nie podłączony
Uwaga!: Napięcie VCC jest de facto prowadzone do stabilizatora napięcia 5V więc - wg specyfikacji technicznej scalaka 7805 - dopuszczalne napięcie podane na pin 1 może mieć max 35V. Zakładając jednak, że nie zamontowałem radiatora na stabilizatorze takie napięcie byłoby zabójcze dla układu. Idealnie natomiast nadaje się napięcie dostarczone przez NXT (biała żyłka w konektorze NXT - +9V).

Uwagi do skonstruowanego czujnika

Poniżej opiszę szczegółowo proces tworzenia schematu czujnika i uwagi jego dotyczące.
Przede wszystkim czujnik wykonany został w oparciu o tutorial programowania mikrokontrolerów AVR zamieszczony na stronie:
Tutorial pana Teodora Otulaka
Oraz projekt zmodyfikowanego przykładu czujnika odległości ze strony:
Modyfikacja przykładu z powyższego źródła

W efekcie udało mi się skonstruować czujnik, który miał zasięg około 50cm. Przy większych odległościach niestety sygnały zanikały. W tym momencie inspiracją stał się ogólnodostępny schemat czujników odległości dostępnych komercyjnie na rynku pod nazwą SRF08 (tudzież SRF02, SRF06 etc.). Zastosowano w nich dodatkowy układ scalony max232, którego głównym zadaniem była konwersja napięć ze standardu TTL na RS232. Tym samym nadajnik ultradźwięków zasilony został napięciem około 9V (zamiast początkowych 5V bezpośrednio z atmegi).
Wspomniany komercyjny schemat sonarów można znaleźć np. pod tym adresem: SRF06
Kupić zaś można choćby tutaj: SRF08-sklep.
Dzięki temu zabiegowi udało mi się uzyskać zasięg do około 2m.

Jako IDE do pisania kodu w C dla mikrokontrolera użyłem AVR Studio w wersji 4.13. Poniżej zamieszczam spakowany projekt utworzony właśnie w tym środowisku:
nxtsensor_avrstudio_projekt.rar

Zaistniałe problemy, pomysły na rozwiązanie

Problemy, które pojawiły się w trakcie realizacji projektu podzieliłem na kilka części. Przy niektórych problemach zamieszczam uwagi i pomysły na ich rozwiązanie.

Zasięg i dokładność sonaru

Komunikacja I2C

(Linki do omawianych tu tematów znajdują się na dole strony).
Dla mikrokontrolera Atmega udało mi się znaleźć gotową bibliotekę (Procyon AVRlib - linki na dole strony) na licencji GPL mającą m.in. zaimplementowaną wysokopoziomową obsługę protokołu I2C. Ze strony NXT korzystałem z języka NXC i IDE BricxCC (Bric Command Center). Jednak - nawet mimo, że korzystałem z przykładu, który teoretycznie powinien działać. Na przytoczonym forum nie udało się znaleźć odpowiedzi. Znalazłem jeszcze kilka wątków na różnych forach, z których wynikało że NXT z firmware'em starszym niż 1.05 ma bugi związane z komunikacją przez I2C. W testowanym zestawie NXT znajdował się firmware 1.01. Nie podjąłem się jednak jego wymiany.

Ewentualnie można by próbować podszyć się pod dostarczany w zestawie czujnik ultradźwięków? Jednak wbrew pozorom nie jest to proste. Lego nie udostępnia kodu źródłowego mikrokontrolera użytego w ich czujniku. Nie wiadomo więc co i kiedy wysyła do bricka. Można jedynie dowiedzieć się jak - dostępny jest dokument opisujący format akceptowalnych komunikatów I2C obsługiwanych przez NXT.

Komunikacja z PC

Do tej części nie udało mi się niemal w ogóle dotrzeć. Warte odnotowania jest jedynie to, że w standardzie języka NXC znajdują się interfejsy odpowiedzialne za komunikację bluetooth, które być może można by wykorzystać do podłączenia Brick'a do PC. Wciąż jednak problemem pozostanie zaimplementowanie własnych czujników w środowisku graficznym na PC. Jak można zrobić własny bloczek?

inne

Źródło informacji:
wikipedia - patrz sekcja ' Connector',
Dokumentacja Atmegi 8.

Programator

W ramach projektu dołączam także programator pod LPT (używałem go wraz z darmową aplikacją PonyProg do której link znajduje się na dole strony). Jego schemat jest następujący:

Dołączoną taśmę do Atmegi8-16PI podłączyć należy następująco (zakładając, że żyłka różowa ma nr 10, a żyłka po drugiej stronie taśmy ma nr 1).

Numer żyłki - odpowiadający pin Atmegi

Uwaga: W przypadku problemów (np. PonyProg wciąż zgłasza błąd) sprawdzić czy jest odblokowany port LPT w BIOS'ie.

Kod źródłowy

Prezentuję poniżej kod źródłowy sonaru (nie uwzględniam tu plików biblioteki Procyon AVRlib).
Plik sonar.c:

//#############################
//
// Sonar ultradźwiekowy
//
//#############################
 
#include <avr/io.h>
#include "deprecated.h"
#include "sonar.h"
#include "znaki.h"
#include <avr/interrupt.h>
#include <util/delay.h>
#include "i2c.h"
 
#define wait 0xffff
 
int distance=0;
int idx; //zmienna uzyta w petli w funkcji wynik
 
unsigned int TicksNo[42] = {10,20,50,85,120,150,170,	//3...30cm
						220,240,280,315,335,375,    //35...60cm
						400,440,460,500,530,560,    //65...90cm
						600,630,660,690,720,760,    //95...120cm
						790,820,850,885,910,945,    //125...150cm
						970,1010,1050,1080,1115,    //155...175cm
						1150,1180,1210,1240,1270,   //180...200cm
						1300}; //troche ponad 2m
 
unsigned short DisplayChars0[42] = {0,0,1,1,2,2,3,3, //03...35cm
									   4,4,5,5,6,6,7,7, //40...75cm
									   8,8,9,9,0,0,1,1, //80...115cm
									   2,2,3,3,4,4,5,5, //120...155cm
									   6,6,7,7,8,8,9,9,	//160...195cm
									   0,10}; //200...troche ponad 200
 
unsigned char DisplayChars1[42] = {3,5,0,5,0,5,0,5, //03...35cm
									   0,5,0,5,0,5,0,5, //40...75cm
									   0,5,0,5,0,5,0,5, //80...115cm
									   0,5,0,5,0,5,0,5, //120...155cm
									   0,5,0,5,0,5,0,5,	//160...195cm
									   0,10}; //200...troche ponad 200								
 
unsigned char digits[11] = {
 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF)),
 ((1<<LEDB)|(1<<LEDC)),
 ((1<<LEDA)|(1<<LEDB)|(1<<LEDD)|(1<<LEDE)|(1<<LEDG)),
 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDG)),
 ((1<<LEDB)|(1<<LEDC)|(1<<LEDF)|(1<<LEDG)),
 ((1<<LEDA)|(1<<LEDC)|(1<<LEDD)|(1<<LEDF)|(1<<LEDG)),
 ((1<<LEDA)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG)),
 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)),
 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG)),
 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDF)|(1<<LEDG)),
 (1<<LEDG)	//kreska pozioma
};
 
unsigned char DisplayedChar[2];
unsigned char Com[2] = {~(1<<COM1),~(1<<COM2)};
 
//
//############################################################
//
 
//-------------------------
//
// procedura wysyłania paczki ultradźwięków
//
//-------------------------
int sygnal(void)		
{
	int echos=0;			// zmienna do bliczenia powrotu ultradźwięków
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
	sinus_40_khz();
 
	// teraz trzeba wytłumić drgania przetwornika zwierając go do masy
	cbi(ultrasonic_pinA_port,ultrasonic_pinA_pin);
	cbi(ultrasonic_pinB_port,ultrasonic_pinB_pin);
	delay(8);
 
	// przetwornik wejściowy też zwieramy do masy w celu wytłumienia
	sbi(DDRD,PD6);
	cbi(PORTD,PD6);
	delay(8);
 
	cbi(DDRD,PD6);					// no i można go włączyć
	for(echos=0;echos<2500;echos++)	// i czekać na odbite dźwięki
	{
		if(bit_is_set(ACSR,ACO))	// jeżeli bit ACO rejestru ACSR ustawiony
		{
			break;					// to przerwij
		}
	}
	return echos;					// zwróć wartość zmiennej
}
//-------------------------
//
// procedura sygnału 40kHz
//
//-------------------------	
void sinus_40_khz(void)	
{
	sbi(ultrasonic_pinA_DDR,ultrasonic_pinA_pin);sbi(ultrasonic_pinA_port,ultrasonic_pinA_pin);
	sbi(ultrasonic_pinB_DDR,ultrasonic_pinB_pin);cbi(ultrasonic_pinB_port,ultrasonic_pinB_pin);
 
	asm volatile("WDR"::);  //watchdog reset, czyli nic nie rób.
	asm volatile("WDR"::);
	asm volatile("WDR"::);
	asm volatile("WDR"::);
	cbi(ultrasonic_pinA_port,ultrasonic_pinA_pin);
	sbi(ultrasonic_pinB_port,ultrasonic_pinB_pin);
 
	asm volatile("WDR"::);
	asm volatile("WDR"::);
}	
//-----------------------------------------------------
//
// procedura wyswietlajaca wynik na wyswietlaczach LED
//
//-----------------------------------------------------
void result(void)
{
idx = 0;
	while(distance > TicksNo[idx])
		idx++;
 
	if(idx>41)	//wieksza odleglosc niz 2m z hakiem
	{
		DisplayedChar[0]=0;
		DisplayedChar[1]=0;
		_delay_loop_2(wait);
	}
	else //w mierzonym zakresie
	{
	DisplayedChar[0]=digits[DisplayChars0[idx]];
	DisplayedChar[1]=digits[DisplayChars1[idx]];
	if(idx>19 && idx<40) //miedzy 1m a 2m
		DisplayedChar[0] = DisplayedChar[0] | mdp; //dodaj kropke
	if(idx==40) // 2m
		DisplayedChar[1] = DisplayedChar[1] | mdp; //dodaj kropke
 
	_delay_loop_2(wait);
	}
 
}
 
//-----------------------------------------------------
//
// MAIN
//
//-----------------------------------------------------
int main(void)
{
	//inicjalizacja i2c - na razie nie uzywana...
	i2cInit();
	i2cSetBitrate(10);
 
 
	sbi(DDRD,PD7);
	cbi(PORTD,PD7);
 
	LEDDDR=0xff;
	COMDDR=((1<<COM1)|(1<<COM2));
		TCCR0 = 1<<CS01|1<<CS00;//preskaler 64//
		TIMSK = 1<<TOIE0;
		sei();
	for(;;)
	{
		distance = sygnal();
		result();
	}
	return(0);
}
 
 
//-----------------------------------------------------
//
// PRZERWANIE
//
//-----------------------------------------------------
SIGNAL(SIG_OVERFLOW0)
{
	static int ActiveDisplay = 0;
	TCNT0=128;
	COMPORT &= ~(1<<COM1 | 1<<COM2);			///zerowanie wyswietlacza
	LEDPORT = DisplayedChar[ActiveDisplay];	///wysylanie znaku
	COMPORT |= (Com[ActiveDisplay]);				///wlaczenie wyswietlacza
	++ActiveDisplay;							/// wlaczanie kolejnego wyswietlacza
	if(ActiveDisplay > 1)
		{
		ActiveDisplay = 0; 		
		}	
}


Plik sonar.h:

//najpierw pin do którego podłączamy pierwszy kabelek
#define speaker_pinA_port PORTC
#define speaker_pinA_pin  PC4
#define speaker_pinA_DDR  DDRC
//pin kabelka 2
#define speaker_pinB_port PORTC
#define speaker_pinB_pin  PC5
#define speaker_pinB_DDR  DDRC
// definicja ultradzwiekowego nadajnika
#define ultrasonic_pinA_port PORTD
#define ultrasonic_pinA_pin PD0
#define ultrasonic_pinA_DDR DDRD
//drugi pin
#define ultrasonic_pinB_port PORTD
#define ultrasonic_pinB_pin PD1
#define ultrasonic_pinB_DDR DDRD
//diody//
#define LED4_ON  sbi(DDRD,PD5);sbi(PORTD,PD5);
#define LED4_OFF sbi(DDRD,PD5);cbi(PORTD,PD5);
 
#define LED3_ON  sbi(DDRD,PD4);sbi(PORTD,PD4);
#define LED3_OFF sbi(DDRD,PD4);cbi(PORTD,PD4);
 
#define LED2_ON  sbi(DDRD,PD3);sbi(PORTD,PD3);
#define LED2_OFF sbi(DDRD,PD3);cbi(PORTD,PD3);
 
#define LED1_ON  sbi(DDRD,PD2);sbi(PORTD,PD2);
#define LED1_OFF sbi(DDRD,PD2);cbi(PORTD,PD2);
 
// Procedury opóźnień czasowych
 
#define CYCLES_PER_US ((1000000+500000)/1000000)
 
void delay(unsigned int us)
{
	unsigned int delay_loops;
	register unsigned int i;
	delay_loops=((us+3)/5*CYCLES_PER_US)*10;
	for(i=0;i<delay_loops;i++){};
}
 
void delayms(unsigned int ms)
{
	unsigned int i;
	for(i=0;i<ms;i++)
	{
		delay(999);
		asm volatile("WDR"::);
	}
}
//prototypy funkcji i procedur
void delay(unsigned int us);
void delayms(unsigned int ms);
 
int sygnal(void);
void sinus_40_khz(void);


Plik znaki.h:

/////////////////////////////////////////////////////
////////Definicje polączenia wyświetlaczy 7 segm/////
////////i definicje znaków wyswietlanych/////////////
////////ZDEFINIOWANE ZNAKI://////////////////////////
///0-9; a,b,c,d,e,f,h,i,j,l,n,o,p,r,u////////////////
/////////////////////////////////////////////////////
 
///definicje klawiszy///
#define SWPORT PORTC
#define SWDDR DDRC
#define SWPIN PINC
#define SW1 2
#define SW2 3
 
////definicje podłączonych segmentów/////
#define LEDPORT PORTB
#define LEDDDR DDRB
#define LEDA 2
#define LEDB 1
#define LEDC 7
#define LEDD 0
#define LEDE 5
#define LEDF 3
#define LEDG 4
#define LED_DP 6
////definicje podłączonych wspólnych anod////
#define COMPORT PORTC
#define COMDDR  DDRC
#define COM1 0
#define COM2 1
////definicje znaków wyświetlanych na wyświetlaczu////
 
#define mnul 0;//kasowanie wyswietlacza//
#define m0 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF));
#define m1 ((1<<LEDB)|(1<<LEDC));
#define m2 ((1<<LEDA)|(1<<LEDB)|(1<<LEDD)|(1<<LEDE)|(1<<LEDG));
#define m3 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDG));
#define m4 ((1<<LEDB)|(1<<LEDC)|(1<<LEDF)|(1<<LEDG));
#define m5 ((1<<LEDA)|(1<<LEDC)|(1<<LEDD)|(1<<LEDF)|(1<<LEDG));
#define m6 ((1<<LEDA)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define m7 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC));
#define m8 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define m9 ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDF)|(1<<LEDG));
#define mdip (1<<LEDG); // myslnik//
#define mdp (1<<LED_DP); //kropka//
#define mA ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define mB ((1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define mC ((1<<LEDD)|(1<<LEDE)|(1<<LEDG));
#define mD ((1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDG));
#define mE ((1<<LEDA)|(1<<LEDD)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define mF ((1<<LEDA)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define mH ((1<<LEDC)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define mI ((1<<LEDE)|(1<<LEDF));
#define mJ ((1<<LEDA)|(1<<LEDB)|(1<<LEDC)|(1<<LEDD)|(1<<LEDE));
#define mL ((1<<LEDD)|(1<<LEDE)|(1<<LEDF));
#define mN ((1<<LEDC)|(1<<LEDE)|(1<<LEDG));
#define mO ((1<<LEDC)|(1<<LEDD)|(1<<LEDE)|(1<<LEDG));
#define mP ((1<<LEDA)|(1<<LEDB)|(1<<LEDE)|(1<<LEDF)|(1<<LEDG));
#define mR ((1<<LEDE)|(1<<LEDG));
#define mU ((1<<LEDC)|(1<<LEDD)|(1<<LEDE));

Materiały

Ponownie zamieszczam - tym razem w jednym miejscu - kod źródłowy oraz projekt w Eagle.
1) nxtsensor_avrstudio_projekt.rar
2) nxtsensor_eagle_projekt.rar

TODO - Materiały, linki

Poniżej zamieszczam materiały i linki, które znalazłem, a które mogą się przydać osobom pragnącym kontynuować projekt.

1)Dokumentacja biblioteki Procyon AVRlib pod mikrokontrolery Atmegi obejmująca między innymi komunikację przez I2C.
2)Strona skąd można pobrać bibliotekę Procyon AVRlib gdyż link na stronie oficjalnej nie działa.
3)Przykład użycia powyższej biblioteki (Procyon AVRlib).
4)IDE do pisania programów w NXC (not exactly C) dla Bricka NXT.
5)IDE do pisania programów w C pod mikrokontrolery Atmega.
6)PonyProg - darmowy programator dla Atmegi.
7)Przykładowy projekt własnego czujnika komunikującego się z NXT przez I2C.
8)Wątek na oficjalnym forum NXT dotyczący prób komunikacji NXT z mikrokontrolerami przy użyciu I2C.
9)Strona lego mindstorms.
10)Dokumentacja techniczna NXT.
11)Dokumentacja I2C zaimplementowanego w NXT.
12)Wątek na forum dot. prób komunikacji Atmegi z NXT przez I2C wraz z __załączonym kodem__ który teoretycznie powinien działać, ale nie działa....
13)Strona z wyszukiwarką "datasheet'ów" układów scalonych.
14)Firma 1 gdzie można zamówić wykonanie profesjonalnej płytki PCB.
15)Firma 2 gdzie można zamówić wykonanie profesjonalnej płytki PCB.
16)Sklep 1.
17)Sklep 2.
18)Dokumentacja Atmega8.
19)Schemat komercyjnie sprzedawanego czujnika odległości.
20)NXT na wiki (patrz sekcja 'Connector').