Motorized Sit or Stand, Landscape or Portrait Monitor (Arduino + Autohotkey)

by jwolin in Circuits > Electronics

4720 Views, 37 Favorites, 0 Comments

Motorized Sit or Stand, Landscape or Portrait Monitor (Arduino + Autohotkey)

2017-10-05 15.20.21.jpg
Motorized Sit or Stand, Landscape or Portrait Monitor (Alexa + Arduino + Autohotkey)
2017-10-05 14.43.16.jpg
2017-10-05 14.42.27.jpg

I have always wanted a way to mindlessly manage the real-estate of my monitors so as to maximize the screen for a particular application. Some applications perform wonderfully in landscape mode but terribly in portrait and vice versa. The hassle of manually rotating the monitors (i.e cable management, computer settings, disruption) prevents many from actually doing it and thus living with a sub-optimal experience. This solution controls optimal orientation of a single monitors in a quick, powerful and automatic fashion. Truly a cutting edge experience!

In addition to providing an easy way to arrange my monitors I wanted a way to quickly take my workstation from a sitting configuration to a standing one. So, I put the whole setup on a home-baked linear actuator that raises and lowers with a keyboard stroke!

I used components I had laying around from other CNC related projects so the solution represented here is a proof-of-concept and SERIOUS overkill from what would be needed; a much cheaper and simpler solution should be designed by others but I will share my component list nonetheless

  • 1 rotary actuators and associated controllers
  • Aluminum plate for Vesa Mounts
  • Aluminum Extrusion
  • 1x8 wood
  • 24" linear actuator
  • Hbridge motor controller BTS7960 43A
  • Rollon Linear Bearings
  • MDF
  • Various screws and hardware

Building a Vertical Actuator

2017-08-26 17.21.11.jpg
2017-08-28 20.14.36.jpg
2017-09-04 14.35.15.jpg
2017-09-04 15.26.40 HDR.jpg
2017-08-28 20.01.49.jpg
E3218EB9-018F-4239-8DB6-BE63BE8310DB.jpeg
2017-08-28 20.02.01.jpg
0439E3EC-EC1F-4CC8-9D09-B52B0F79F5FA.jpeg
2017-08-28 20.03.03.jpg
C246694A-A4B8-4593-892F-2F487C7D77A9.jpeg
2017-08-28 21.07.52.jpg
2017-09-04 15.36.23.jpg
2017-08-28 20.02.58.jpg
2017-09-04 15.14.17.jpg
2017-09-04 15.14.31.jpg

Basically what we are doing here is making an actuator that will raise and lower the keyboard/monitor worksurface. To accomplish this we us 2 sets of Rollon Rails. These are heavy duty rails that can support a lot of weight and are designed for industrial applications. We will steal the carriages from one to double up the supporting strength and use the rails from the other as the support structure that will hold the vertical piece of aluminum extrusion.

In order to attach the spare rails to the carriages we need to drill and tap them, but the rails are made from hardened steel. Drill bits laugh at you when you try to drill through hardened steel so you need to laugh at the harden steel by softening it with a torch. Eventually the steel yields and once the color has turned, you know the properties have changed. Allow to cool and you can drill and tap as expected.

The frame that actually supports the rails and actuator is just scrap plywood I had laying around. I had to cut a hole with my hole-saw to make room for the motor at the base of the actuator.

The actuator I purchased (shipped straight from China via ebay), doesn't come with any method of attaching to either the base or the actuator. So I fabricated some brackets for that purpose. You can see the actuator in various stages of construction here. Any actuator you build might take inspiration from some of these ideas.

Machine the VESA Mounts and Adapter Plates

unnamed.jpg
3d assembly.JPG
linear plate dimensions.JPG
linear plate.JPG
2017-08-28 20.02.20.jpg
2017-09-16 04.33.06.jpg
2017-08-28 20.02.23.jpg
2017-09-04 14.54.50.jpg

We need to focus on the mechanics of things and get all the physical degrees of freedom properly functioning so up next is the monitor VESA mounts. These will likely need to be custom to whatever setup you have but I'll attach both the CAD files and the images of my exact setup in the event it helps others. In the photos here I'm machining my VESA mounts. VESA is a standard hole space sizing so manufactures can make mounts that work across many monitors. I'm making my own that will both attach to the rotary access on one side and the monitor on the other. You can see the finished product nicely secured to the aluminum frame as well as to the monitor. As a side note: I re-purposed some aluminum that had holes from a previous project so that's why there are "extra" holes that aren't on the drawings.

