Wednesday, March 8, 2023

Drone Design

Drone Design for Bellingham Coding and Robotics Club


  • Learn basic Fusion 360 (CAD) skills.
  • Learn about drone components.
  • Learn electronics.
  • Learn flight tuning.
  • Learn piloting skills.

Fusion Process:

  1. Download and install Fusion 360.
  2. Sign up for a free account.
  3. Open Fusion.
  4. Create a new design. ( CTL+N )
  5. Save your file ( CTL-S ).
    1. Name your design.
  6. Open the parameters window.
  7. Add the following parameters, then click OK:
  8. Create a new sketch:
    1. Click on the top of the navigation cube:

    2. Select the XY plane as your sketch plane by selecting the orange square:
  9. Create a center point rectangle:
    1.     Select the origin as your center point and enter the motor mount parameter as your dimensions for the rectangle. Hit the tab key to switch between the two dimensions.

    2. Click "Finish Sketch".

  10. Create a new component:
    1. Name the new component "MotorMount", then click OK.
    2. Create a new sketch. The image below will be the finished sketch.

      1. Press the P key to project. Select a corner point from the rectangle on your previous sketch. Click OK.
      2. Create a "center point circle" by pressing the C key or clicking its icon.
      3. With its center being the point you just projected, move the mouse slightly and enter the motormount parameter you set earlier. It should be 6.6mm. Click on the circle and hit the "x" key to turn it into a reference line. This is shown above in YELLOW.
      4. Hit the "O" key and click on the circle just created to offset the circle. I offset mine by 3.1, shown in MAGENTA above. This will NOT be a reference line. If it is dashed, click the circle and hit "x".
      5. Create a hole for the motor shaft by creating another center point circle in the center of the motor mount with a diameter of 3mm. Shown in BLUE above.
      6. Press the "L" key to open the line tool. Click on the sketch's origin (center of the drawing with the black and white circles), then click the center of your motor mount. Then, create another line from the center of the motor mount to the 6.6mm reference circle. You'll see a mark that looks like "//" when the lines are parallel. Both of these lines should be reference lines.
      7. Create a center point circle using the motorMountScrew parameter for the diameter. Mine is 1.5mm, shown in GREEN above.
      8. To create two more equally spaced circles, use the circular pattern tool.
      9. Select the circle you just created, and the center point will be the center of the motor mount. Click OK.
      10. Once your sketch resembles the marked-up sketch, you are ready to extrude. Click finish sketch.
    3. Extrude your drawing 3mm. Press the "E" key, click the extrude icon, or select CREATE > EXTRUDE. When you mouse over your motor mount profile, It'll all turn blue. This will help you be sure you are going to extrude the propper profile. Select your motor mount profile.

    4. You just created a 3d BODY. That is what fusion calls 3d objects. Now we are going to create a circular pattern of motor mounts, one for each motor. Do this by selecting CREATE > PATTERN > CIRCULAR PATTERN. Make sure the "Object Type" is set to Bodies. Select your motor mount to be the object, and your Z axis will be your Axis. Selecting the Zaxis can be done on the main GUI or in the upper left browser by expanding the origin data and clicking on Z.

      Set quantity to 4.

    5. We are finished with motor mounts.
  11. FC_Mount.
    1. Make your main component active by clicking on the circle next to it.

    2. Create a new component: FC_Mount.
    3. Create a new sketch on the XY plane(The flat plane when viewing from the top view).

      1. Create a center point rectangle. CREATE > RECTANGLE > CENTER POINT RECTANGLE. Select the origin to be the center. The dimensions of the rectangle will be drawn from the FC_Size parameter, it should be 26mm. This parameter will be used for both dimensions. Switch between dimensions by pressing TAB. Shown in GREEN above. 
      2. Double-click on the rectangle so that all four sides turn blue.
      3. Press "X" to turn these into reference lines.
      4. Right-click on one of the blue lines and select "Move/Copy".
      5. Grab the circle of the rotation handle (YELLOW above) and rotate your square 45 degrees.
      6. Press "O", to create an offset of your square to be about 2mm larger. The BLUE square above.
      7. Create a center point circle at one of the corners of your original reference square. The diameter will be a parameter set to about 1.4mm for FC_ScrewSize.
      8. Use the circular pattern tool to create the 3 other screw holes. Or add them manually to every corner of your reference square.
      9. You can customize it with a center cut-out or your initials here.
    4. Extrude the flight controller mount profile. I made mine 4mm thick.

  12. ARMS
    1. Make your main component active.

    2. Create a new component called ARMS.
    3. Create a new sketch on the XY plane.
    4. Press "P" to use the project tool or select CREATE > Project/Include >PROJECT. This will pull edges, geometries, or other previous work into our drawings.

    5. Make previous drawings visible. You can toggle visibility settings in the browser by clicking on the eye icons.

    6. Click on the outer circle of your motor mount and the outer rectangle of the FC_mount. Click OK.
    7. Hide everything, except the drawing you're working on by right clicking the arms component and selecting "Isolate".

    8. You should have purple lines on your drawing now.
    9. Create a line from a corner of your FC projection that is tangent to your motor mount.

      You'll see a blue tangent icon when your line is in the right spot.

    11. Extrude your arm 4mm.

    12. Create a new sketch on the XY plane.
    13. Open the project tool and select your arm.
    14. Click on one of the purple projection lines, then press "O" to offset. Offset 5mm inside. I had to set mine to -5mm.

    15. Add some parallel lines toward the motor mount.

      NOTE the blue parallel symbols.
    16. Do the same towards the FC_Mount.

    17. Delete the inner lines shown in blue by clicking on them and pressing the delete key. You can use the shift key to select multiple lines.

    19. Extrude the center area of your new sketch. Change the "Extent Type" to "All".

    20. Add a chamfer to make up the height differential between your 4mm FC_Mount and your 3mm motorMount.
      1. Select: MODIFY > CHAMFER
      2. Click the upper arm edges, where they would touch the motor mount.
      3. Change the chamfer type to "Two Distance".
      4. Adjust the two arrows to your liking or enter 10mm in the first black and 1mm in the second.

      5. Click OK.
    21. Customize with more chamfers or adjust widths by changing the offset value from 12-14.
    22. Create a circular pattern of the arms.

      1. The Objects should be the two parts of the arms.
      2. The Axis will be Z. Select it from the browser or the blue vertical line at the origin.
    23. Arms Complete.
  13. Propeller Guards.
    1. Make the main component active.
    2. Create a new component called PropGuards.
    3. Create a new user parameter called PropSize. Choose 3 inches or 40 mm.
    4. Create a new sketch on the XY plane.
      1. Make sure you can see your original drone-sized rectangle from 9-1.

      2. Project one of the corner points.

      3. Create a center point circle on that point. The diameter of the circle will be "PropSize +5". This will make the prop guards 5mm bigger than our props for clearance.

      4. Create an offset circle 1.2mm bigger.

        1. Press "O" to create offsets.
        2. The 3D printing nozzles are 0.4 mm wide, so 1.2mm is 3 layers of plastic thick. You may try out different multiples of 0.4 here.
      5. Make your arm bodies visible.

      6. Project the inner lines from your arms.

        1. P is the keyboard shortcut for the project tool.
    5. Extrude your PropGuard profile 16.6mm.

    6. Add chamfers to the top openings.

      1. Select 2 distance.
      2. Bring the vertical chamfer down with the down arrow to around 14mm.
      3. Move the horizontal chamfer out until just before it deletes half of your PropGuard, this is 38mm for the 3-inch PropSize.
    7. Create a circular pattern to add the 3 other prop guards.

      1. Your prop guard is the object.
      2. Z is your axis.
      3. Quantity:4.
    1. Make your main component active.
    2. Right click your main component.
    3. Select "Show all Bodies".

    4. Select: MODIFY > COMBINE.

      1. The target body will be your FC_Mount.
      2. Tool Bodies are all other bodies. Get everything.
      3. Check the "New Component" box.
      4. Check the "Keep Tools" box.
      5. Click OK.
    5. Export your combined model for 3D slicing.

      1. Find your new component.
      2. Find the newly created body.
      3. Right-click and select "Save as Mesh".
        1. Format: 3MF
        2. Refinement: High
        3. OK
      4. Save your file to your student folder.

