Maker.io main logo

Build a Custom Fusion 360 Controller with the Arduino Plug and Make Kit

2025-10-03 | By Travis Foss

License: See Original Project Board / Sensor Interface Cables Displays LEDs / Discrete / Modules Microcontrollers Encoder LED / Display Drivers Movement Rotary Arduino Qwiic

Have you ever thought it would be fun to create your own game controller to control your favorite game or build a shortcut control pad for your favorite CAD program? Does it involve some button presses and directional arrows? I recently tested the Arduino Plug and Make kit and came across their game controller example, which was an uncomplicated way to set up either of those. This example uses the Arduino R4 WiFi along with the Movement Modulino and the Button Modulino, and outputs the motion as HID outputs. HID, for those unfamiliar, stands for Human Interface Device class, and these microcontrollers can emulate actions such as key presses on a keyboard or mouse movements.

keypresses_1

Parts used in this build

Getting Started

Arduino has put together an excellent walkthrough on getting started with the Arduino Plug and Make Kit or the Game Controller Modulino, as well as templates to get quickly up and running with the example. The template for the Game Controller is located here: Game Controller | Plug and Make. If you are new to Arduino, I highly suggest you review this page. In the game controller example, it first walks through setting up the buttons and using them for HID output, by setting button A to type the letter “B,” button B to type the letter “E,” and button C to emulate a left Mouse button click. The next step was to set up the Movement Modulino to emulate mouse movements based on the direction it is tilted.

Adapting the project for Fusion 360

After thinking for a while, I decided to build a controller for Fusion 360 based on this example. Previously, I had built a CAD controller for OnShape, Raspberry Pi Pico Space Mouse for OnShape CAD Design, and I thought it would be a fun challenge to do a similar project with this kit. I started by looking into what keyboard/mouse shortcuts I could use for this application. Since the button module only has three buttons, I decided it would be best to set up a button that switches through modes so that I could have more than just 3 shortcuts. Next, I began thinking about the motion module. The first thing that sprang to mind was to use it to control orbiting around the part. By holding the module, it would feel as if I were rotating the part itself based on the direction it is moved. To expand the functionality of this project, I decided to add the Knob Modulino and the Pixel Modulino as well. I came up with the idea of using the knob to adjust the sensitivity of rotation or movement. By setting it to the low end, the rotation would be very slow, while moving it to the high end would allow for rapid movement. I also wanted to have a quick option to set the sensitivity back to the middle, so the idea of clicking the knob to set it back centered in the range was the next idea that came to mind. Lastly, I wanted to have a visual indicator to know where in the range my sensitivity was set. For this, I thought that using the pixel Modulino would be a good option. I could have the lights move from one pixel lit to all the pixels lit to show the full range of sensitivity.

adapting_2

adapting_3

adapting_4

adapting_5

Loading the Template

Since the Game Controller template seemed to be a quick start option, I attempted to load it onto my board. I did run into a hiccup at this point, however. The page kept saying that the program was loading onto the board for a few hours and never got to a completed point. I did find out that if I just refreshed the page, the program was already loaded on the board. After getting to that point, I clicked on the game controller “Thing” that had been generated on my Arduino Cloud app page.

loading_6

After clicking on the game controller thing, the first page I landed on was the cloud variables page. Without knowing exactly what these did yet, I clicked on the Sketch button on the top right corner.

button_7

When the sketch opened, it brought me to a familiar page. At this point, I read the learning page and implemented the additional lines of code for the movement Modulino and uploaded it to my board. On the last line of the project, it has a link to add the Modulino Knob to the project. After looking at the page, it suggested and noticing that the code was not exactly what I was looking for, I started thinking about how I would go about my next step. Looking back at the coding page of the Arduino code IDE, I noticed a button that I had not really paid attention to before, the Arduino AI Assistant button. For the fun of it, I thought it would be interesting to test this feature.

Testing Arduino Cloud AI Assistant

Since this was my first time trying this AI Assistant, I started with the following prompt:

I am looking at using the Knob Modulino to increment and decrement the sensitivity variable in this sketch. I would like it to move in multiples of 5 and be limited to a range between 30 and 70. I would also like to use the Pixel Modulino to show what level of sensitivity I am at. When the knob is pressed, it will set the sensitivity back to 50.

The AI Assistant then was able to provide the full code for what I wanted to do; however, once I had uploaded it into the sketch space, it ran into an issue with the syntax that the AI had chosen on a few of the functions. After two more prompts back and forth with the AI, I was able to get the code as I intended, minus one small issue where only one pixel on the Pixel Modulino would light up. I gave it the following prompt, which fixed the issue; however, it presented another issue. After two more prompts asking it to fix the issue, I had the code working as I felt it should.

Can you change the pixels' code so that one pixel lights up at a 30 sensitivity and they all light up at 70?

knob

Now that I had the base hardware functioning in the way I wanted it to, I decided to see what the Arduino AI assistant was capable of. I was not sure if the assistant had access outside the IDE itself, so I decided to give it the following prompt:

I am building a device using these devices that run Fusion 360 shortcuts. I would like for button A to be used to set which mode the Uno is in. I need 4 different modes. I would also like to display the numbers 1 through 4 on the matrix display as they are toggled through.

The first thing the AI assistant did was to implement the toggling of modes using button A. It started by giving me 3 sections of code to add.

implement_8

Copy Code
int sensitivity = 50;

int lastKnobPosition = 0;

int currentMode = 1; // Modes 1-4

void setup() {

Serial.begin(9600);

Mouse.begin();



lastKnobPosition = knob.get();



// Display initial mode

displayMode(currentMode);



}

display_9

Copy Code
// Rest of your existing code...

bool a = false, b = false, c = false;

static bool lastA = false;



if (buttons.update()) {

a = buttons.isPressed(0);

}



// Keyboard/mouse controls

// Button A cycles through modes

if (a && !lastA) {

currentMode++;

if (currentMode > 4) currentMode = 1;

displayMode(currentMode);

Serial.print("Mode: ");

Serial.println(currentMode);

}

lastA = a;



if (b) Keyboard.write('e');

else Keyboard.release('e');

release_10

Copy Code
pixels.show();

}

void displayMode(int mode) {

byte frame[8][12] = {

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

};



// Number patterns (centered)

if (mode == 1) {

frame[2][5] = 1; frame[2][6] = 1;

frame[3][6] = 1;

frame[4][6] = 1;

frame[5][5] = 1; frame[5][6] = 1; frame[5][7] = 1;

} else if (mode == 2) {

frame[2][4] = 1; frame[2][5] = 1; frame[2][6] = 1;

frame[3][7] = 1;

frame[4][5] = 1; frame[4][6] = 1;

frame[5][4] = 1; frame[5][7] = 1;

} else if (mode == 3) {

frame[2][4] = 1; frame[2][5] = 1; frame[2][6] = 1;

frame[3][7] = 1;

frame[4][5] = 1; frame[4][6] = 1;

frame[5][4] = 1; frame[5][5] = 1; frame[5][6] = 1;

} else if (mode == 4) {

frame[2][4] = 1; frame[2][7] = 1;

frame[3][4] = 1; frame[3][7] = 1;

frame[4][4] = 1; frame[4][5] = 1; frame[4][6] = 1; frame[4][7] = 1;

frame[5][7] = 1;

}



matrix.renderBitmap(frame, 8, 12);

}

My first test of this AI assistant had me a bit confused by how it shows the various lines of code that should be fixed, which caused me to make a mistake. I accidentally copied the Void Setup function twice and started to get errors in my code. After finally realizing what I had done, the code was working well. I did notice that the numbers 2 and 3 on the matrix were not as clear as I thought they could be, so I asked the Assistant if it could make the numbers clearer. It then produced the changes needed to make them look great.

changes_11

Copy Code
// Number patterns (centered)

