YOU CAN FIND ALL THE TUTORIAL FILES ALREADY DONE HERE! https://drive.google.com/drive/folders/1rsX0B4-FVEz7sqbKhTE4KWZDgFgdbHJM?usp=sharing
If you are like me two weeks ago, you're probably wondering how to connect your Arduino UNO to Construct 3, to turn on LEDs or use any Arduino element with Construct as a controller.
There are multiple ways that allow you to do this, but I didn't quite manage to make any of them work.
Here's the one that worked for me (and the easiest!).
The basics:
SENDING A MESSAGE TO ARDUINO
Construct 3 sends an instruction using WebSocket to the Node.js server > Node.js server "translates" it into a serial port input > Arduino receives the serial port input.
The Tutorial:
In this tutorial, we will create a Construct 3 project that allows us to send a signal to the Arduino to turn on an LED, and use an Arduino button as a trigger for code in Construct 3. This tutorial assumes you have a basic understanding of Arduino coding and electronics.
We will begin by connecting a button to pin 2 and an LED to pin 13.
Once the electronics setup is complete, we can proceed.
We will start by creating a Node.js server. Begin by visiting https://nodejs.org/en and downloading/installing the latest version.
Once this is done, create a folder for your server and open CMD on your computer.
Use "cd" to navigate through folders with CMD. If you're unfamiliar with how to do this, here's a simple tutorial made by Russell Thackston: https://www.youtube.com/watch?v=9zMWXD-xoxc&ab_channel=RussellThackston
Once you've located the folder you created previously, type the following commands.
(One by one, and wait until the command is done to input the next one)
npm init -y
npm install serialport
npm install express
npm install ws
type nul > server.js
Once this is done, if no errors are encountered, you should be able to see new files in your folder!
Open now server.js using notepad or whatever program you use.
Paste the following code (THIS HAS BEEN UPDATED TO ALLOW THE PROGRAM TO INSTANTLY DETECT WHICH PORT USES ARDUINO UNO!):
const { SerialPort } = require('serialport');
const { ReadlineParser } = require('@serialport/parser-readline');
const { Server } = require('ws');
async function findArduinoPort() {
try {
const ports = await SerialPort.list();
if (ports.length === 0) {
throw new Error('No serial ports found');
}
for (const port of ports) {
console.log(port); // Log the ports to see their details
if (port.manufacturer && (port.manufacturer.includes('Arduino') || port.manufacturer.includes('wch.cn'))) {
return port.path;
}
}
throw new Error('Arduino not found');
} catch (error) {
console.error('Error listing ports:', error);
}
}
function startServer(portPath) {
const port = new SerialPort({ path: portPath, baudRate: 9600 });
port.on('open', () => {
console.log('Serial Port Opened');
});
port.on('error', function(err) {
console.log('Error: ', err.message);
});
// The ReadlineParser will emit data once a newline is received
const parser = port.pipe(new ReadlineParser());
// Set up WebSocket server
const wss = new Server({ port: 8080 });
wss.on('connection', function connection(ws) {
console.log('A client connected');
// When a WebSocket message is received
ws.on('message', function incoming(message) {
console.log('received from WebSocket client: %s', message);
// Write to the Arduino serial port with a newline
port.write(message + '\n', function(err) {
if (err) {
return console.log('Error on write: ', err.message);
}
console.log('message written to Arduino');
});
});
// When data is received from the Arduino, send it to the WebSocket client
parser.on('data', function(data) {
console.log('received from Arduino: ', data);
ws.send(data);
});
});
wss.on('error', function(err) {
console.log('WebSocket Server Error: ', err.message);
});
console.log('WebSocket server started on ws://localhost:8080');
}
// Keep the script running
function keepAlive() {
setTimeout(keepAlive, 1000);
}
(async () => {
try {
const arduinoPortPath = await findArduinoPort();
if (arduinoPortPath) {
console.log('Arduino found on port:', arduinoPortPath);
startServer(arduinoPortPath);
} else {
console.log('Arduino not found');
}
} catch (error) {
console.error('Failed to find Arduino port:', error);
// Retry after a delay
setTimeout(() => {
(async () => {
try {
const arduinoPortPath = await findArduinoPort();
if (arduinoPortPath) {
startServer(arduinoPortPath);
}
} catch (error) {
console.error('Retry failed: ', error);
}
})();
}, 5000); // Retry every 5 seconds
}
// Start the keep-alive loop
keepAlive();
})();
Once this is done, you can close the programm.
Create now a new file named "RUNSERVER.cmd" on the same folder. Inside this file input the following command and close it: "node server.js" (without the ")
This will allow you to open the server just clicking on this file and not loading it on cmd.
Now if you open the file it should say something like "WebSocket server started on..."
This means everything is working.
Now open Arduino IDE. In here, the code will change for everyone but for using only leds and buttons, just paste this code right here:
const int buttonPin = 2; // Pin number for the button
const int ledPin = 13; // Most Arduinos have an LED on pin 13
int lastButtonState = HIGH; // the previous state of the button
int currentButtonState; // the current state of the button
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // Initialize the button pin as an input with an internal pull-up resistor
pinMode(ledPin, OUTPUT); // Initialize the LED pin as an output
Serial.begin(9600); // Start serial communication at 9600 baud rate
}
void loop() {
currentButtonState = digitalRead(buttonPin); // read the button state
// compare the button state to its previous state
if (currentButtonState != lastButtonState) {
// if the state has changed, increment the counter
if (currentButtonState == LOW) {
// if the current state is LOW then the button went from off to on:
Serial.println("Button pressed");
}
// Delay a little bit to avoid bouncing
delay(10);
}
// save the current state as the last state, for next time through the loop
lastButtonState = currentButtonState;
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n'); // Read the incoming data as a string until a newline character is found
if (command == "LED ON") {
digitalWrite(ledPin, HIGH); // Turn on the LED
} else if (command == "LED OFF") {
digitalWrite(ledPin, LOW); // Turn off the LED
}
}
}
Once finished, send the code to your Arduino. IMPORTANT, You now need to close Arduino IDE, if two programs are reading from the serial it doesn't work.
Now on construct it's really easy. Start by adding a Button or some type of player input, and the WebSocket Object.
Here's the basic code:
In this code, the user must click on the button to connect to the WebSocket server. This step is crucial because a connection always requires user interaction. When the button is clicked, the Arduino sends a message to the server. Upon receiving a message, it updates a variable to the name of the WebSocket text sent by the Arduino.
It's important to "trim" this received text because, without this step, it WILL NOT WORK. Once this command is received, the button can be programmed to perform any desired action.
How do we activate the LEDs now? Simply add an action to send WebSocket text. In this specific case, use "Open LED" or "Close LED" to control the LEDs.
EXAMPLE:
That's it! I'm sure there's infinetly easier ways of doing it, but this is the one i managed to make it work. Hopefully this tutorial will help people have less headaches on the future, and happy programming!