Slicing your model:

Tuesday, December 20, 2022

Adafruit Accessories Quad Level-Shifter and NeoPixel Ring

Today I'll be using a 74AHCT125N  quad level-shifter to use a 5V 24 neoPixel ring with my Arduino Nano Connect. It is on pin 4.

That part was pretty easy. Wiring followed the adafruit reference. The only problem was sending the programmable input/output (PIO) state machine commands from one of the cores. This would cause animations to stall while running CPU-heavy instructions. I could run it on core0 since it will just be handling BLE communications. I would like it to be able to run the lights in some preset animations. Ideally independently while taking some FIFO interrupts from the main core. PIOs are capable of looping small snippets. I've only used PIOs once before using a Pi Pico and micropython.

Saturday, December 10, 2022

Arduino nano connect RP2040 Multiprocessing

I'll be trying to use the dual-core 32-bit Arm® Cortex®-M0+. One core for communication and the other to run timers and servo commands for Pinky's gait management.

 Set up the ANC-RP2040:

  • Using Arduino IDE 2.0.3
  • In the boards manager, install MBED OS Nano boards.
  • From the library manager, install wifinina.
Modifying code from this tutorial based on the pi pico RP2040. Found this one to work better.

Using pico/mulitcore.h, usage can be found in C:\Users\*YOUR USER*\AppData\Local\Arduino15\packages\arduino\hardware\mbed_nano\3.4.1\cores\arduino\mbed\targets\TARGET_RASPBERRYPI\TARGET_RP2040\pico-sdk\rp2_common\pico_multicore\include\pico\multicore.h

