A MakeCode project
View the Project on GitHub cmiicbrg/microbit-car-unified-sender-and-receiver
In this tutorial, you will learn how to control a vehicle with the Micro:bit. We will use a motor and a motor shield (motor driver). The motor driver is the red board that is attached to the vehicle. The motor is connected to the motor driver, and the motor driver is connected to the Micro:bit. Everything is already assembled on the vehicle. When it’s time, you just need to insert the Micro:bit into the slot.
We have already created a variable r and a function determineDirection for you. The function determineDirection determines the orientation (rotation) of the Micro:bit using the accelerometer. The variable r will be used later to control the direction of the vehicle. So there’s nothing to do here yet!
let r = 0
function determineDirection() {
// If turned too far, it would otherwise set exactly the opposite direction
if (input.acceleration(Dimension.Y) > 0) {
r = 180 * (Math.atan2(input.acceleration(Dimension.Y), -1 * input.acceleration(Dimension.X)) / Math.PI) - 90
}
}
Create the variables vl and vr.
The variable r already exists; it is used for the direction. vl and vr are used for the speed of the left and right motors.
At startup ||basic:on start||, the SmallDiamond icon is displayed, and the motors’ speed and direction are set to 703 and 0, respectively.
Moreover, you need to set the radio group. It’s best to use the same number as in the previous tutorial.
let r = 0
let vl = 0
let vr = 0
basic.showIcon(IconNames.SmallDiamond)
vr = 703
vl = 703
radio.setGroup(134)
When the A button is pressed, we send the text “forward” via radio. When the B button is pressed, we send the text “back” via radio. When the logo is pressed, we send the text “stop” via radio.
Moreover, we use arrows to indicate the direction and the SmallDiamond icon to show that the vehicle has been stopped.
input.onButtonPressed(Button.A, function () {
basic.showArrow(ArrowNames.North)
radio.sendString("forward")
})
input.onButtonPressed(Button.B, function () {
basic.showArrow(ArrowNames.South)
radio.sendString("back")
})
input.onLogoEvent(TouchButtonEvent.Pressed, function () {
basic.showIcon(IconNames.SmallDiamond)
radio.sendString("stop")
})
To create a function, click on Advanced and then on Create a function.
The pins 0, 1, 8, 12 of the Micro:bit are connected to the inputs of the motor driver that control the motors’ direction.
To tell the motor driver in which direction the motors should run, the pins need to be set to 1 or 0.
You will have to figure out later on your own how the pins’ values must be set to be able to drive backwards.
function forward() {
pins.digitalWritePin(DigitalPin.P0, 1)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P8, 0)
pins.digitalWritePin(DigitalPin.P12, 1)
basic.showArrow(ArrowNames.North)
}
function stop() {
pins.digitalWritePin(DigitalPin.P0, 0)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P8, 1)
pins.digitalWritePin(DigitalPin.P12, 1)
basic.showIcon(IconNames.SmallDiamond)
}
function back() {
basic.showArrow(ArrowNames.South)
}
The outputs of the motor driver that control the motors’ speed are connected to pin 14 and 13 of the Micro:bit.
function writeSpeed() {
pins.analogWritePin(AnalogPin.P14, vr)
pins.analogWritePin(AnalogPin.P13, vl)
}
||functions:call forward|| can be found under Advanced - Functions.
Etc.
radio.onReceivedString(function (receivedString) {
if (receivedString == "forward") {
forward()
} else if
(receivedString == "back") {
back()
} else if (receivedString == "stop") {
stop()
}
})
// @hide
function forward() {
pins.digitalWritePin(DigitalPin.P0, 1)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P8, 0)
pins.digitalWritePin(DigitalPin.P12, 1)
basic.showArrow(ArrowNames.North)
}
// @hide
function stop() {
pins.digitalWritePin(DigitalPin.P0, 0)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P8, 1)
pins.digitalWritePin(DigitalPin.P12, 1)
basic.showIcon(IconNames.SmallDiamond)
}
// @hide
function back() {
basic.showArrow(ArrowNames.South)
}
Since the values of vl and vr will constantly change later on, we write them continuously. (||functions:determineDirection||)
Moreover, we send the direction r via radio.
basic.forever(function () {
radio.sendNumber(r)
writeSpeed()
})
// @hide
function writeSpeed() {
pins.analogWritePin(AnalogPin.P14, vr)
pins.analogWritePin(AnalogPin.P13, vl)
}
Your vehicle should now be able to move forward and stop. Get a vehicle, find a partner, set the radio group, and try it out. One micro:bit is inserted in the vehicle, and the other controls it.
The direction is determined using the accelerometer. This is done using the determineDirection function. This function has been there from the start, so you don’t need to create it anew.
But you have to continuously complement it with determineDirection. (Do not create a new forever block!)
function determineDirection() {
// If turned too far, it would otherwise set exactly the opposite direction
if (input.acceleration(Dimension.Y) > 0) {
r = 180 * (Math.atan2(input.acceleration(Dimension.Y), -1 * input.acceleration(Dimension.X)) / Math.PI) - 90
}
}
basic.forever(function () {
// @highlight
determineDirection()
radio.sendNumber(r)
writeSpeed()
})
// @hide
function writeSpeed() {
pins.analogWritePin(AnalogPin.P14, vr)
pins.analogWritePin(AnalogPin.P13, vl)
}
The received number is converted into speed and written into the variables vl and vr.
radio.onReceivedNumber(function (receivedNumber) {
// serial.writeValue("r", receivedNumber)
vr = Math.map(receivedNumber, -90, 90, 383, 1023)
vl = Math.map(-1 * receivedNumber, -90, 90, 383, 1023)
})
The final project will look like this:
let r = 0
let vl = 0
let vr = 0
basic.showIcon(IconNames.SmallDiamond)
vr = 703
vl = 703
radio.setGroup(134)
stop()
// @hide
function stop() {
pins.digitalWritePin(DigitalPin.P0, 0)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P8, 1)
pins.digitalWritePin(DigitalPin.P12, 1)
basic.showIcon(IconNames.SmallDiamond)
}
input.onLogoEvent(TouchButtonEvent.Pressed, function () {
basic.showIcon(IconNames.SmallDiamond)
radio.sendString("stop")
})
radio.onReceivedNumber(function (receivedNumber) {
vr = Math.map(receivedNumber, -90, 90, 383, 1023)
vl = Math.map(-1 * receivedNumber, -90, 90, 383, 1023)
})
function forward() {
pins.digitalWritePin(DigitalPin.P0, 1)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P8, 0)
pins.digitalWritePin(DigitalPin.P12, 1)
basic.showArrow(ArrowNames.North)
}
function stop() {
pins.digitalWritePin(DigitalPin.P0, 0)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(D
pins.digitalWritePin(DigitalPin.P8, 1)
pins.digitalWritePin(DigitalPin.P12, 1)
basic.showIcon(IconNames.SmallDiamond)
}
input.onButtonPressed(Button.A, function () {
basic.showArrow(ArrowNames.North)
radio.sendString("forward")
})
function back() {
basic.showArrow(ArrowNames.South)
}
radio.onReceivedString(function (receivedString) {
if (receivedString == "forward") {
forward()
} else if (receivedString == "back") {
back()
} else if (receivedString == "stop") {
stop()
}
})
input.onButtonPressed(Button.B, function () {
basic.showArrow(ArrowNames.South)
radio.sendString("back")
})
function determineDirection() {
// If turned too far, it would otherwise set exactly the opposite direction
if (input.acceleration(Dimension.Y) > 0) {
r = 180 * (Math.atan2(input.acceleration(Dimension.Y), -1 * input.acceleration(Dimension.X)) / Math.PI) - 90
}
}
function writeSpeed() {
pins.analogWritePin(AnalogPin.P14, vr)
pins.analogWritePin(AnalogPin.P13, vl)
}
basic.forever(function () {
determineDirection()
radio.sendNumber(r)
writeSpeed()
})
let r = 0
let vl = 0
let vr = 0
// @hide
basic.showIcon(IconNames.SmallDiamond)
// @hide
vr = 703
// @hide
vl = 703
// @hide
radio.setGroup(134)
// @hide
stop()
Show a teacher that your vehicle works and submit your code.
# BlocksExistValidator
* enabled: true