Porting Bit:Bot Code from MicroPython to C

I will port all of the code created in tutorials 1 – 5 from MicroPython to C++ so we can use it for the tutorials that use Arduino IDE.

PLEASE NOTE; You will need to have the Adafruit Neopixel and newPing libraries installed for this code to compile download links for these libraries can be found at the top of the code as a comment. For instructions on how to install Arduino libraries go to the Neopixel download link and follow the instructions their or follow my guide here that shows you how to install the newPing library. Even if you don’t plan on using the Neopixels or Ultrasonic sensor still import the library and keep the code incase you add these in the future. What’s provided here is a good code base for all Bitbot projects.

This will give us access to the NeoPixels, Motors, Light Sensor and IR Line Detectors when using the Arduino IDE. I will also add methods to use the Ultrasonic sensor by importing the newPing library. If you don’t have he ultrasonic sensor you can either delete this part of the code or install the newPing library as described in the previous tutorial. The Neopixels will on work if you carry out the Neopixel modification shown here. The code is starting to look more complex now and because of this I will arange the code into different tabs. The core Bitbot code will go into a tab named Bitbot_Lib_PORTED and the program code will go into a tabe named _00_programLoop.

Open Arduino IDE and create a new tab and name it BotBot_Lib_PORTED. The tab button is at the top right of the Arduino IDE window under the search icon. It looks like a downwards pointing arrow. Select the new tab and paste the below code into it.

