The source code of all examples can be downloaded from here. |
Data transmission with Bluetooth |
For data exchange between two Raspberry Pi's or a Raspberry Pi and a computer or smartphone, the Bluetooth protocol is often a good choice. It may be simpler than using TCP/ IP, because no TCP-network (WLAN, router) is needed. Some application proposals are:
The latest version of the NOOPs distribution supports the built-in Bluetooth chip of the Raspberry model 3 and of the Raspberry ZeroW as well as most USB Bluetooth dongles on the Raspberry Pi model 2. The current version of the RaspiBrick firmware downloaded from here is based on this operating system version. On startup, Bluetooth is activated and placed in Discovery Mode. An external device recognizes the Raspberry Pi with the Bluetooth friendly name raspberrypi and can pair without authentication. On the other hand, the Raspberry Pi can connect itself to a visible external Bluetooth device without pairing. As with TCP/IP, data transmission is performed using the client/server technology. It is important to know that the communication partners, the server and client are not symmetric. First the server program has to be started and only then a client can establish a connection. Python 2.7 Bluetooth library (inkl Doc), Doc online |
Experiment 1: Bluetooth Echo Client/Server |
Aim: Program at the Raspberry Pi:[►] # BtEchoServer.py from btpycom import * def onStateChanged(state, msg): if state == "LISTENING": print "Server is listening" elif state == "CONNECTED": print "Connection established to", msg elif state == "MESSAGE": print "Got message", msg server.sendMessage(msg) serviceName = "EchoServer" server = BTServer(serviceName, stateChanged = onStateChanged) Remarks: Program:[►] # BtEchoClient.py from btcom import * # TigerJython from btpycom import * # Standard-Python (PC, Raspi, ...) def onStateChanged(state, msg): global reply if state == "CONNECTING": print "Connecting", msg elif state == "CONNECTION_FAILED": print "Connection failed", msg elif state == "CONNECTED": print "Connected", msg elif state == "DISCONNECTED": print "Disconnected", msg elif state == "MESSAGE": print "Message", msg reply = msg serviceName = "EchoServer" print "Performing search for service name", serviceName client = BTClient(stateChanged = onStateChanged) serverInfo = client.findService(serviceName, 20) if serverInfo == None: print "Service search failed" else: print "Got server info", serverInfo if client.connect(serverInfo, 20): for n in range(0, 101): client.sendMessage(str(n)) reply = "" while reply == "": time.sleep(0.001) client.disconnect() Remarks: Performing search for service name EchoServer Instead of searching with the given Bluetooth service name, the Bluetooth server name can be used: client.findServer("raspberrypi", 20) If the Bluetooth MAC address is known (e.g. by a previous Bluetooth search result), the serverInfo can be hard-coded: serverInfo = ("B8:27:EB:04:A6:7E", 1) This greatly decreases the connection delay. |
Experiment 2: Remote-Guided Rover |
Aim: Program at the Raspberry Pi:[►] # BTRover.py import RPi.GPIO as GPIO from btpycom import * def onStateChanged(state, msg): if state == "LISTENING": print "Waiting for connecting controller..." stop() elif state == "CONNECTED": print "Connection to", msg, "established" elif state == "MESSAGE": print "Got command:", msg if msg == "FORWARD": forward() elif msg == "BACKWARD": backward() elif msg == "STOP": stop() elif msg == "LEFT": left() elif msg == "RIGHT": right() # adapt to your rover P_MOTA1 = 40 # right motor P_MOTA2 = 38 # right motor P_MOTB1 = 36 # left motor P_MOTB2 = 32 # left motor def forward(): GPIO.output(P_MOTA1, GPIO.HIGH) GPIO.output(P_MOTA2, GPIO.LOW) GPIO.output(P_MOTB1, GPIO.HIGH) GPIO.output(P_MOTB2, GPIO.LOW) def backward(): GPIO.output(P_MOTA1, GPIO.LOW) GPIO.output(P_MOTA2, GPIO.HIGH) GPIO.output(P_MOTB1, GPIO.LOW) GPIO.output(P_MOTB2, GPIO.HIGH) def left(): GPIO.output(P_MOTA1, GPIO.HIGH) GPIO.output(P_MOTA2, GPIO.LOW) GPIO.output(P_MOTB1, GPIO.LOW) GPIO.output(P_MOTB2, GPIO.HIGH) def right(): GPIO.output(P_MOTA1, GPIO.LOW) GPIO.output(P_MOTA2, GPIO.HIGH) GPIO.output(P_MOTB1, GPIO.HIGH) GPIO.output(P_MOTB2, GPIO.LOW) def stop(): GPIO.output(P_MOTA1, GPIO.LOW) GPIO.output(P_MOTA2, GPIO.LOW) GPIO.output(P_MOTB1, GPIO.LOW) GPIO.output(P_MOTB2, GPIO.LOW) def setup(): GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) GPIO.setup(P_MOTA1, GPIO.OUT) GPIO.setup(P_MOTA2, GPIO.OUT) GPIO.setup(P_MOTB1, GPIO.OUT) GPIO.setup(P_MOTB2, GPIO.OUT) setup() serviceName = "BTRover" BTServer(serviceName, stateChanged = onStateChanged) Remarks:
Program:[►] # RoverControl.py # TigerJython from entrydialog import * from btcom import * def showDialog(): global dlg, buttons buttons = [ButtonEntry("Left"), ButtonEntry("Forward"), ButtonEntry("Stop"), ButtonEntry("Backward"), ButtonEntry("Right")] pane = EntryPane(buttons[0], buttons[1], buttons[2], buttons[3], buttons[4]) dlg = EntryDialog(pane) dlg.setTitle("Remote Control") dlg.show() showDialog() commands = ["LEFT", "FORWARD", "STOP", "BACKWARD", "RIGHT"] def onStateChanged(state, msg): pass serviceName = "BTRover" client = BTClient(stateChanged = onStateChanged) dlg.setTitle("Searching for rover. Please wait...") serverInfo = client.findService(serviceName, 30) if serverInfo == None: dlg.setTitle("Rover not found") else: if client.connect(serverInfo, 20): dlg.setTitle("Connected to " + serverInfo[0]) while not dlg.isDisposed(): for n in range(len(buttons)): if buttons[n].isTouched(): client.sendMessage(commands[n]) client.disconnect() Remarks: |
Experiment 3: Speed control with Android app |
Aim: Program at the Raspberry Pi:[►] # BTRover1.py import RPi.GPIO as GPIO from btpycom import * def onStateChanged(state, msg): global speed if state == "LISTENING": print "Waiting for connecting controller..." stop() elif state == "CONNECTED": print "Connection to", msg, "established" elif state == "MESSAGE": print "Got command:", msg if msg == "FASTER": if speed < 100: speed += 10 if speed > 0: forward(speed) else: backward(-speed) elif msg == "SLOWER": if speed > -100: speed -= 10 if speed > 0: forward(speed) else: backward(-speed) elif msg == "STOP": speed = 0 stop() elif msg == "LEFT": left(30) elif msg == "RIGHT": right(30) P_MOTA1 = 40 P_MOTA2 = 38 P_MOTB1 = 36 P_MOTB2 = 32 fPWM = 60 # Hz def setup(): global pwm_a1, pwm_a2, pwm_b1, pwm_b2 GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) GPIO.setup(P_MOTA1, GPIO.OUT) pwm_a1 = GPIO.PWM(P_MOTA1, fPWM) pwm_a1.start(0) GPIO.setup(P_MOTA2, GPIO.OUT) pwm_a2 = GPIO.PWM(P_MOTA2, fPWM) pwm_a2.start(0) GPIO.setup(P_MOTB1, GPIO.OUT) pwm_b1 = GPIO.PWM(P_MOTB1, fPWM) pwm_b1.start(0) GPIO.setup(P_MOTB2, GPIO.OUT) pwm_b2 = GPIO.PWM(P_MOTB2, fPWM) pwm_b2.start(0) def stop(): forward(0) def forward(speed): pwm_a1.ChangeDutyCycle(speed) pwm_a2.ChangeDutyCycle(0) pwm_b1.ChangeDutyCycle(speed) pwm_b2.ChangeDutyCycle(0) def left(speed): pwm_a1.ChangeDutyCycle(speed) pwm_a2.ChangeDutyCycle(0) pwm_b1.ChangeDutyCycle(0) pwm_b2.ChangeDutyCycle(speed) def right(speed): pwm_a1.ChangeDutyCycle(0) pwm_a2.ChangeDutyCycle(speed) pwm_b1.ChangeDutyCycle(speed) pwm_b2.ChangeDutyCycle(0) def backward(speed): pwm_a2.ChangeDutyCycle(speed) pwm_a1.ChangeDutyCycle(0) pwm_b2.ChangeDutyCycle(speed) pwm_b1.ChangeDutyCycle(0) speed = 0 setup() serviceName = "BTRover" BTServer(serviceName, stateChanged = onStateChanged) Remarks: Open source in Online-Compiler. Program:[►] // RoverControlApp.java package rovercontrol.app; import ch.aplu.android.*; import android.graphics.Color; import android.bluetooth.*; import ch.aplu.android.bluetooth.*; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; public class RoverControlApp extends GameGrid implements GGPushButtonListener { private GGPushButton faster; private GGPushButton slower; private GGPushButton left; private GGPushButton right; private GGPushButton stop; private GGTextField tf; private BluetoothClient bc; private DataInputStream dis; private DataOutputStream dos; public RoverControlApp() { super(21, 21, 0); setScreenOrientation(PORTRAIT); } public void main() { String serverName = askName(); getBg().clear(Color.BLUE); new GGTextField("Rover Control App", new Location(0, 1), true).show(); addButtons(); tf = new GGTextField("Trying to connect...", new Location(4, 19), true); tf.show(); // Search device BluetoothDevice serverDevice = searchDevice(serverName); if (serverDevice != null) { bc = new BluetoothClient(serverDevice); boolean rc = bc.connect(); if (!rc) { tf.hide(); tf = new GGTextField("Connection failed", new Location(4, 19), true); tf.show(); return; } tf.hide(); tf = new GGTextField("Connection established", new Location(3, 19), true); tf.show(); dis = new DataInputStream(bc.getInputStream()); dos = new DataOutputStream(bc.getOutputStream()); enableButtons(); } } private String askName() { GGPreferences prefs = new GGPreferences(this); String oldName = prefs.retrieveString("BluetoothName"); String newName = null; while (newName == null || newName.equals("")) { newName = GGInputDialog.show(this, "Rover Control App", Remarks: |