if (mode == 1) {

frame[1][5] = 1; frame[1][6] = 1;

frame[2][6] = 1;

frame[3][6] = 1;

frame[4][6] = 1;

frame[5][6] = 1;

frame[6][4] = 1; frame[6][5] = 1; frame[6][6] = 1; frame[6][7] = 1; frame[6][8] = 1;

} else if (mode == 2) {

frame[1][4] = 1; frame[1][5] = 1; frame[1][6] = 1; frame[1][7] = 1;

frame[2][7] = 1;

frame[3][6] = 1;

frame[4][5] = 1;

frame[5][4] = 1;

frame[6][4] = 1; frame[6][5] = 1; frame[6][6] = 1; frame[6][7] = 1;

} else if (mode == 3) {

frame[1][4] = 1; frame[1][5] = 1; frame[1][6] = 1; frame[1][7] = 1;

frame[2][7] = 1;

frame[3][5] = 1; frame[3][6] = 1; frame[3][7] = 1;

frame[4][7] = 1;

frame[5][7] = 1;

frame[6][4] = 1; frame[6][5] = 1; frame[6][6] = 1; frame[6][7] = 1;

} else if (mode == 4) {

frame[1][4] = 1; frame[1][7] = 1;

frame[2][4] = 1; frame[2][7] = 1;

frame[3][4] = 1; frame[3][7] = 1;

frame[4][4] = 1; frame[4][5] = 1; frame[4][6] = 1; frame[4][7] = 1;

frame[5][7] = 1;

frame[6][7] = 1;

}



matrix.renderBitmap(frame, 8, 12);

matrix_12

Adding Fusion 360 Movement commands

At this point, the program was toggling nicely through the modes and performing well, except that it only had one mode for buttons B and C. I gave the Assistant the following prompt.

Can you set it up so that there is an option for each of the modes for both buttons B and C, and also an option for the movement based on each mode?

When the Assistant responded, the answer I received surprised me a bit. The assistant gave me the following code.

code_13

Copy Code
if (buttons.update()) {

a = buttons.isPressed(0);

b = buttons.isPressed(1);

c = buttons.isPressed(2);

}



static bool lastB = false, lastC = false;



// Keyboard/mouse controls

// Button A cycles through modes

if (a && !lastA) {

currentMode++;

if (currentMode > 4) currentMode = 1;

displayMode(currentMode);

Serial.print("Mode: ");

Serial.println(currentMode);

}

lastA = a;



// Button B - different shortcuts per mode

if (b && !lastB) {

switch(currentMode) {

case 1: Keyboard.write('r'); break; // Rotate

case 2: Keyboard.write('e'); break; // Extrude

case 3: Keyboard.write('f'); break; // Fillet

case 4: Keyboard.write('c'); break; // Circle

}

}

lastB = b;



// Button C - different shortcuts per mode

if (c && !lastC) {

switch(currentMode) {

case 1: Keyboard.write('l'); break; // Line

case 2: Keyboard.write('m'); break; // Move

case 3: Keyboard.write('s'); break; // Sketch

case 4: Keyboard.write('p'); break; // Project

}

}

lastC = c;



// Mouse movement with updated sensitivity

imu.update();

float x = imu.getX();

float y = imu.getY();



// Different movement sensitivity per mode

float modeSensitivity = sensitivity;

switch(currentMode) {

case 1: modeSensitivity *= 0.8; break; // Slower for precision work

case 2: modeSensitivity *= 1.0; break; // Normal speed

case 3: modeSensitivity *= 1.2; break; // Faster for navigation

case 4: modeSensitivity *= 1.5; break; // Fastest for quick movements

}



Mouse.move(x modeSensitivity, -1 (y * modeSensitivity));

mouseDist += abs(x modeSensitivity) + abs(y modeSensitivity);

addcommands_14

To my surprise, the Assistant was able to accurately add Fusion 360 keyboard commands to the buttons.

buttons_15

creating_16