Control the Linear Actuator

PWM motor test
FRV794BHUL8W14L.MEDIUM.jpg
s-l1600.jpg

The linear actuator is controlled with an inexpensive BTS7960 43A motor controller. The BTS 7960 is a fully integrated high current half , bridge for motor drive applications , comes with Two package as in pictures .The Operating Voltage of 24V And Continuous current of 43A Max , PWM capability of up to 25 kHz combined with active freewheeling. I basically used these exact instructions from this instructables to move the motor and then modified it to fit my needs. The video shows my test bench setup controlling a 24VDC wheelchair motor. After successful implementation here, I wired up the actuator and modified the code for my purposes. Basically this code just turns on the motor for a specified period of time and shuts it off. Since the actuator has limit switches built in, it's not critical that the actuator be raised and lowered a precise amount. It's just important to get it in the ballpark and the limit switch takes care of the rest. Here's the relevant section of the arduino code I used:

<p>int RPWM=0;<br>int LPWM=1;
int enable = D2;   
int direction = D4; 
int direction1 = D5; </p><p>void setup() {
  // put your setup code here, to run once:
  for(int i=0;i<9;i++){
   pinMode(i,OUTPUT);
  }
   for(int i=0;i<9;i++){
   digitalWrite(i,LOW);
  }</p><p>pinMode(enable, OUTPUT);
digitalWrite(enable, HIGH);  
pinMode(direction, OUTPUT);
pinMode(direction1, OUTPUT);</p><p>  Particle.function("rotatetall", tall);
  Particle.function("rotatewide", wide);
  Particle.function("moveup", up);
  Particle.function("movedown", down);
  Particle.function("adjustup", upsmall);
  Particle.function("adjustdown", downsmall);
  }</p><p>void loop() {</p><p>}</p><p>int up(String command)
{
 
for(int i=0;i<256;i++){
  analogWrite(RPWM,i);
}</p><p>delay(15000);  //how long the actuator travels</p><p>for(int i=255;i>0;i--){
  analogWrite(RPWM,i);
}</p><p>}</p><p>int upsmall(String command)
{
 
for(int i=0;i<256;i++){
  analogWrite(RPWM,i);
}</p><p>delay(2500);  //how long the actuator travels</p><p>for(int i=255;i>0;i--){
  analogWrite(RPWM,i);
}</p><p>}</p><p>int down(String command)
{
for(int i=0;i<256;i++){
  analogWrite(LPWM,i);
}</p><p>delay(15000);</p><p>for(int i=255;i>0;i--){
  analogWrite(LPWM,i);
}</p><p>}</p><p>int downsmall(String command)
{
for(int i=0;i<256;i++){
  analogWrite(LPWM,i);
}</p><p>delay(2500);</p><p>for(int i=255;i>0;i--){
  analogWrite(LPWM,i);
}</p><p>}</p><p>int tall(String command)
{
digitalWrite(enable, LOW);  
digitalWrite(direction, LOW);
digitalWrite(direction1, HIGH);
delay (2000);
digitalWrite(enable, HIGH); </p><p>}</p><p>int wide(String command)
{
digitalWrite(enable, LOW);  
digitalWrite(direction, HIGH);
digitalWrite(direction1, LOW);
delay (2000);
digitalWrite(enable, HIGH); </p><p>}</p>

Triggering Events With AutoHotkey and Arduino (The Arduino Part)

shopping.jpg

First of all we need to understand the desired usage of this assembly in real life. In the envisioned setup, the user will have many windows open and will not want the monitors constantly adjusting as he switches applications. However, there will be times when the user is going to be in a particular setup where he will want to make monitor configuration changes as easily and hassle-free as possible. To accomplish this, we will setup a special hotkey (F6 in this case) that will allow the user to make all necessary changes with a simple press of a button. Our software will sense both which windows are opened and which specific window is active, and based on predefined preferences, will adjust the monitors accordingly. For example, let's say that a user has Microsoft Word opened and active with a predefined preference of portrait and on the second monitor he has Excel open with a predefined preference of landscape. Pressing the hotkey F6 will center the first monitor (MS Word) and spin it to portrait mode since it is active and spin to landscape the secondary monitor (MS Excel). Make sense? Okay, now how do we do that?