[pastacode lang=”c” manual=”%2F*%0A%20*%20Bit%3ABot%20code%20ported%20from%20MicroPython%20to%20C%2B%2B.%20This%20code%20provides%20basic%20functions%0A%20*%20that%20were%20worked%20through%20from%20tutorials%201%20-%205%20from%20www.l33t.uk%2Fbitbot.%0A%20*%20Author%20David%20Bradshaw%202018%0A%20*%20%0A%20*%20Version%201.2%20adds%20support%20for%20Neopixel%20Library%20on%20pin%203%20for%20modified%20BitBots%0A%20*%20To%20see%20how%20to%20modify%20the%20Bitbot%20goto%20https%3A%2F%2Fwww.l33t.uk%2Fbitbot%2F%3Fpage_id%3D656%0A%20*%20Dependcies%20NewPing%20Library%3B%20https%3A%2F%2Fplayground.arduino.cc%2FCode%2FNewPing%0A%20*%20%20%20%20%20%20%20%20%20%20%20%20Adafruit%20NeoPixel%20Library%201.1.6%3B%20https%3A%2F%2Flearn.adafruit.com%2Fadafruit-neopixel-uberguide%2Farduino-library-installation%0A%20*%20%0A%20*%20If%20you%20have%20a%20unmodified%20Bitbot%20you%20can%20delete%20the%20neoPixel%20code%20however%20it%20might%20be%20easier%20to%20keep%20it%20incase%20you%20modify%20your%0A%20*%20Bitbot%20at%20somepoint%20and%20later%20examples%20will%20use%20the%20neoPixel%20code%20so%20it%20would%20be%20easier%20to%20leave%20it.%0A%20*%2F%0A%0A%2F%2FUltrasonic%20stuff%0A%23include%20%3CNewPing.h%3E%20%2F%2FImports%20library%20to%20be%20used%20with%20HC-SR04%20sensor%0ANewPing%20sonar(15%2C%2015%2C%20400)%3B%20%2F%2FCreate%20a%20newPing%20object%20with%20a%20range%20of%20400cm%0A%0A%2F%2FNeoPixel%20stuff%0A%23include%20%3CAdafruit_NeoPixel.h%3E%0A%23define%20PIN%203%20%20%2F%2FPin%20number%20thats%20connected%20to%20the%20Neopiexels%0A%23define%20LEDNUM%2012%20%20%2F%2Fnumber%20of%20Neopixels%0AAdafruit_NeoPixel%20neoPixels%20%3D%20Adafruit_NeoPixel(LEDNUM%2C%20PIN%2C%20NEO_GRB%20%2B%20NEO_KHZ800)%3B%0A%0A%0A%2F%2FMotor%20pin%20assignments%0A%23define%20leftSpeed%200%0A%23define%20leftDirection%208%0A%23define%20rightSpeed%201%0A%23define%20rightDirection%2012%0A%0A%2F%2FIR%20assignments%0A%23define%20leftLineSensor%2011%0A%23define%20rightLineSensor%205%0A%0A%2F%2FLight%20Sensor%20assignments%0A%23define%20lightSensor%202%0A%23define%20sensorSelect%2016%0A%0A%2F*%0A%20*%20THE%20BELOW%20ARE%20HELPER%20METHODS%20THAT%20WILL%20MAKE%20BIT%3ABOT%20DO%20THINGS%0A%20*%20SUCH%20AS%20MAKING%20THE%20MOTORS%20ROTATE%20AND%20TAKING%20READINGS%20FROM%20THE%20%0A%20*%20SENSORS.%0A%20*%2F%0A%0A%2F*%0A%20*%20NeoPixel%20helper%20methods%0A%20*%20It%20takes%20650uS%20to%20light%20up%20each%20neoPixel%20when%20lighting%20a%20strip%20of%206%20neopixels.%0A%20*%20This%20means%20that%20it%20will%20take%204.3mS%20to%20light%20up%20each%20side%20of%20the%20Bitbot.%0A%20*%20With%20this%20in%20mind%20we%20will%20endevour%20to%20write%20to%20the%20NeoPixels%20as%20little%20as%20possible%0A%20*%20A%20good%20update%20rate%20would%20be%201hz%20i.e.%20once%20per%20second%20or%20on%20colour%20change.%0A%20*%20The%20neopixles%20brightness%20will%20be%20adjusted%20if%20the%20room%20is%20pitch%20black%20the%20nP’s%0A%20*%20will%20be%20white%20in%20colour%20regardless%20of%20the%20values%20you%20give%20to%20them.%0A%20*%2F%0Avoid%20setColour(uint8_t%20pixelIndex%2C%20float%20bF%2C%20uint8_t%20red%2C%20uint8_t%20green%2C%20uint8_t%20blue)%20%2F%2F650uS%20Execution%20time%0A%7B%0A%20%20%20%20neoPixels.setPixelColor(pixelIndex%2C%20neoPixels.Color(applyBF(red%2C%20bF)%2C%20applyBF(green%2C%20bF)%2C%20applyBF(blue%2C%20bF)))%3B%0A%20%20%20%20neoPixels.show()%3B%0A%7D%0Avoid%20setColourLeft(uint8_t%20red%2C%20uint8_t%20green%2C%20uint8_t%20blue)%20%2F%2F4300uS%20execution%20time%0A%7B%0A%20%20%20%20float%20bF%20%3D%20getBrightnessFactor()%3B%0A%20%20%20%20for%20(uint8_t%20ii%20%3D%200%3B%20ii%20%3C%206%3B%20ii%2B%2B)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20setColour(ii%2C%20bF%2C%20red%2C%20green%2C%20blue)%3B%0A%20%20%20%20%7D%0A%7D%0Avoid%20setColourRight(uint8_t%20red%2C%20uint8_t%20green%2C%20uint8_t%20blue)%20%2F%2F4300uS%20execution%20time%0A%7B%0A%20%20%20%20float%20bF%20%3D%20getBrightnessFactor()%3B%0A%20%20%20%20for%20(uint8_t%20ii%20%3D%206%3B%20ii%20%3C%2012%3B%20ii%2B%2B)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20setColour(ii%2C%20bF%2C%20red%2C%20green%2C%20blue)%3B%0A%20%20%20%20%7D%0A%7D%0Afloat%20getBrightnessFactor()%20%2F%2F300uS%20execution%20time%0A%7B%0A%20%20%20%20%2F%2FReturns%20a%20value%20depending%20on%20how%20bright%20the%20room%20is%20so%20we%20can%20set%20the%20brightness%0A%20%20%20%20%2F%2Fof%20the%20neopixels.%20Bright%20in%20bright%20rooms%20and%20dim%20in%20dark%20rooms%0A%20%20%20%20uint32_t%20brightness%20%3D%20detectLight(%22LEFT%22)%3B%0A%20%20%20%20brightness%20%3D%20(brightness%20%2B%20detectLight(%22RIGHT%22))%20%2F%202%3B%20%20%2F%2FAverage%20brightness%20for%20left%20and%20right%20sensor%0A%20%20%20%20float%20rtnValue%20%3D%20float(brightness)%20%2F%201000%3B%0A%20%20%20%20if(rtnValue%20%3E%201)%7BrtnValue%20%3D%201%3B%7D%0A%20%20%20%20return%20rtnValue%3B%0A%7D%0Auint8_t%20applyBF(uint8_t%20colour%2C%20float%20brightnessFactor)%20%2F%2FAround%2012uS%20execution%20time%0A%7B%0A%20%20%20%20%2F%2FChanges%20the%20colour%20value%20so%20the%20Neopixels%20will%20automatically%20adjust%20their%20brightness%0A%20%20%20%20%2F%2FIf%20a%20value%20is%20less%20than%201%20it%20will%20be%20rounded%20up%20to%20a%201%20in%20getBrightnessFactor()%20to%20%0A%20%20%20%20%2F%2Fstop%20the%20LEDs%20from%20switching%20off.%20This%20means%20that%20in%20very%20dark%20conditions%20the%20LEDS%20will%0A%20%20%20%20%2F%2Feither%20turn%20white%20or%20a%20paler%20colour.%0A%20%20%20%20colour%20%3D%20colour%20*%20brightnessFactor%3B%0A%20%20%20%20if%20(colour%20%3C%201)%7Bcolour%20%3D%201%3B%7D%0A%20%20%20%20return%20colour%3B%0A%7D%0A%0A%2F*%0A%20*%20Returns%20the%20distance%20between%20Bit%3ABot%20and%20an%20object%20range%20%3D%3D%20400CM%0A%20*%2F%0Aint%20getDistance()%20%2F%2FTakes%20upto%2030mS%20to%20execute%2C%20upto%2050mS%20with%20the%20delay%0A%7B%0A%20%20%20%20delay(25)%3B%20%2F%2Fsettle%20time%20ensures%20more%20accurate%20readings%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20unsigned%20int%20uS%20%3D%20sonar.ping()%3B%0A%20%20%20%20int%20rtnVal%20%3D%20int(uS%20%2F%20US_ROUNDTRIP_CM)%3B%0A%20%20%20%20if(rtnVal%20%3D%3D%200)%7BrtnVal%20%3D%20450%3B%7D%20%2F%2FOut%20of%20range%20or%20somethings%20gone%20wrong%0A%20%20%20%20return(rtnVal)%3B%20%0A%7D%0A%0A%2F*%0A%20*%20IR%20sensor%20function%20for%20line%20following%0A%20*%2F%0Aboolean%20detectLine(uint8_t%20side)%0A%7B%0A%20%20%20%20uint8_t%20isLine%3B%0A%20%20%20%20if(side%20%3D%3D%200)%0A%20%20%20%20%7B%0A%20%20%20%20isLine%20%3D%20digitalRead(leftLineSensor)%3B%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20isLine%20%3D%20digitalRead(rightLineSensor)%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20if%20(isLine%20%3D%3D%201)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F*%0A%20*%20Light%20sensor%0A%20*%2F%0Auint32_t%20detectLight(String%20side)%0A%7B%0A%20%20%20%20if(side.equals(%22LEFT%22))%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20digitalWrite(sensorSelect%2C%20LOW)%3B%0A%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20digitalWrite(sensorSelect%2C%20HIGH)%3B%0A%20%20%20%20%7D%0A%20%20%20%20return%20uint32_t(analogRead(lightSensor))%3B%0A%7D%0A%0A%2F*%0A%20*%20Motor%20Functions%0A%20*%20Due%20to%20the%20arduino%20implementation%20we%20have%20lost%20precision%20for%20the%20motor%0A%20*%20argument%20speed.%20the%20values%20it%20can%20take%20is%20between%200%20-%20255.%20In%20the%20microPython%0A%20*%20version%20the%20largest%20value%20was%201023.%0A%20*%2F%0Avoid%20move(uint8_t%20_leftSpeed%2C%20uint8_t%20_rightSpeed%2C%20uint8_t%20_leftDirection%2C%20uint8_t%20_rightDirection)%0A%7B%0A%20%20%20%20analogWrite(leftSpeed%2C%20_leftSpeed)%3B%0A%20%20%20%20analogWrite(rightSpeed%2C%20_rightSpeed)%3B%0A%20%20%20%20digitalWrite(leftDirection%2C%20_leftDirection)%3B%0A%20%20%20%20digitalWrite(rightDirection%2C%20_rightDirection)%3B%0A%7D%0Avoid%20forwards(uint8_t%20speed)%0A%7B%0A%20%20%20%20move(speed%2C%20speed%2C%200%2C%200)%3B%0A%7D%0Avoid%20backwards(uint8_t%20speed)%0A%7B%0A%20%20%20%20speed%20%3D%20254%20-%20speed%3B%0A%20%20%20%20move(speed%2C%20speed%2C%201%2C%201)%3B%0A%7D%0Avoid%20left(uint8_t%20speed)%0A%7B%0A%20%20%20%20move(254%20%2B%20-speed%2C%20speed%2C%201%2C%200)%3B%0A%7D%0Avoid%20right(uint8_t%20speed)%0A%7B%0A%20%20%20%20move(speed%2C%20254%20%2B%20-speed%2C%200%2C%201)%3B%0A%7D” message=”Basic Functions” highlight=”” provider=”manual”/]