This just made creating my project much easier. Even though I had found a page on the Fusion 360 website that called out all the keyboard commands for Fusion, I did not have to spend the time entering each of the commands for each mode. I then decided to try another prompt to see if it could add similar logic to the movement module. I typed in the following prompt.

I would like to use the movement for these Fusion 360 actions. In mode 1 - Pan, Mode 2 - Zoom, Mode 3 - Orbit, Mode 4 - Orbit around a point.

The AI assistant gave me the following code. To my surprise, it worked well.

code_17

code_18

code_19

Copy Code
if (buttons.update()) {

a = buttons.isPressed(0);

b = buttons.isPressed(1);

c = buttons.isPressed(2);

}



static bool lastB = false, lastC = false;



// Keyboard/mouse controls

// Button A cycles through modes

}

lastC = c;



// Movement-based Fusion 360 controls per mode

imu.update();

float x = imu.getX();

float y = imu.getY();



// Only process movement if there's significant motion

if (abs(x) > 0.1 || abs(y) > 0.1) {

float modeSensitivity = sensitivity * 0.5; // Scale down for smoother control



switch(currentMode) {

case 1: // Pan - Middle mouse drag

Mouse.press(MOUSE_MIDDLE);

Mouse.move(x modeSensitivity, -y modeSensitivity);

delay(10);

Mouse.release(MOUSE_MIDDLE);

break;



case 2: // Zoom - Scroll wheel

if (y > 0.3) {

Mouse.move(0, 0, 1); // Scroll up (zoom in)

} else if (y < -0.3) {

Mouse.move(0, 0, -1); // Scroll down (zoom out)

}

break;



case 3: // Orbit - Shift + Middle mouse drag

Keyboard.press(KEY_LEFT_SHIFT);

Mouse.press(MOUSE_MIDDLE);

Mouse.move(x modeSensitivity, -y modeSensitivity);

delay(10);

Mouse.release(MOUSE_MIDDLE);

Keyboard.release(KEY_LEFT_SHIFT);

break;



case 4: // Orbit around point - Ctrl + Shift + Middle mouse

Keyboard.press(KEY_LEFT_CTRL);

Keyboard.press(KEY_LEFT_SHIFT);

Mouse.press(MOUSE_MIDDLE);

Mouse.move(x modeSensitivity, -y modeSensitivity);

delay(10);

Mouse.release(MOUSE_MIDDLE);

Keyboard.release(KEY_LEFT_SHIFT);

Keyboard.release(KEY_LEFT_CTRL);

break;

}



mouseDist += abs(x modeSensitivity) + abs(y modeSensitivity);

}

}

fixing_19

Fixing the Movement issue

All the functions worked well for the movement module; however, I did find one issue with this. Since the movement uses a mouse button being held, I was not able to use the mouse to click anywhere else. After a bit of thinking, I decided that I could use button C to toggle the mouse click off and on. I then gave the AI Assistant the following command.

I need to change the functionality of it just a bit. I would like for button C to activate the mouse commands. Currently, how it is set up doesn’t allow me to toggle it off and on

toggle_20

toggle_21

Copy Code
int lastKnobPosition = 0;

int currentMode = 1; // Modes 1-4

bool mouseActive = false; // Toggle for mouse commands

