Now that you have keyboard control of your cyber:bot working with a USB tether, it's time to take the app wireless!
The transmitter and receiver scripts we will use may be familiar. They are in the Send and Receive Packets [1] activity; it’s the second one in the Cybersecurity: Radio Data [2] tutorial. Each script will get parts of the tethered script added, and some adjustments to make it all work.
Let's build on experience, and adapt a familiar script from a previous tutorial to use keyboard inputs.
Starting with the countdown_sender script from the Send and Receive Packets [1] activity, you can replace its input statements with the ones from terminal_controlled_bot_tethered_try_this. Then, the dictionary that’s created has to be adjusted to contain the vL, vR, and ms keys and values. That’s the most crucial part of incorporating the terminal-in, radio-out part of your tethered app into script that wirelessly transmits.
This animated GIF shows the script being modified:
You will also need to make a few other adjustments. Here they are, step-by-step:
vL = int(input("Enter left speed: ")) vR = int(input("Enter right speed: ")) ms = int(input("Enter ms to run: "))
text = input("Enter countdown start: ") value = int(text) message = input("Enter message after countdown: ")
dictionary['start'] = value dictionary['after'] = message
dictionary['vL'] = vL dictionary['vR'] = vR dictionary['ms'] = ms
print("Countdown App") print("micro:bit sender")
Replace them with this line:
print("\nSpeeds are -100 to 100\n")
radio.config(channel=7,length=50)
It should look like this:
radio.config(channel=7,length=64)
Now, your script should be ready.
# terminal_bot_controller_wireless.py from microbit import * import radio radio.on() radio.config(channel=7,length=64) sleep(1000) print("\nSpeeds are -100 to 100\n") while True: vL = int(input("Enter left speed: ")) vR = int(input("Enter right speed: ")) ms = int(input("Enter ms to run: ")) dictionary = { } dictionary['vL'] = vL dictionary['vR'] = vR dictionary['ms'] = ms packet = str(dictionary) print("Send: ", packet) radio.send(packet) print()
The receiver script is also adapted from a previous tutorial.
Starting with the countdown_receiver.py from the Send and Receive Packets [1] activity, you can replace its countdown while loop and printed message with the servo_speed and sleep(ms) calls from terminal_controlled_bot_tethered_try_this. You will also need to update the dictionary parsing so that it gets the vL, vR, and ms values using the 'vL', 'vR', and 'ms' keys. That’s the most crucial part of incorporating the radio-in to cyber:bot navigation-out part of your tethered app into script that wirelessly receives.
Here's a GIF showing the modification taking place:
You will also need to make a few other adjustments. Here they are step-by-step:
bot(18).servo_speed(vL) bot(19).servo_speed(-vR) sleep(ms) bot(18).servo_speed(None) bot(19).servo_speed(None)
print("value = ", value) print("message = ", message, "\n") while value >= 0: print(value) sleep(1000) value = value - 1 print(message)
value = dictionary['start'] message = dictionary['after']
vL = dictionary['vL'] vR = dictionary['vR'] ms = dictionary['ms']
print() print("Parse: ")
print("Countdown App") print("micro:bit sender")
print("Ready...\n")
radio.config(channel=7,length=50)
It should look like this:
radio.config(channel=7,length=64)
Now, your script should be ready.
# terminal_controlled_bot_wireless from cyberbot import * import radio radio.on() radio.config(channel=7,length=64) sleep(1000) print("Ready...\n") while True: packet = radio.receive() if packet is not None: print("Receive: ", packet) dictionary = eval(packet) vL = dictionary['vL'] vR = dictionary['vR'] ms = dictionary['ms'] bot(18).servo_speed(vL) bot(19).servo_speed(-vR) sleep(ms) bot(18).servo_speed(None) bot(19).servo_speed(None)
Now, it’s time to reconnect your transmitter micro:bit and start radio-broadcasting navigation commands for your cyber:bot.
Next, repeat the tests you typed into the app when it was tethered:
If you take a look at the dictionary that was displayed, it should contain {'ms': 750, 'vR': 25, 'vL': 25}. Remember from the Dictionary Primer [3], order does not matter for dictionaries because they keep the correct values paired with the correct keys.
The import statements and radio calls are similar to the countdown_transmitter.py script from Send and Receive Packets [1]. The only difference is that radio.config has length set to 64 to accommodate a packet string with up to 64 characters.
# terminal_bot_controller_wireless from microbit import * import radio radio.on() radio.config(channel=7,length=64)
As usual, we want at least a 1 second pause before printing anything to make sure the browser terminal is ready. Then, instructions for the range of speeds you’ll use are printed.
sleep(1000) print("\nSpeeds are -100 to 100\n")
The main loop starts with the input statements from terminal_controlled_bot_tethered_your_turn.
while True: vL = int(input("Enter left speed: ")) vR = int(input("Enter right speed: ")) ms = int(input("Enter ms to run: "))
Next, the values are stored in a dictionary. This makes it easy because the receiver just has to do the reverse to get the vL, vR, and ms values back out of the dictionary it received. For more background on this, see the Dictionary Primer [3].
dictionary = { } dictionary['vL'] = vL dictionary['vR'] = vR dictionary['ms'] = ms
The dictionary is converted to a string named packet. That packet is displayed with a print statement, and then transmitted with a call to radio.send.
packet = str(dictionary) print("Send: ", packet) radio.send(packet) print()
Like the transmitter script, the wireless receiver script’s import and radio calls are also similar to countdown_receiver.py. The radio.config call's length is set to 64 to accommodate longer strings if needed. More importantly, since it has to actually control the cyber:bot, from microbit import * was changed to from cyberbot import *.
# terminal_controlled_bot_wireless from cyberbot import * import radio radio.on() radio.config(channel=7,length=64) sleep(1000) print("Ready...\n")
Inside the main loop, the script rapidly and repeatedly checks the radio.receive() method. If the micro:bit has not received a radio message, it returns None. If the micro:bit receives a packet (because you finished typing all three values and pressed Enter), then radio.receive returns a string that contains the dictionary. That gets stored in a variable named packet.
while True: packet = radio.receive()
When radio.receive returns None, the rest of the script gets skipped and the while(True) loop repeats. When radio.receive returns a string (with characters that represent a dictionary), the statements under if packet is not non are executed, starting with printing the packet. (You can only see that if you have the cyber:bot tethered and connected to a terminal.)
if packet is not None: print("Receive: ", packet)
This statement converts a string containing a dictionary into an actual dictionary. The result is named dictionary.
dictionary = eval(packet)
Assuming you typed 25, -25, 1000 in response to the prompts, the dictionary will be something like {'vL': 25, 'vR': -25, 'ms': 1000}. (Again, the order of the key-value pairs doesn’t matter since you use the key to find its corresponding value.) These statements use the 'vL', 'vR', and 'ms' keys to fetch the 25, -25, and 1000 values.
vL = dictionary['vL'] vR = dictionary['vR'] ms = dictionary['ms']
With the variables named vL, vR, and ms now storing the correct values, all that’s left is to make the left and right wheels turn at 25 and -25. And, keep that maneuver going for 1000 ms with sleep before stopping the servos again.
bot(18).servo_speed(vL) bot(19).servo_speed(-vR) sleep(ms) bot(18).servo_speed(None) bot(19).servo_speed(None)
Just as we added exception handling to the tethered prototype, we need to add code that deals with unusable characters typed in for the left and right wheel speeds, and the run time in milliseconds.
What happened? Did an exception occur?
If you haven't done the the Exception Handling Primer [4] yet, you may want to read through it to understand what is going on here!
In any case, if you follow the steps in the next Your Turn section, your wireless app will be equipped to deal with such user entry errors without leaving your cyber:bot stranded.
The same simple approach for prototyping that was used in tethered control can also be used here.
# terminal_bot_controller_wireless_your_turn from microbit import * import radio radio.on() radio.config(channel=7,length=64) sleep(1000) print("\nSpeeds are -100 to 100\n") while True: try: vL = int(input("Enter left speed: ")) vR = int(input("Enter right speed: ")) ms = int(input("Enter ms to run: ")) dictionary = { } dictionary['vL'] = vL dictionary['vR'] = vR dictionary['ms'] = ms packet = str(dictionary) print("Send: ", packet) radio.send(packet) print() except: print("Error in value entered.") print("Please try again. \n")
Links
[1] http://learn.parallax.com/tutorials/robot/cyberbot/cybersecurity-radio-data/send-and-receive-packets
[2] http://learn.parallax.com/tutorials/robot/cyberbot/cybersecurity-radio-data
[3] http://learn.parallax.com/tutorials/robot/cyberbot/dictionary-primer
[4] https://learn.parallax.com/tutorials/robot/cyberbot/exception-handling-primer