No rename your original tab by selecting it, clicking the tabe button and selecting rename. Rename _00_programLoop.

Now copy and paste the below code into the program loop tab.

[pastacode lang=”c” manual=”void%20setup()%20%7B%0A%20%20%20%20%2F%2F%20put%20your%20setup%20code%20here%2C%20to%20run%20once%3A%0A%20%20%20%20pinMode(leftSpeed%2C%20OUTPUT)%3B%20%2F%2FSet%20pin%20modes%2C%20this%20is%20not%20needed%20for%20HC-SR04%20pins%0A%20%20%20%20pinMode(leftDirection%2C%20OUTPUT)%3B%0A%20%20%20%20pinMode(rightSpeed%2C%20OUTPUT)%3B%0A%20%20%20%20pinMode(rightDirection%2C%20OUTPUT)%3B%0A%20%20%20%20%20%20%0A%20%20%20%20pinMode(leftLineSensor%2C%20INPUT)%3B%20%0A%20%20%20%20pinMode(rightLineSensor%2C%20INPUT)%3B%0A%0A%20%20%20%20pinMode(lightSensor%2C%20INPUT)%3B%0A%20%20%20%20pinMode(sensorSelect%2C%20OUTPUT)%3B%0A%20%20%0A%20%20%20%20Serial.begin(115200)%3B%20%2F%2FSetup%20the%20serial%20port%20so%20we%20can%20get%20debug%20data%0A%0A%20%20%20%20pinMode(PIN%2C%20OUTPUT)%3B%20%2F%2FSet%20the%20pinmode%20for%20the%20neopixels%0A%20%20%20%20neoPixels.begin()%3B%20%2F%2Finitilise%20the%20neoPixel%20object%0A%20%20%20%20neoPixels.show()%3B%20%0A%7D%0A%0A%2F*%0A%20*%20THIS%20IS%20THE%20PROGRAM%20LOOP%20PUT%20CODE%20HERE%20THAT%20WILL%20BE%20ITERATED%20THROUGH%0A%20*%20USING%20THE%20HELPER%20METHODS%20BELOW.%0A%20*%2F%0Avoid%20loop()%20%0A%7B%0A%20%20%20%20%2F%2F—-%20Used%20to%20calculate%20the%20time%20taken%20for%20the%20main%20program%20loop%20to%20iterate%20—-%0A%20%20%20%20unsigned%20long%20startTime%3B%0A%20%20%20%20unsigned%20long%20endTime%3B%0A%20%20%20%20unsigned%20long%20runTime%3B%0A%20%20%20%20startTime%20%3D%20micros()%3B%0A%20%20%20%20%2F%2F—-%20End%20of%20program%20loop%20calc%20stuff%20—-%0A%0A%20%20%20%20%2F*%0A%20%20%20%20*%20PUT%20YOUR%20MAIN%20LOOP%20CODE%20HERE%0A%20%20%20%20*%2F%0A%20%20%20%20neoPixels.clear()%3B%0A%20%20%20%20setColourRight(255%2C0%2C0)%3B%0A%20%20%20%20delay(500)%3B%0A%20%20%20%20neoPixels.clear()%3B%0A%20%20%20%20setColourLeft(0%2C255%2C0)%3B%0A%20%20%20%20delay(500)%3B%0A%20%20%20%20%0A%20%20%2F%2F%20—-%20Calculate%20program%20loop%20runtime%20and%20o%2Fp%20—-%0A%20%20endTime%20%3D%20micros()%3B%0A%20%20runTime%20%3D%20endTime%20-%20startTime%3B%0A%20%20%2F%2FSerial.println(runTime)%3B%20%20%2F%2FThis%20value%20is%20in%20micro%20seconds%201000uS%20%3D%3D%201mS%0A%20%20%2F%2FWe%20want%20the%20program%20loop%20to%20execute%20as%20quickly%20as%20possible%20so%20the%20robot%20is%20%0A%20%20%2F%2FAs%20responsive%20as%20it%20can%20be.%20Functions%20that%20take%20a%20long%20time%20should%20be%20called%20%0A%20%20%2F%2Fless%20frequently.%20%0A%20%20%2F%2F—-%20End%20of%20program%20loop%20calc%20stuff%20—-%0A%7D” message=”The Program Loop” highlight=”” provider=”manual”/]

Here we have our setup() and loop() method. The set-up method will be called once on start-up and the loop method will be looped through until the micro-controllers switched off. I have included some code so we can see how long the loop takes to iterate. We want to keep this time down to a minimum. To display the runtime uncomment line 47.

When using tabs they will be order alphabetically, this can have an effect on how the code is compiled. The code will be compiled in the order of the tabs therefore I have numbered the tabs accordingly so I can control in which order they are compiled to stop compilation errors. I will do this for all future projects created using Arduino IDE.

This code will make the left and right lights come on one after the other. Upload the code to the Microbit by clicking the upload button, switch on the batteries and see if the Neopixels are coming on if they are the code worked if they aren’t either something went wrong or your Neopixels aren’t working because you need to modify your Bitbot. Instructions for this can be found here.

As you can see the syntax of C++ and MicroPython is similar. I find C++ more intuitive and easier to read because the code is in code blocks where curly brackets {} are used to shoe the beginning and end of a block. You also use a semicolon at the end of each line (with some exceptions) so the compiler can parse the code correctly. Compare this code with the Microphone code and try to understand the differences. C++ is also strongly typed this means that variables must be declared with a certain type. For instance String, int, boolean, etc.

You can downloaded the code file in the resources section or by clicking here.