I don't know about you, but summer is nearly here, and honestly, I have been a bit bored with my curtains. I wanted to spice up my little maker cave with fancy motorized, remote-controlled curtains. Now, I might indeed be a maker, but I am a lazy one. I do not want to drill into the wall or perform any complex metal bending, so in this project, I promise to only use a small number of parts. (cool segway onto the shopping list of this project, huh ;) )
Just a quick note before we dig inThis project is not the easiest, but I guarantee it'll be fun. I'll make sure to make all instructions and explanations beginner-friendly, so don't worry if it's your first project or if you haven't been very deeply invested in the Arduino world before; this will be a very nice experience!
What you need for the project1 x Arduino Uno Microcontroller
1 x 4 wire nema17 stepper motor
1 x Ifx stepper motor shield
1x Access to a 3D Printer (with some PLA filament, of course)
1x gt2 belt with some metal pulleys (you could get it from Amazon or your dandy hardware store)
1x IR Remote (if you have any maker kit you should probably have it but if not it's dirt cheap so don't worry)
(I assume you already have the curtains ;) )
The XMC1300 IFX9201 Stepper Shield can be put on top of the Arduino. But both need some additional hardware connections.
Shield ConnectionsAs shown in the photo above, the shield is connected to the DC power - note the red cable at the top right corner for power and the black cable at the top right corner for ground. Additionally, the motor's 4-pin connector is linked to the MOT_OUT white connector. This setup ensures that all necessary connections are in place for the system to function effectively.
Arduino ConnectionsAs noted earlier, the setup includes an Arduino Uno board, which is powered via the AC socket - notice the white cable on the left. The IR receiver module is connected with three jumper cables; these handle 5V, ground, and signal connections. The hard end of the jumper cables was cut to expose the copper, making the cables flexible. This allows for easy adjustment and positioning, enabling you to slide the shield effortlessly onto the Arduino even after the cables are connected. This thoughtful preparation ensures a tidy and functional setup.
Why choose a stepper motor?While there are numerous types of motors available, stepper motors are unique because they move in precise, discrete steps. They're controlled by sending digital pulses to the motor's driver, which is perfect for tasks requiring exact positioning—like adjusting your curtains! We need to be spot-on with the positions when the curtains are fully open or closed, and there's no margin for error here.
Sounds appealing, doesn't it? However, controlling stepper motors isn't as straightforward as just turning them on or off. Instead, they operate through a rotating magnetic field, which can seem a bit complex. But don't worry—I'm here to keep things simple for us. Essentially, think of it as if stepper motors have their own unique way of communicating!
Speaking the language of stepper motorsThis shield, the KIT_XMC1300_IFX9201, acts like our translator. It fits right on top of our Arduino, connecting to the motor and power supply. All it needs is the number of steps, the direction, and a simple enable signal. From there, it effortlessly translates these inputs into actions for the motor. It's that straightforward!
If you want to find out more about the shield and how it works, than check out our Protip!
I know the setup might look a little intimidating with all the electronics involved, but for now, just focus on a few key components: the green clamp with screws on the right, the white connector above that, and the blue potentiometer on the left.
Here’s a quick rundown:
- The green clamp handles the DC cables - it’s where you connect the ground and voltage.
- The white connector links directly to the motor’s 4-pin connector.
- The blue potentiometer acts as a safety feature, letting you manually adjust the current supplied to the motor.
It’s all quite manageable once you know what each part does!
Power SupplyTo effectively power the electronics, it's important to distinguish between the high-power needs of the motor and the lower power requirements of the Arduino. For the Arduino, I opted for a low-power solution using a 9V, 0.4 Amp AC adapter. In contrast, to accommodate the motor's higher power needs, i used a more robust 12V, 2.25 Amp DC cable. This setup ensures that both components receive the appropriate power levels for optimal performance without risking damage from over or under-powering.
Let's break the plan throughSo here's the game plan, boss! We're aiming to automate opening and closing the curtains using the power of the stepper motor. You might wonder, "How can a motor that spins around its own axis help move curtains side to side?" Well, that's where the GT2 belt and pulleys come into play. By attaching the pulleys to the motor's spinning shaft and mounting a belt over them, we can convert the motor's rotational movement into a linear motion - perfect for sliding curtains! Take a look at the diagrams below to see how it all comes together.
The first thing to note from this diagram is how the motor's spinning affects the belt. As the motor turns, both the upper and lower sections of the belt move linearly, but in opposite directions. For instance, in the diagram we're looking at above, when the motor spins clockwise, the upper side of the belt shifts to the right while the lower side moves to the left. This opposing motion is key to understanding how to utilize it for our needs.
In the diagram below, you'll see the exact opposite effect. When the motor spins counterclockwise, the upper section of the belt moves to the left, while the lower section moves to the right. By syncing this linear motion of the belt with the curtains, we can cleverly control them: turning the motor clockwise closes the curtains, and spinning it counterclockwise opens them. This simple mechanism allows for smooth and efficient control of curtain movement.
Now that we've established the belt's left and right movement, the next challenge is syncing the curtain fabric with this motion. The key lies in the rails. These rails are the crucial link between the belt and the fabric, and we need to effectively transfer motion from the rails to the fabric. If you look at the diagram below, you’ll notice how we use the Bottom and Top Belt anchors to connect what we're calling the 'rail factor'—the hooks—to the GT2 belt. This setup ensures that as the belt moves (indicated by the red arrows), the motion is seamlessly transferred to the rail (shown with blue arrows). The Fabric Hooks, which are attached to the rail, then move accordingly when they come into contact with the anchor hooks (as seen with the green arrows). This system ensures smooth and coordinated movement of the curtains.
The straightforward approach would be to drill holes in the walls and secure the motor on a mount attached to those drilled spots—and voilà! But as I've mentioned, I have a somewhat troubled history with drills (and yes, I maintain that the 8 holes behind the poster were there when I moved in!). So, I cleverly designed the system so that the motor mount and pulley mount simply clip onto the rail—no drilling required. Don't worry, I’ll provide the.stl files for everything you need!
Motor MountAs you can see in the image below, the motor mount is designed almost like a cage. This allows the motor to slide right in. I've crafted it with a frame that fits perfectly on the left side of the belt. But no worries—I'll provide the design files, so if you have different ideas for your setup, you can easily modify the design before 3D printing it. This way, you can tailor everything to fit your specific needs.
The pulley is meticulously designed to match the motor's appearance, parameters, and metrics. I've created pulleys that fit snugly on the belt, positioned between the left and right edges, and another right at the right edge to complement the motor mount on the left. This ensures a seamless and balanced setup for optimal performance.
This is an optional step, but for added security, I designed a lid that fits snugly over the top of the pulley edge. I personally used hot glue to secure it in place. This ensures that even if the belt is tensioned to the maximum, it won't slip off the pulley. This small addition can help prevent mishaps and keep your setup running smoothly.
Belt ConnectorUse this connector to join the two ends of your GT2 Belt after determining the appropriate length for your needs and cutting it to size. This will ensure a snug and secure fit, enabling smooth and efficient operation of your setup.
Anchor System (Connecting the Belt with the Rail)To effectively transfer the belt's motion to the curtains, we need a robust connection. That's why I've designed an Anchor, which consists of two parts. The first part slides into the GT2 belt and features a hole in the middle, allowing you to secure it with a zip tie for a tight connection at the center. Additionally, the edges of the Anchor have small openings at the top on each side, designed for zip ties to further secure the ends.
The main aim here is to ensure an extremely tight and stable connection that remains unaffected by any force applied, preventing any tilting. There's also a large rectangular hole in the center of the Anchor, which is meant for the anchor hooks to slot in precisely like a lock and key, ensuring a seamless and secure fit.
These hooks are what connect the fabric of the curtains with the rails.
During testing, I discovered a significant issue: the horizontal force from the belt caused the anchor hooks to tilt, which in turn increased friction as these hooks began exerting force on the regular hooks. To mitigate this, I devised a suspension system designed specifically to lessen the tilting of the anchor hooks and reduce the resulting friction from the regular hooks' contact.
The solution I chose involves magnetism. I had some common fridge magnets on hand, so I designed a special enclosure for them that also fits onto the rails. This magnetic setup helps to stabilize the hooks by evenly distributing the forces, effectively reducing tilting and ensuring smoother operation.
To set up our system, you'll need two of the printed magnetic slides. Place the hook between them. The objective here is for the magnets to attract each other, creating a firm grip on the hook while simultaneously providing a repulsive force to other nearby hooks. One of the unique features of these magnets is their irregular shape, which produces a distinctive magnetic field that is denser at the flat end. This design ensures that there is no attraction when the spherical ends are not aligned, and a strong repulsion occurs when the flat ends meet. This clever arrangement enhances the functionality and efficiency of our setup.
This step is optional, but to further secure each suspension unit, you could use rubber bands. Any type will work—I just used some that were available at the supermarket checkout. You likely have some lying around at home; even hair ties would do the trick. This simple addition helps ensure everything stays tightly in place, enhancing the stability of your setup.
Check out the photos and GIF below!
Now that you're familiar with nearly all the hardware needed for the curtains, let's dive into the wireless control methodology. Next, we'll explore the infrared remote control, including its library and how we can effectively use it to operate our system. This will give you the tools to manage your curtains remotely, adding convenience and a touch of tech-savvy sophistication to your setup.
IR REMOTEThere are numerous types of remotes available, but the one shown in the photo below is particularly common and can be found at very affordable prices online. This type of infrared remote operates using a protocol known as NEC, which is widely used due to its reliability and ease of integration.
The remote package includes:
- The remote itself (yes, Captain Obvious at your service!)
- An IR Receiver
The receivers come equipped with three pins, and the arrangement of these pins can vary depending on the model. Typically, you'll find configurations like GND, voltage, and signal, although sometimes the order is reversed. Regardless of the arrangement, you can always find the specific pin placement details in the documentation for the model you purchase, usually available on the website from which you buy it.
Calibrating the RemoteSince not all remotes are created equally, we need to figure out which buttons on your remote correspond to specific command numbers. This will allow us to program the curtain controls effectively. The first step is to install the infrared library. Here’s how to do it in your Arduino IDE:
- Click on "Tools."
- Then, select "Manage Libraries."
- In the window that appears, search for "infrared."
- Install the library shown in the screenshot below.
This setup will enable us to start programming your remote to control the curtains.
Now that the library is installed, we can start using it to understand how the Arduino interprets the commands it receives from the remote. A quick note: instead of connecting the receiver to the standard 5V pin, I opted to connect it to one of the GPIO pins. To achieve this, I set the logic level of GPIO pin 53 to high, simulating a 5V pin. If you prefer a simpler setup, you can just connect the receiver to a 5V pin directly. Also, I'm connecting the signal pin to pin 52.
To tailor the code to your specific setup, change the RECEIVE_PIN definition in the code to the pin connected to your signal receiver. This flexibility allows you to adapt the setup to suit your hardware configuration.
#include <IrReceiverSampler.h>
#include <Nec1Decoder.h>
static constexpr pin_t RECEIVE_PIN = 3U;
static constexpr size_t BUFFERSIZE = 200U;
static constexpr uint32_t BAUD = 115200UL;
uint8_t receivedSignal = 0;
static IrReceiver *receiver;
void setup() {
Serial.begin(BAUD);
while (!Serial);
receiver = IrReceiverSampler::newIrReceiverSampler(BUFFERSIZE, RECEIVE_PIN);
}
void loop() {
receiver->receive();
if (receiver->isEmpty())
Serial.println(F("timeout"));
else {
Nec1Decoder decoder(*receiver);
receivedSignal = decoder.getF();
Serial.println(receivedSignal);
}
}
When you open the serial monitor, set the baud rate to 115200 and begin pressing some buttons on your remote to test it out.
Note: A common oversight to be aware of—I've made this mistake myself—is that most IR remotes are shipped without batteries. You'll need to purchase a coin cell battery and insert it into the compartment at the back of your remote to get it up and running.
When you run this Arduino program and observe the serial monitor, you'll see numbers displayed as soon as you press a button on the remote. These numbers are captured in the receivedSignal variable. This variable is crucial because it's what we will be using throughout the full code to manage the curtains. It effectively translates each remote button press into a specific action in our curtain control system.
Curtains SoftwareWhat do we want from our Arduino?We want our microcontroller to effectively decode IR commands from our remote, giving us several handy options:
- Fully open the curtains from any position.
- Fully close the curtains from any position.
- Partially close the curtains.
- Partially open the curtains.
Additionally, we'll set up the Arduino with limits on the motor's rotation to ensure safety and prevent mechanical issues. Even if the Arduino is disconnected from power, or if a button is pressed excessively, these limits will stop the motor from rotating too far, preventing the anchors from moving over the pulleys and potentially causing the belt to crash.
So, take a step back, relax, and buckle up—we're going to walk through all of this now.
Stepper Motor LibraryIn your Arduino IDE click on Tools and Manage Libraries (Press CTRL+Shift+I) for short. The Library Manager window should pop up (sometimes it takes a couple of seconds to load). Then search for IFX9201_XMC1300_StepperMotor and click Install.
After installing the library, you might want to explore the examples provided to get a feel for how it works. Alternatively, you can check out this pro tip that details its usage (CLICK HERE!). This will give you a solid foundation before you dive into the coding. Don’t worry—I’m providing all the resources you need to get started smoothly!
Rotations Control For LimitsWhether you prefer moving the belt manually or using a remote that controls the motor by either one rotation per button press or 100 steps per rotation—whichever method suits you—make sure to measure how many steps it takes to fully open and close your curtains. For my setup, it takes 20 full revolutions to move from fully open to fully closed, and vice versa. It's crucial to know this because, as you're aware, we have anchors on the belt. We need to ensure that the motor doesn't attempt to rotate these anchors over the pulleys, as this could lead to a crash and potentially cause the entire belt system to collapse.
What is the EEPROM?EEPROM stands for Electrically Erasable Programmable Read-Only Memory. This might sound complex, but it's simply a type of memory on the microcontroller where you can save data that remains even when the Arduino is turned off. Can you think of how this could be useful? We're going to use it to save the position of the motor. This way, if there's a power outage or you disconnect and reconnect the microcontroller to power, the motor won’t attempt to over-rotate, which could cause issues. This feature ensures your system remembers its last position and operates smoothly and safely upon restart.
Project CodeLibrary Inclusion#include <IrReceiverSampler.h>
#include <Nec1Decoder.h>
#include <EEPROM.h>
#include <IFX9201_XMC1300_StepperMotor.h>
- IR Receiver Libraries:
IrReceiverSampler.h and Nec1Decoder.h: These handle the IR signals from the remote.
- EEPROM Library:
EEPROM.h: This allows us to save data (like the motor position) that persists even when the Arduino is powered off.
- Stepper Motor Control Library:
IFX9201_XMC1300_StepperMotor.h: This library is specific to the IFX9201 stepper motor shield and helps control the stepper motor with precision.Key Variables and Setup
static constexpr pin_t RECEIVE_PIN = 3U;
static constexpr size_t BUFFERSIZE = 200U;
static constexpr uint32_t BAUD = 115200UL;
uint8_t receivedSignal = 0;
int8_t revolutionsCounter = 0;
static IrReceiver *receiver;
#define DIR_PIN IFX9201_STEPPERMOTOR_STD_DIR
#define STP_PIN IFX9201_STEPPERMOTOR_STD_STP
#define DIS_PIN IFX9201_STEPPERMOTOR_STD_DIS
const int StepsPerRevolution = 200;
const int MaxRevolutions = 20;
Stepper_motor MyStepperMotor = Stepper_motor(StepsPerRevolution, DIR_PIN, STP_PIN, DIS_PIN);
- RECEIVE_PIN: The pin connected to the IR receiver's signal pin.
- BUFFERSIZE and BAUD: Parameters for serial communication and buffer size.
- receivedSignal and revolutionsCounter: Track the received IR signal and the current motor position.
- DIR_PIN, STP_PIN, DIS_PIN: Pins for controlling the stepper motor.
- StepsPerRevolution and MaxRevolutions: Define the motor's steps per revolution and the maximum number of revolutions for full curtain movement.
void setup() {
Serial.begin(BAUD);
while (!Serial);
receiver = IrReceiverSampler::newIrReceiverSampler(BUFFERSIZE, RECEIVE_PIN);
pinMode(53, OUTPUT);
digitalWrite(53, HIGH);
revolutionsCounter = EEPROM.read(0); // Read stored position from EEPROM
}
- Serial.begin(BAUD): Initializes serial communication.
- receiver = IrReceiverSampler::newIrReceiverSampler(...): Sets up the IR receiver.
- revolutionsCounter = EEPROM.read(0): Reads the last saved motor position from EEPROM to ensure continuity after a power cycle.
void loop() {
receiver->receive();
if (receiver->isEmpty())
Serial.println(F("timeout"));
else {
Nec1Decoder decoder(*receiver);
receivedSignal = decoder.getF();
Serial.print("Revolutions Counter: ");
Serial.println(revolutionsCounter);
switch (receivedSignal) {
case 90:
if (revolutionsCounter < MaxRevolutions) {
MyStepperMotor.begin();
MyStepperMotor.setSpeed(100);
MyStepperMotor.move_revolution(1);
revolutionsCounter++;
EEPROM.write(0, revolutionsCounter);
MyStepperMotor.end();
} else {
Serial.println(F("Curtain already fully closed"));
}
break;
case 8:
if (revolutionsCounter > 0) {
MyStepperMotor.begin();
MyStepperMotor.setSpeed(100);
MyStepperMotor.move_revolution(-1);
revolutionsCounter--;
EEPROM.write(0, revolutionsCounter);
MyStepperMotor.end();
} else {
Serial.println(F("Curtain already fully opened"));
}
break;
case 13:
if (revolutionsCounter < MaxRevolutions) {
int stepsToClose = MaxRevolutions - revolutionsCounter;
MyStepperMotor.begin();
MyStepperMotor.setSpeed(100);
MyStepperMotor.move_revolution(stepsToClose);
revolutionsCounter = MaxRevolutions;
EEPROM.write(0, revolutionsCounter);
MyStepperMotor.end();
} else {
Serial.println(F("Curtain already fully closed"));
}
break;
case 22:
if (revolutionsCounter > 0) {
int stepsToOpen = revolutionsCounter;
MyStepperMotor.begin();
MyStepperMotor.setSpeed(100);
MyStepperMotor.move_revolution(-stepsToOpen);
revolutionsCounter = 0;
EEPROM.write(0, revolutionsCounter);
MyStepperMotor.end();
} else {
Serial.println(F("Curtain already fully opened"));
}
break;
default:
Serial.println(F("Invalid command"));
break;
}
}
}
- receiver->receive(): Continuously checks for IR signals.
- Nec1Decoder decoder(*receiver): Decodes the received IR signal.
switch (receivedSignal): Executes different actions based on the received IR signal:
- 90: Close the curtains one step.
- 8: Open the curtains one step.
- 13: Close the curtains completely.
- 22: Open the curtains completely.
- default: Handle any invalid commands.
The EEPROM is used to store the current position of the curtains. This ensures that even if the power is lost, the Arduino remembers the last position of the curtains when it powers back up.
Porting the CodeTo port this code for your setup:
- Adapt the Pin Configuration: Ensure the pins defined in the code match those used in your hardware setup.
- Calibrate Steps and Revolutions: Adjust
StepsPerRevolution
andMaxRevolutions
according to your motor and curtain system. - Test the IR Remote: Ensure the IR remote you are using has the same command codes. If not, you may need to update the
switch (receivedSignal)
cases to match your remote’s codes.
By following these steps and understanding each part of the code, you can effectively adapt this project to control your own motorized curtains.
This deserves a celebration but before we pull the full stop I wanna share one last optimization I did to polish the curtains
To refine the aesthetics of the curtain setup, I opted to hang some foam boards that I picked up from my local stationery shop. This addition covers the mechanical parts of the curtains, giving them a sleeker look and facilitating smoother motion. While this step is entirely optional, I thought it was worth mentioning before we wrap things up—it might just be the finishing touch your project needs!
You did it! You've just built a slick curtain control system that reacts to IR signals like a champ. Now you can open and close your curtains with just a click. Here's a quick recap of the cool stuff you nailed:
- IR Signal Reception and Decoding: Your setup continuously listens for and decodes IR signals like a pro.
- Command Execution: You set up a switch case to handle different commands for precise curtain moves.
- EEPROM Usage: Using EEPROM to save the curtain position ensures that even if the power goes out, your setup remembers where the curtains were.
Not only did you automate your curtains, but you also showed off your skills in embedded systems and Arduino. Great job! Now kick back and enjoy the ease of your new curtain system. Maybe even think about adding more features or hooking it up with other smart home gadgets. You’re on a roll!
Feel free to share your curtain projects with us and the rest of the maker community—I’ll kick things off with mine! Also, if you have any questions or need assistance with any details, don't hesitate to leave a comment. We’re here to help each other out!
Comments
Please log in or sign up to comment.