PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Roboter mit J2ME-Handy steuern



radbruch
08.09.2010, 23:45
Hallo

Ich bin inzwischen stolzer Besitzer eines Samsung GT-S5620 (Monte) (http://www.samsungmobile.de/samsung-handy/samsung-s5620) und versuche jetzt, das Teil "sinnvoll" zu nutzen. Für einen guten Ansatz halte ich dabei den Versuch von wolfgangI das Display des Handys als Schnittstelle zu verwenden:

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=52064
(Displaysensor: https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=468332)

Erstaunlich, was die ScriptKids alles können. Ich kenne Java leider überhaupt nicht. Nach zähem googlen bin ich auf einen anderen handygesteuerten Roboter gestossen:

http://www.robohobby.com/index_de.jsp

Alles gut erklärt und dokumentiert (http://www.robohobby.com/run_java_me_code_examples.jsp), aber ich scheitere schon bei der Installation der Java-Umgebung. Irgendwelche Referenzen stimmen nicht, das kann ja heiter werden ;)

Das sollte das Monte auch können. Mit zwei Kameras, WiFi und MIDP 2.0 scheint es mir eine taugliche Plattform zu sein. Allerdings ist der Einstieg ziemlich zäh. Ziel ist ein Websever auf dem Handy, der über eine Browseroberfläche gesteuert wird und das Bild streamen soll. Der Weg dahin ist aber sehr weit und steinig...

Ein erster kleiner Erfolg ist eine Webcamfunktion, die ich hier gefunden habe: http://www.mobile-mir.com/en/MobileWebCam.php

Das Monte sendet über WiFi in einstellbaren Intervallen einen Schnappschuss. Empfänger ist ein Serverscript auf einem Webserver:

http://tinyurl.com/radbruchcam

Vielleicht habt ihr ein paar Tipps oder Anregungen?

Gruß

mic

radbruch
10.09.2010, 22:02
Hallo

Nach gefühlten 100000 Mausklicks hab' ich nun das nötigste zusammen:

http://i1.ytimg.com/vi/xY1UIcGEu7o/3.jpg (http://www.youtube.com/watch?v=xY1UIcGEu7o)
http://www.youtube.com/watch?v=xY1UIcGEu7o

Neben dem Java SDK (http://www.oracle.com/technetwork/java/javase/downloads/jdk6-jsp-136632.html)(32Bit) benötigte ich nur noch das SDK des Herstellers (http://innovator.samsungmobile.com/down/cnts/toolSDK.detail.view.do?platformId=3&cntsId=7500) (, welches netterweise mein Monte direkt unterstützt,) und schon klappt es mit NetBeans (http://netbeans.org/downloads/start.html?platform=windows&lang=en&option=java) :)

Ich hatte massive Probleme beim Installieren des Java ME 3.0 SDK. Das lies sich erst installieren, nachdem ich die 32Bit-Version des Java SDK installiert hatte. Irgendwie scheint die 64Bit-Variante mit meinem AMD unverträglich. Ach, ist das alles kompliziert.

Gruß

mic

radbruch
20.09.2010, 00:16
Hallo

Das Display als Schnittstelle habe ich inzwischen verworfen. So einen hübschen 240x400-Touchscreen sollte man sinnvoller nutzen ;) Mein neuer Ansatz: Der Kopfhöhrerausgang steuert ein Servo.

Weil man in Java scheinbar keine Ports oder Pins mehr kennt, muss ich die Aufgabe irgendwie mit gelenkten Datenströmen lösen. Datenquelle ist eine Wav-Datei. Inhalt dieser Wav-Datei ist ein PWM-Signal mit 50Hz und ca. 1:20 Puls:Pause Verhältniss. Quasi ein Servosignal auf Band.

Die "Hardware" ist eine kleine Verstärkerschaltung mit einem NPN-Transistor (http://www.radiovilag.hu/images/BC546_50.pdf) als Verstärker und einem 7404 (http://pdf1.alldatasheet.com/datasheet-pdf/view/27356/TI/SN74LS04N.html) als Signalformer. Mit dieser "Zu Fuss"-Elektronik kenne ich mich allerdings überhaupt nicht aus. Das Zwischenergebniss sieht nun so aus:

http://i4.ytimg.com/vi/CaVxa6zH2bI/2.jpg (http://www.youtube.com/watch?v=CaVxa6zH2bI) http://i4.ytimg.com/vi/3FbgwJg-btw/2.jpg (http://www.youtube.com/watch?v=3FbgwJg-btw)
http://www.youtube.com/watch?v=CaVxa6zH2bI
http://www.youtube.com/watch?v=3FbgwJg-btw


Der Verstärker ist eine stablilsierte Emitterschaltung (http://loetstelle.net/grundlagen/transistor/transistor3.php). Der Arbeitspunkt des Transistors knapp über dem Schaltpunkt des 7404 wird mit einem 39K Widerstand in Reihe zu einem 100K-Poti eingestellt. Kollektorwiderstand ist ein 1k, Emitterwiderstand fehlt. Ein 3,3µF-Elko koppelt das Signal ein, der 7404 invertiert es erneut und gibt es direkt weiter zum Servo. Software im Monte ist der eingebaute Wav-Player.

Es gibt noch viel zu erforschen ;)

Gruß

mic

btw: Das Oszi ist ein Tektronics 222 (http://www.teknetelectronics.com/Search.asp?p_ID=18583) aus meinem Fundus. Blöderweise habe ich seit zwei Wochen keine echte serielle Schnittstelle mehr.... *grummel*

radbruch
22.09.2010, 16:50
Hallo

Adapter fertig, kleines Fahrwerk zusammengebastelt, es geht voran:

http://i3.ytimg.com/vi/bm9Udc27jQA/2.jpg (http://www.youtube.com/watch?v=bm9Udc27jQA)
http://www.youtube.com/watch?v=bm9Udc27jQA

Softwaremässig siehts leider noch etwas mau aus.

Gruß

mic

Thomas$
22.09.2010, 16:52
tolle sache
wenn ich mir die rechenleistung von einigen handys ansehe ist das echt verschwendung für die meisten anwendungen
die handys gehören in roboter ;-)

-schumi-
22.09.2010, 17:06
Au ja, das Handy meines kleiner Bruders hat einen schnelleren Prozessor als der Laptop an dem ich gerade sitze! (zugegeben, 700 mhz is nich viel^^)

In dem Video bewegen sich die 2 Servos (sind es überhaupt 2?) immer gleich. Mit Stereo-musik könntest du ja 2 unabhängig voneinander Steuern. Kann man mit Java auch das Mikrofon benutzen? Dann könnte man auch Daten zum Handy schicken...

MfG
-schumi-

Philsuro
23.09.2010, 17:55
geht das auch mit dem n97?

radbruch
15.10.2010, 16:34
Hallo

Weil das Projekt grad etwas durchhängt schildere ich mal, was bisher geht. Natürlich war der Grundgedanke das Stereosignal zu nutzen um beide Servo getrennt anzusteuern. Blöderweise habe ich aber kein (kostenloses) Programm gefunden mit dem man die Signalform brauchbar in Stereo generieren kann. Ich habe deshalb die Monosignale mit Audacity bearbeitet und zusammengeschnitten. Für die Funktionen vor, zurück und stop habe ich für beide Servos zusammen jeweils kurze Waves mit den wichtigsten Kombinationen erzeugt (Anhang). Testweise kann ich mit diesen Tondateien das Fahrwerk auch direkt am Kopfhörerausgang meines PCs betreiben;)

Als Java-Laie habe ich mir fürs Monte aus verschiedenen Codeschnippseln ein kleines Programm zusammengeklickt. Ausgangsbasis war das kleine PatchyMIDlet (http://www.java2s.com/Code/Java/J2ME/PatchyMIDlet.htm). Es zeigt, wie man quick&dirty eine Socketverbindung aufbaut und ankommende Browseranfragen auswertet und beantwortet. Im Orginalzustand "überliest" das PatchyMIDlet aber die Daten die der Browser sendet und antwortet nur mit der Empfangsquittung und einem zufällig ausgewählten String. In der Praxis gibt man die IP des Monte als URL im Browser des PCs ein und sieht dann den Satz oben im Browserfenster. Prima.

Nun zu meinen Erweiterung des PatchMIDlet. Ein Browser sendet bei einer Anfrage eine Menge Daten zum Server, unter anderem auch die aufgerufene URL. Diese lese ich aus dem Datenstrom und suche alles, was hinter http://handy-ip/ eingegeben wurde. Diesen "Anhang" an die URL (normalerweise der Pfad zur angeforderten Datei auf einem Webserver) interpretiere ich als Kommando und ordne einen Dateinamen meiner Servo-WAVs zu. Dann sende ich dem Browser eine kleine HTML-Seite mit einer kleinen Link-Tabelle. Die Links sind dabei die Handy-IP mit passendem Anhang, also z.B. handy-ip/1, handy-ip/2... Der Einfachheit halber im Moment nur einziffrige Befehle:


<html><head><title>Robotersteuerung mit J2ME-Handy</title></head><body>Kommando:
<table><tr><td>Test2 (1>Test1</a></td><td><a)</td><td>Test4 (3>Test3</a></td></tr><tr><td><a)</td><td>Test6 (5>Test5</a></td><td><a)</td></tr><tr><td>Test8 (7>Test7</a></td><td><a)</td><td>Test0 (9>Test9</a></td></tr><tr><td></td><td><a)</td><td></td></tr></table>
</body></html>

Zusätzlich habe ich einen kleinen Audioplayer ergänzt. Die mit dem Kommando ausgewählte Wav-Datei wird dann am Kopfhöhrerausgang ausgegeben und das Fahrwerk bewegt sich dem Mausklick entsprechend. Leider sind die WAVs etwas zu kurz, deshalb, und weil der Adapter noch nicht gut funktioniert, ist das Video langweilig. Ich zeige es nur, weil es eben existiert:

http://i4.ytimg.com/vi/kkArTA0t6cY/2.jpg (http://www.youtube.com/watch?v=kkArTA0t6cY)
http://www.youtube.com/watch?v=kkArTA0t6cY

Die WAVs werden übrigens direkt in das Java-Programm eingebunden. Die Java-Syntax ist der von C sehr ähnlich. Das Programm dazu sieht so aus:


/*
Wireless Java 2nd edition
Jonathan Knudsen
Publisher: Apress
ISBN: 1590590775
*/
import java.io.*;

import javax.microedition.io.*;
//import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
//import javax.microedition.pki.*;
import javax.microedition.io.SocketConnection;
import javax.microedition.io.ServerSocketConnection;
//import javax.microedition.io.UDPDatagramConnection;

//import java.io.InputStream;

//import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
//import javax.microedition.lcdui.List;
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.midlet.MIDlet;

public class PatchyMIDlet extends MIDlet implements CommandListener, Runnable {

private Display mDisplay;
private Form mForm;

private ServerSocketConnection mServerSocketConnection;
private boolean mTrucking = true;
private String line;

public void startApp() {
mDisplay = Display.getDisplay(this);

if (mForm == null) {
mForm = new Form("PatchyMIDlet");

mForm.addCommand(new Command("Exit", Command.EXIT, 0));
mForm.setCommandListener(this);
}

Thread t = new Thread(this);
t.start();

mDisplay.setCurrent(mForm);
}

public void pauseApp() {}

public void destroyApp(boolean unconditional) { shutdown(); }

private void log(String text) { log(null, text); }

private void log(String label, String text) {
StringItem si = new StringItem(label, text);
//si.setLayout(Item.LAYOUT_NEWLINE_AFTER);
mForm.append(si);
}

private void shutdown() {
mTrucking = false;
try { mServerSocketConnection.close(); }
catch (IOException ioe) {}
}

public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT) {
shutdown();
notifyDestroyed();
}
}

public void run() {
try {
mServerSocketConnection = (ServerSocketConnection)
Connector.open("socket://:80");
log("Startup complete.");
SocketConnection sc = null;
while (mTrucking) {
sc = (SocketConnection)
mServerSocketConnection.acceptAndOpen();
log("client: ", sc.getAddress());
//log("Test: ", sc.getLocalAddress());
// Strictly speaking, each client connection
// should be handled in its own thread. For
// simplicity, this implementation handles
// client connections inline.
Reader in = new InputStreamReader(
sc.openInputStream());
String dummy_line;
String erste_line="";
String Kommando;
while ((dummy_line = readLine(in)) != null) if(erste_line.equals("")) erste_line=dummy_line;
// Ignoring the request, send a response.
Kommando=erste_line.substring(5,6);
PrintStream out = new PrintStream(sc.openOutputStream());
out.print("HTTP/1.1 200 OK\r\n\r\n");
//out.print(getMessage());
out.print("<html><head><title>Robotersteuerung mit J2ME-Handy</title>");
out.print("</head><body>");
out.print("Kommando: ");
out.print(Kommando);
log(Kommando);
out.print("
<table><tr><td><a href=1>Test1</a></td>");
out.print("<td><a href=2>Test2</a></td>");
out.print("<td><a href=3>Test3</a></td></tr>");
out.print("<tr><td><a href=4>Test4</a></td>");
out.print("<td><a href=5>Test5</a></td>");
out.print("<td><a href=6>Test6</a></td></tr>");
out.print("<tr><td><a href=7>Test7</a></td>");
out.print("<td><a href=8>Test8</a></td>");
out.print("<td><a href=9>Test9</a></td></tr>");
out.print("<tr><td></td><td><a href=0>Test0</a></td><td></td>");
out.print("</tr></table>
");
//out.print(erste_line);
out.print("");
out.print("");
out.print("");
out.print("");
out.print("</body></html>");
out.close();
in.close();
sc.close();
//playFromResource("/"+Kommando+".wav");
if(Kommando.equals("1")) playFromResource("/servo-4ms-r.wav");
if(Kommando.equals("2")) playFromResource("/servo-4ms.wav");
if(Kommando.equals("3")) playFromResource("/servo-4ms-l.wav");
//if(Kommando.equals("4")) playFromResource("/4.wav");
//if(Kommando.equals("5")) playFromResource("/5.wav");
//if(Kommando.equals("6")) playFromResource("/6.wav");
//if(Kommando.equals("7")) playFromResource("/7.wav");
if(Kommando.equals("8")) playFromResource("/servo-10ms.wav");
//if(Kommando.equals("9")) playFromResource("/9.wav");
if(Kommando.equals("0")) playFromResource("/1ms_lang.wav");
}
}
catch (Exception e) {
log("exception: ", e.toString());
}
}
private String readLine(Reader in) throws IOException {
// This is not efficient.
StringBuffer temp_line = new StringBuffer();
int i;
while ((i = in.read()) != -1) {
char c = (char)i;
if (c == '\n') break;
if (c == '\r') ;
else temp_line.append(c);
}
if (temp_line.length() == 0) return null;
//log(line.toString());
return temp_line.toString();
}

private java.util.Random mRandom = new java.util.Random();

private String getMessage() {
int i = Math.abs(mRandom.nextInt()) % 5;
String s = null;
switch (i) {
case 0: s = "Above all the others we'll fly"; break;
case 1: s = "There is no reason to hide"; break;
case 2: s = "I dreamed about Ray Charles last night"; break;
case 3: s = "Someone keeps moving my chair"; break;
case 4: s = "Joseph's face was black as night"; break;
default: break;
}
return s;
}

private void playFromResource(String wavedatei) {
try {
InputStream in = getClass().getResourceAsStream(wavedatei);
Player player = Manager.createPlayer(in, "audio/x-wav");
player.start();
} catch (Exception e) {
log("exception: ", e.toString());
return;
}
}
}

/*
public void paint(Graphics g) {
((Graphics2D)g).setRenderingHint
(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.green);
g.drawLine(20, 20, 40, 140);
g.setColor(Color.blue);
g.fillOval(50, 110, 120, 60);
g.setColor(Color.red);
g.setFont(new Font("Serif", Font.ITALIC, 36));
g.drawString("Cellini", 40, 80);
}
*/



Gruß

mic

Toubs
29.05.2011, 20:12
wie hast du die töne in audacity gemacht?

radbruch
29.05.2011, 20:18
Ab einer gewissen Zoomstufe (erkennbar an den vielen kleinen Punkten in der Darstellung) kann man den Kurvenverlauf direkt mit der Maus zusammenklicken. Zuerst wird eine einzelne 20ms-Periode mit der gewünschten Impulsdauer erstellt und diese dann vervielfältigt.

Toubs
29.05.2011, 20:24
danke! :-D