I was having trouble with the cursor jumping to the left when I started a new line or tabbed. Solution was hidden in the preferences menu.

#include <stdio.h>
#include <mbed.h>
#include "pico/multicore.h"
#include <WiFiNINA.h>

void core1_entry() {
    uint32_t time1 = multicore_fifo_pop_blocking();
    if(time1 % 600 == 0){
      digitalWrite(LED_BUILTIN, LOW);
    else if (time1 % 300 == 0){
      digitalWrite(LED_BUILTIN, HIGH);

void setup() {
  while(!Serial){//Wait for serial to come up
  Serial.println("\r\nHello, multicore_BLINKER!");

void loop() {
  uint32_t time = millis();
  if(time % 1000 == 0){
    digitalWrite(LEDR, LOW);
  else if (time % 500 == 0){
    digitalWrite(LEDR, HIGH);

Friday, December 9, 2022

Got some ESP32s for cyber Monday.

Installed Arduino "arduino-ide_2.0.3_Windows_64bit". Followed these instructions, except I chose the NodeMCU-32s. Unknown device in win10 device manager. CP210x_Universal_Windows_Driver downloaded and installed. Upload fails. v4.2.1
Serial port COM3
Connecting...Traceback (most recent call last):
  File "", line 34, in <module>
  File "esptool\", line 1004, in _main
  File "esptool\", line 646, in main
  File "esptool\", line 895, in get_default_connected_device
  File "esptool\", line 631, in connect
  File "esptool\", line 572, in _connect_attempt
  File "esptool\", line 435, in sync
  File "esptool\", line 365, in command
  File "esptool\", line 317, in write
  File "serial\", line 325, in write
serial.serialutil.SerialTimeoutException: Write timeout
[2060] Failed to execute scrip
t 'esptool' due to unhandled exception!
Failed uploading: uploading error: exit status 1

 I had two com3 devices, so I disabled the non usb-uart one. The upload completes. But the output is gibberish. P ���-t��Yt�(�l��. The baud rate of the serial monitor did not match the baud rate specified in the code.

12/22/22 update

Testing out Bluetooth

There is a library conflict if you have the arduinoBLE library installed. 
Multiple libraries were found for "BLEDevice.h"
  Used: C:\Users\Jash\Documents\Arduino\libraries\ArduinoBLE
  Not used: C:\Users\Jash\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\libraries\BLE
exit status 1
They both have BLEDevice.h. I had to change:
#include <BLEDevice.h> to #include "BLEDevice.h"
This project will be a client so that it can accept multiple connections. The goal is a multiplayer game.
The ESP32 BLE_client example throws many errors! Lots of undefined references.

Friday, December 2, 2022

ROS experiments

I will be experimenting with the newest ROS2 at the time of this writing; Humble Hawksbill. Image a raspberry PI 4 2Gb with 64-bit rasbian OS on a 32Gb microSD. I am using putty to ssh into the pi and VNCviewer to interface with GUIs. 

Learn docker to install ROS2 on the RPI4

This is my first time using docker. After cloning the docker images repo, I went with the humble ros-base image.

The following are some useful docker commands:

  • docker ps
  • docker images
  • docker container start [CONTAINER-ID]
  • docker exec -ti [CONTAINER-ID] /bin/bash
  • docker container list -f "status=exited"
  • docker commit os_name image_name:version
  • docker container update --help (this might have saved me some time and disk space. I was committing so that I could rerun with new parameters)
  • docker rm container_id_or_name
  • The config file is a json file at the location ‘ /var/lib/docker/containers/[container-id]/config.v2.json
Build the container using the appropriate Dockerfile, then renamed it "ROS-TEST" to reference it without having to use the randomly generated container number.
  • $ sudo docker rename [container#] ROS-TEST

Set the timezone in a container

  • sudo rm -rf /etc/localtime
  • sudo ln -s /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
  • date

Moving on to the ROS2: Humble Hawksbill tutorials.

The environment set up without problems. 

  • source /opt/ros/humble/setup.bash
  • echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
  • printenv | grep -i ROS
  • export ROS_DOMAIN_ID=24
  • echo "export ROS_DOMAIN_ID=24" >> ~/.bashrc

The turtlebot tutorial took a while to download and setup. When running the turtlebot simulator an error occurred:

qt.qpa.xcb: could not connect to display 
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, xcb.
[ros2run]: Aborted

The sim uses qt and qt can't find a display. Is this a problem with docker, vnc, or a combo of both? 

Make an image of the current container to run with environmental variables set: 

  • --env="Display"
  • --net=host
  • FIX: in RPI terminal "xhost +local:docker". This needs to be done every reboot that you wish to use a GUI. It can also be run while a container is running

"exit" docker. The container is no longer running. "docker container start ROS-TEST", the container is running in the background.

Turtlesim GUI still launches with errors:

libGL error: MESA-LOADER: failed to retrieve device information

MESA-LOADER: failed to retrieve device information

MESA-LOADER: failed to retrieve device information

libGL error: failed to create dri screen

libGL error: failed to load driver: vc4

libGL error: failed to open /dev/dri/card1: No such file or directory

libGL error: failed to load driver: vc4

qt.qpa.xcb: QXcbConnection: XCB error: 148 (Unknown), sequence: 191, resource id: 0, major code: 140 (Unknown), minor code: 20

However, teleop keys work for the movement. I'll look into the errors above if I run into problems. 

  • --volume="$HOME/.Xauthority:/root/.Xauthority:rw"

^ Adding this didn't get rid of the errors. I'm not even sure if that is how to share the RPI's xserver as a volume to the docker container though...

Moving on... rqt install is 1198MB. 

Everything works to finish the CLI tutorials.

The following error came up in Tutorials \Beginner: Client libraries \Using colcon to build packages.

CMake Error at CMakeLists.txt:14 (find_package):
  By not providing "Findexample_interfaces.cmake" in CMAKE_MODULE_PATH this
  project has asked CMake to find a package configuration file provided by
  "example_interfaces", but CMake did not find one.

This is caused by a missing install and remedied by:  

  • sudo apt install ros-humble-example-interfaces

The RPI does not like "colcon build --symlink-install" very much. It went unresponsive for 1h 6m. Plus...more errors. I forgot to start from a clear directory though... When I re ran the build, it maxed out my ram and swap file, interrupting my VNC connection, and became generally unresponsive. 12 hours in, it was still unresponsive. I power cycled the RPI and got back into the container to try again. rm -r the ros2_ws directory and started over... It looks like it is going to have the same problem. Next attempt is to increase the RPI swap file from 100M to 1000M and reduce the amount of RAM the container has access to, it is currently unlimited.

Swap increase:

  1. sudo dphys-swapfile swapoff
  2. sudo nano /etc/dphys-swapfile
  4. CONF_SWAPSIZE=2048 (Increased to 6144 later)
  5. sudo dphys-swapfile setup
  6. sudo dphys-swapfile swapon
  7. sudo reboot
Docker's memory and CPU usage: MEM reference. In step 5, I give docker access to only 3 of the RPI's 4 cpus, 1G of its memory, and 1.5G of swap so that it'll remain responsive and not kill other processes like VNC.
  1. sudo cp /boot/cmdline.txt /boot/cmdline.txt.bak
  2. sudo nano /boot/cmdline.txt
  3. add "cgroup_enable=memory cgroup_memory=1 swapaccount=1" to the end of the line, not on a new line.
  4. verify with "docker info"
  5. docker run -it --name guiROSlimited --memory="1g" --memory-swap="2.5g" --cpus="3" --env="DISPLAY" --net=host [IMAGE NAME]
Now running "colcon build --symlink-install" isn't crashing the pi or making ssh/VNC unsresponsive.
I'm starting to question whether I should have made the swap file 4 or 6G now...  26 minutes in, the RPI swap is at 1.47G and 0/22 modules have been built...45 minutes: the container swap is full :-( ctl+c aborted. increasing swap to 6144.
  • want /var/swap=6144MByte, restricting to config limit: 2048MBytes, checking existing: keeping it
  • uncomment CONF_MAXSWAP=2048 and change to CONF_MAXSWAP=6144
31 minutes later, I forgot to run a new docker container with an increased swap. It maxed out faster. I created a new container for a fresh start.
  • docker run -it --name rosFresh1 --memory="1.25g" --memory-swap="4.5g" --cpus="3" --env="DISPLAY" --net=host ros_docker
  • sudo apt update
  • sudo apt upgrade
I updated chrome and lost a chunk of the blog. colcon on the RPI works better with only one package processed at a time. Although, I have not tried 2 or 3. Use the following tag to use one CPU or the second to use a specific amount:
  • --executor sequential
  • --parallel-workers NUMBER
  • This is only necessary when building multiple packages. It is not necessary yet when using --packages-select
Sometimes I create packages in the root (ros2_ws) directory, instead of 'src'. rm -r the created folder. To remove; "build", "install", and "log".
  • rm -rf build/ install/ log/
  • colcon build --executor sequential
Short of it is that I have restarted from the ros-desktop image. No fundamental errors to speak of as of yet.
Here is a free book on ROS.

Monday, September 26, 2022

Stuck on a bug...

 After getting 1300 lines deep, the code has started to develop a bug. While running gait timers for leg/servo movement, Bluetooth disconnects and the program hangs... I've tried debugging and the error goes away if I had a serial.print()... but that is odd that it would fix it. I know that adding serial communication can sometimes take more time for a process... 

Anyway, I'm going to try running some multicore examples from

Thursday, August 11, 2022

Pinky: Android RC control over Bluetooth to Arduino Nano PR2040 Connect.

 For remote control of Pinky the octobot I had a choice of wifi, Bluetooth, or an old drone TX and RX set up. I'm choosing to go with Bluetooth because everybody with a phone has the capability in their pockets. The old drone RX/TX setup would require additional components and take up internal cavity space in the robot. After two nights of testing I finally got BLE working last night by following these resources:

Tonight, 8/11/22, I'll try and build a joystick and control scheme into the app inventor to push command controls to the Arduino. After that, I'll try to port Pinky's old micropython codebase to the Arduino programming language and convert all of its classes to headers....
Finally got an app I am okay with. The code is vast, so if you want to see it, just download it to view it outside your browser.
Time to start working on the arduino code.
#include <ArduinoBLE.h>

#include <Arduino_LSM6DSOX.h>

BLEService RCService("27810000-4786-42e7-bd27-45257b2e988f"); // BLE LED Service
// BLE AppInventorRC Characteristic - custom 128-bit UUID, read and writable by central
BLEIntCharacteristic RC_AngleCharacteristic("27810001-4786-42e7-bd27-45257b2e988f", BLERead | BLEWrite | BLEWriteWithoutResponse);
BLEIntCharacteristic RC_SpeedCharacteristic("27810002-4786-42e7-bd27-45257b2e988f", BLERead | BLEWrite | BLEWriteWithoutResponse);
BLEIntCharacteristic RC_HeightCharacteristic("27810003-4786-42e7-bd27-45257b2e988f", BLERead | BLEWrite | BLEWriteWithoutResponse);
BLEIntCharacteristic RC_RotationCharacteristic("27810004-4786-42e7-bd27-45257b2e988f", BLERead | BLEWrite | BLEWriteWithoutResponse);

int LastSpeed = 0;
int LastAngle = 0;
int LastHeight = 0;
int LastRot = 0;

int tick = 0;
bool CentralConnected = 0;
float x, y, z;

void setup() {
  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy failed!");

  // set advertised local name and service UUID:
  // add the characteristics to the service
  // add service
  // start advertising
  Serial.println("Pinky Peripheral, waiting for connections....");
  //IMU stuff
  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
    Serial.print("Gyroscope sample rate = ");
  Serial.println(" Hz");
  Serial.println("Gyroscope in degrees/second");
void loop() {
  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();
  // if a central is connected to peripheral:
  if (central) {
    if (!CentralConnected){
      Serial.print("Connected to central: ");
      // print the central's MAC address:
      // while the central is still connected to peripheral:
      CentralConnected = 1;
    while (central.connected()) {
      //Serial.print("Waiting for the write thing: ");
      //delay(100);//This causes hangs / crashes
      if (RC_AngleCharacteristic.written() || RC_SpeedCharacteristic.written() || RC_HeightCharacteristic.written() || RC_RotationCharacteristic.written()) {
        //Debounce the BLE
        if (LastAngle != RC_AngleCharacteristic.value() || LastSpeed != RC_SpeedCharacteristic.value() || LastHeight != RC_HeightCharacteristic.value() || LastRot != RC_RotationCharacteristic.value()){
        Serial.print("Angle: ");
        Serial.print(" Speed: ");
        Serial.print(" Height: ");
        Serial.print(" Rotation: ");
        LastAngle = RC_AngleCharacteristic.value();
        LastSpeed = RC_SpeedCharacteristic.value();
        LastHeight = RC_HeightCharacteristic.value();
        LastRot = RC_RotationCharacteristic.value();

      // if (IMU.gyroscopeAvailable()) {
      // IMU.readGyroscope(x, y, z);

      // Serial.print(x);
      // Serial.print('\t');
      // Serial.print(y);
      // Serial.print('\t');
      // Serial.println(z);
      // when the central disconnects, print it out:
      Serial.print(F("Disconnected from central: "));
      CentralConnected = 0;