void setup() {

Serial.begin(9600);

// Keyboard/mouse controls

// Button A cycles through modes

if (a && !lastA) {

currentMode++;

if (currentMode > 4) currentMode = 1;

displayMode(currentMode);

Serial.print("Mode: ");

Serial.println(currentMode);

}

lastA = a;



// Button C toggles mouse commands on/off

if (c && !lastC) {

mouseActive = !mouseActive;

Serial.print("Mouse commands: ");

Serial.println(mouseActive ? "ON" : "OFF");

}

lastC = c;



// Movement-based Fusion 360 controls per mode

float x = imu.getX();

float y = imu.getY();



// Only process movement if mouse is active and there's significant motion

if (mouseActive && (abs(x) > 0.1 || abs(y) > 0.1)) {

float modeSensitivity = sensitivity * 0.5; // Scale down for smoother control



switch(currentMode) {

After a few iterations of fixing errors, I was able to get the full code working.

zoom gif

Finished Code

Here is a copy of my final code:

Copy Code
#include "thingProperties.h"

#include <Arduino_LED_Matrix.h>

#include <Arduino_CloudConnectionFeedback.h>

#include <Modulino.h>

#include <Keyboard.h>

#include <Mouse.h>

ArduinoLEDMatrix matrix;

ModulinoButtons buttons;

ModulinoMovement imu;

ModulinoKnob knob;

ModulinoPixels pixels;

int sensitivity = 50;

int lastKnobPosition = 0;

int currentMode = 1; // Modes 1-4

bool mouseActive = false; // Toggle for mouse commands

void setup() {

Serial.begin(9600);

delay(1500);



matrix.begin();



initProperties();

ArduinoCloud.begin(ArduinoIoTPreferredConnection);

waitForArduinoCloudConnection(matrix);

setDebugMessageLevel(2);

ArduinoCloud.printDebugInfo();



Modulino.begin();



knob.begin();

buttons.begin();

imu.begin();

pixels.begin();

Keyboard.begin();

Mouse.begin();

lastKnobPosition = knob.get();

// Display initial mode

displayMode(currentMode);

}

void loop() {

ArduinoCloud.update();

updatePixelDisplay();

// Handle knob for sensitivity adjustment

int currentKnobPosition = knob.get();

int knobDelta = currentKnobPosition - lastKnobPosition;



if (abs(knobDelta) >= 1) {

sensitivity += (knobDelta > 0) ? 5 : -5;

sensitivity = constrain(sensitivity, 30, 70);

lastKnobPosition = currentKnobPosition;

updatePixelDisplay();



Serial.print("Sensitivity: ");

Serial.println(sensitivity);

}



// Reset sensitivity on knob press

if (knob.isPressed()) {

sensitivity = 50;

lastKnobPosition = knob.get();

updatePixelDisplay();

Serial.println("Sensitivity reset to 50");

}



// Button handling

bool a = false, b = false, c = false;

static bool lastA = false, lastB = false, lastC = false;



if (buttons.update()) {

a = buttons.isPressed(0);

b = buttons.isPressed(1);

c = buttons.isPressed(2);

}



// Button A cycles through modes

if (a && !lastA) {

currentMode++;

if (currentMode > 4) currentMode = 1;

displayMode(currentMode);

Serial.print("Mode: ");

Serial.println(currentMode);

}

lastA = a;



// Button B - different shortcuts per mode

if (b && !lastB) {

switch(currentMode) {

case 1: Keyboard.write('r'); break; // Rotate

case 2: Keyboard.write('e'); break; // Extrude

case 3: Keyboard.write('f'); break; // Fillet

case 4: Keyboard.write('c'); break; // Circle

}

}

lastB = b;



// Button C toggles mouse commands on/off

if (c && !lastC) {

mouseActive = !mouseActive;

Serial.print("Mouse commands: ");

Serial.println(mouseActive ? "ON" : "OFF");

}

lastC = c;



// Movement-based Fusion 360 controls per mode

imu.update();

float x = imu.getX();

float y = imu.getY();



// Only process movement if mouse is active and there's significant motion

if (mouseActive && (abs(x) > 0.1 || abs(y) > 0.1)) {

float modeSensitivity = sensitivity * 0.5; // Scale down for smoother control



switch(currentMode) {

case 1: // Pan - Middle mouse drag

Mouse.press(MOUSE_MIDDLE);

Mouse.move(x modeSensitivity, -y modeSensitivity);

delay(10);

Mouse.release(MOUSE_MIDDLE);

break;



case 2: // Zoom - Scroll wheel

if (y > 0.3) {

Mouse.move(0, 0, 1); // Scroll up (zoom in)

} else if (y < -0.3) {

Mouse.move(0, 0, -1); // Scroll down (zoom out)

}

break;



case 3: // Orbit - Shift + Middle mouse drag

Keyboard.press(KEY_LEFT_SHIFT);

Mouse.press(MOUSE_MIDDLE);

Mouse.move(x modeSensitivity, -y modeSensitivity);

delay(10);

Mouse.release(MOUSE_MIDDLE);

Keyboard.release(KEY_LEFT_SHIFT);

break;



case 4: // Orbit around point - Ctrl + Shift + Middle mouse

Keyboard.press(KEY_LEFT_CTRL);

Keyboard.press(KEY_LEFT_SHIFT);

Mouse.press(MOUSE_MIDDLE);

Mouse.move(x modeSensitivity, -y modeSensitivity);

delay(10);

Mouse.release(MOUSE_MIDDLE);

Keyboard.release(KEY_LEFT_SHIFT);

Keyboard.release(KEY_LEFT_CTRL);

break;

}

}

}

void updatePixelDisplay() {

// Clear all pixels first

pixels.clear();



// Map sensitivity (30-70) to number of pixels (1-8)

int numPixels = map(sensitivity, 30, 70, 1, 8);



// Light up pixels progressively

for (int i = 0; i < numPixels; i++) {

if (i < 3) {

pixels.set(i, 255, 0, 0); // Red for first 3 pixels (low sensitivity)

} else if (i < 6) {

pixels.set(i, 255, 255, 0); // Yellow for middle pixels (mid sensitivity)

} else {

pixels.set(i, 0, 255, 0); // Green for last pixels (high sensitivity)

}

}



pixels.show();

}

void displayMode(int mode) {

// Use byte array format for easier pixel control

byte frame[8][12] = {

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

};



// Display different numbers for each mode

switch(mode) {

case 1: // Number "1"

frame[1][5] = 1;

frame[1][6] = 1;

frame[2][5] = 1;

frame[2][6] = 1;

frame[3][5] = 1;

frame[3][6] = 1;

frame[4][5] = 1;

frame[4][6] = 1;

frame[5][5] = 1;

frame[5][6] = 1;

frame[6][4] = 1;

frame[6][5] = 1;

frame[6][6] = 1;

frame[6][7] = 1;

break;



case 2: // Number "2"

frame[1][4] = 1;

frame[1][5] = 1;

frame[1][6] = 1;

frame[1][7] = 1;

frame[2][4] = 1;

frame[2][7] = 1;

frame[3][6] = 1;

frame[3][7] = 1;

frame[4][5] = 1;

frame[4][6] = 1;

frame[5][4] = 1;

frame[5][5] = 1;

frame[6][4] = 1;

frame[6][5] = 1;

frame[6][6] = 1;

frame[6][7] = 1;

break;



case 3: // Number "3"

frame[1][4] = 1;

frame[1][5] = 1;

frame[1][6] = 1;

frame[1][7] = 1;

frame[2][7] = 1;

frame[3][5] = 1;

frame[3][6] = 1;

frame[3][7] = 1;

frame[4][7] = 1;

frame[5][4] = 1;

frame[5][7] = 1;

frame[6][4] = 1;

frame[6][5] = 1;

frame[6][6] = 1;

frame[6][7] = 1;

break;



case 4: // Number "4"

frame[1][4] = 1;

frame[1][7] = 1;

frame[2][4] = 1;

frame[2][7] = 1;

frame[3][4] = 1;

frame[3][5] = 1;

frame[3][6] = 1;

frame[3][7] = 1;

frame[4][7] = 1;

frame[5][7] = 1;

frame[6][7] = 1;

break;

}



matrix.renderBitmap(frame, 8, 12);

}

While the code does work fairly well overall, I can see that there is room for improvement. Based on that, I challenge you to take this and make it your own. I would love to see what you make. If you do put together a build, post a comment below, and we can share any tips and tricks you have found.

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.