Now to understand and apply how the triggering of events happens we have to dig into the relationship between Autohotkey and Arduinio. This is the real magic of the automation. On the arduino side I am using a MKRZero board which is basically an Zero in a smaller form factor.

From a conceptual point of view what we are doing is using autohotkey to sense events in the windows environment which then sends a serial character to the arduino zero which then triggers monitor movement. For example, the user presses F6, autohotkey senses that Microsoft Word is currently active. To spin monitor one to portrait autohotkey must sending an ascii character over serial to the arduino and the arduino must then send the appropriate signals to the control drivers.

In order to illustrate the principle of how we trigger events from hotkeys, consider the the follow piece of code. All this code does is listen on the serial port for a "o" or and "s". If it reads an "o" from the serial port it turns the onboard LED off. If it reads an "s" it turns the onboard LED on. To test this code, first upload it and then use a PuTTy terminal or something similar to connect. Watch the LED turn on and off. Cool! Never get tired of controlling LEDs! Now you understand how to control and LED from a terminal. But how can we do that from the F6 function key? Next step!

char serialin;
  void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT); 
  digitalWrite(LED_BUILTIN,LOW);  //initialize off
  }
void loop() {
  //Verify connection by serial
  while (Serial.available() > 0) {
    //Read Serial data and push to serialin
    serialin = Serial.read();
    //If serialin is equal to 'o' LED off 
    if (serialin == 'o'){ 
      digitalWrite(LED_BUILTIN,LOW); 
      }
    /*serialin is equal to 'c' LED on 
    else if (serialin == 'c'){ 
      digitalWrite(LED_BUILTIN,HIGH);
      }
      Serial.println(serialin);
  }
}

Triggering Events With AutoHotkey and Arduino (The Autohotkey Part)

ahk_logo.jpg
2017-05-10 12.32.06

Autohotkey is the brains behind the windows automation. The software is designed to be an automation and scripting tool for windows and I use it for all sorts of things. What it is doing here is simple effective. The code to send serial data from the PC is delightfully easy to do. When the F6 button is pressed the code looks to see if Microsoft Word is the active window. If it is, it will essentially pull up a command prompt and execute the command: echo c > COM6

echo.exe is a windows utility that echos in ascii characters whatever you tell it (in this case the character "c") out the COM port specified (in this case COM6). Pretty simple. Hint- If you want the MSDOS shell window to be invisible add ", , Hide" to the end of the hotkey script so that it looks something like this: RunWait, cmd /c echo c > COM6, , Hide

The video shows the autohotkey script here interacting with the arduino script in the previous step. The communication between software and hardware should be more clear. Now all we have to do is take that event trigger and make some motors move! Let's do it!

^f6::
{
SetTitleMatchMode, 2
IfWinActive Word
{
RunWait, cmd /c echo o > COM6	
}
return
}

Add a Keyboard Tray and Build a Electronics Box With Bling!

2017-09-27 09.34.12.jpg
2017-09-27 09.37.15.jpg
2017-09-27 09.37.19.jpg
7D24D030-7310-479F-A09F-FA5B703B34DA.jpeg

Here I've made a simply keyboard tray out of 3/4 MDF with my CNC machine. The tray simply bolts to the bottom of the aluminum extrusion and actually has surprising rigidity. I wasn't certain how strong it would be but it turns out to be plenty rigid for both sitting and standing configurations. The electronics are housed in a box and those electronics need to breath so I machined a fancy cover for my electronics box from 1/4 MDF. I also purchased straight from amazon a laptop holder so I can position my laptop directly beneath my screen. Since I like to walk and work on my lifespan treadmill, I incorporated the treadmill controller into the 'console' you can see in the photo.

Enjoy the Fruits!

2017-10-05 14.42.51.jpg

This project has exceeded my expectations in terms of usefulness. I love the versatility of sitting, standing, walking! It's great to have quick ability to rotate the display for optimal setup. Tip: I use Input director to have a single keyboard and mouse between the two computers. It's a great way to move between the two devices. You can even copy and paste! As another little side note, I screwed an iphone mount to the mouse pad area to hold my device. That seems to work pretty well. Hope this instructable inspires you to explore more creative (and of course automated) ways to position your workstation.