Friday, September 1, 2023

Off-Road UTV Dump Cart

 The planning process began with online research to collect ideas regarding dump carts. Initial inspiration was the Polar HD trailers. I also liked the Bosski trailers I particularly liked the tandem walking arms, but I decided this was excessive for the size of my property especially considering it's mostly flat. It did need to have a dump that could be electrified if necessary, but also balanced well to dump manually.



I was very meticulous with tracking the cost of the cart. I ordered some pieces pre-cut where it made sense, while others I cut myself to keep costs down. Metals Depot has very reasonable prices, but through Covid and over the course of the project metal prices did climb dramatically. For instance, in July of 2020 a 2"x2"x2'10" piece of 11 gauge steel tube was $16.96. In July 2021 I ordered another piece of the same tubing, but 2'8" for $35.69!

I really love the look of the Carlisle HD Field Trax tires, but they are pricey. I couldn't justify it since bald tires would work fine for the application. I opted for some knock off Ocelot P3026 4-Ply tires in size 20x10x10. Here they are standing next to standard 16" Garden tractor tires. I mounted them on 10x8 black steel wheels for a golf cart. Mounting them turned into quite the adventure, but I got it sorted after buying tome tire irons at the old HF.
Costs:
Metal - 207.01
Tires - $103.50
Wheels + Trailer Axles - $143.05
All of the steel for the dump bed was actually recycled from an old kitchen table! This probably saved me at least $100 given how much metal prices had shot up.

A teaser layout of the sub-frame. Next post I will show the fabrication of the dump bed hinges and axle "holders".


Graduation from ASU in Fall 2023

 I didn't realize this until I recently check my blog, but my last post coincides quite clearly with returning to complete my undergraduate degree. In Fall of 2017 I started taking courses at Arizona State University:


And here I am all this time later, taking my last semester of my Electrical Engineering degree:

This has been far from a typical college experience starting all the way back in 2004 when I gradated high school and went to Vanderbilt University. It has been a long and bumpy ride, but I am finally at the finish line. So in honor of this completion I would like to try and post a little more regularly one this blog to document my adventures & hobbies again. I will be playing a little bit of catch up to show the few projects I've tackled while in school. Please bare with me. Thanks!


Saturday, March 11, 2017

Setting up LinuxCNC for Arduino & Extruder Controller

I will be using an Arduino to control the heaters on my 3020 3D Printer. LinuxCNC will send commands to the Arduino through the USB port and heater temperatures will be set on the LinuxCNC GUI. I did this using LinuxCNC 2.5.0 and 2.6.4, but it should work with most versions.

This work was originally done by Sam Wong using an older version back when it was called EMC. So some things have changed slightly. Here are the steps!

1) Install pyserial 2.7.13 (I have not tried 3.6.0, let me know if it works okay)
https://pypi.python.org/pypi/pyserial
- Extract to your user folder
- Open the terminal to the pyserial folder
- Then "sudo python setup.py instlall"

2) Install the files. Copy to a folder inside "/linuxcnc". I used "/linuxcnc/scripts".
https://github.com/sam0737/hrepstrap

3) Make sure all the scripts are executable:
chmod a+x *.pl *.py *.sh

4) Edit your machine's ini file (usually in "/linuxcnc/configs/your-machines-name/your-machines-name.ini"). Add a new line at the bottom of [DISPLAY]:
"PYVCP = /home/username/linuxcnc/scripts/repstrap-extruder.pyvcp"

and under [FILTER]:
"PROGRAM_EXTENSION = .skf Skeinforge Output
skf = /home/username/linuxcnc/scripts/skeinforge2emc.pl"

under [HAL] make sure there is a:
"POSTGUI_HALFILE = custom_postgui.hal"

5) The easiest way to add halui is to add the following to the [HAL] section of the ini file.
HALUI = halui
6) Open "repstrap-extruder.hal" inside "linuxcnc/scripts" folder. Change the 3rd line to point to the correct directory. Mine was:
"loadusr -Wn rs-extruder /home/username/linuxcnc/scripts/repstrap-extruder.py"

and comment out the following lines by adding a "#" at the beginning. It should look like this:

#net motor1.spindle <= motion.spindle-speed-out => rs-extruder.motor1.spindle
#net motor1.spindle.on <= motion.spindle-on => rs-extruder.motor1.spindle.on

I'm not 100% sure why this is a problem, but I had to comment the lines to get my setup to load without error.

7) Execute "softlink-mcode-inject.sh" to have the softlinks needed created.

When you're all done you should be able to load Linux CNC like so:


Let me know if you have issues and we'll try and sort them out together. I know I had tons of issues the first AND second time I did this, so that's what I wrote a post on it.

Jorge Pinto (casainho) from Portugal also did some work on this, but it was lost when google code was shut down. Original thread here:
http://www.cnczone.com/forums/linuxcnc-formerly-emc2-/95045-cnc-software.html

A separate tutorial just on connecting an Arduino to Linux CNC by some Russian professor:
http://rkmiit.ru/main/all/students/educational/tutorials/arduinolinuxcnc_en.html

Sunday, August 7, 2016

Posting to Thingspeak over GPRS with SIM900 & Seeeduino Stalker & GPRSBee

My family has a cabin in the remote upper peninsula of Michigan. There we have a solar array that keeps the various vehicles batteries charged over the winter. I wanted to track the battery status through the winter when no one is up there. However, there is no internet up that far, but there is cell phone reception. So the plan is to have a Seeeduino Stalker run up 24/7/365 off of a lipo battery. Every hour or so it will power up and push the state of charge of the battery bank and voltage of the solar panels to Thingspeak.

A few people have worked on this, but even less have published in detail how to do it for the rest of us. So I've been working on it for the last month or so. I now have the GPRS able to connect to thingspeak and push data manually. All I have to do it clean up the code and make it into a more power friendly version that will work year round.

Hardware:

SeeedStalker 3.0
GPRS Bee Rev. 4 (SIM900)
LiPo Battery

Steps:
  1. Wake Seeedstalker from sleep
  2. Power up GPRSBee
  3. Pull data from sensors
  4. Connect to wireless network
  5. Connect to thingspeak
  6. Push data to thingspeak
Hardware Modifications:

It is necessary to solder P3 and P4 for for the RTC interrupts to function correctly. See the Seeeduino Stalker wiki for more details on this.
You will also need to solder a wire from pin 9 on the Bee socket to D5. See why here:
http://old.gprsbee.com/ 
Finally, for debugging, I find it's essential to have serial communication with my computer, so I've had to switch to using SW serial on D6 & D7. This means dealing with the Seeeduino Stalker v3.0's hardware bug. I found Seeed's wiki does not completely address the hardware bug. I had to cut a trace on P6 in addition to the one for P7. If you're having a hard time, just use a multi-meter to ensure you are wired how you expect to be.


Code:

1) Wake Seeedstalker from sleep -

This code has been written mostly by SeeedStudio on their wiki:
http://www.seeedstudio.com/wiki/Seeeduino-Stalker_v3#Data_Logger_Example
I'm not going to cover it again.

2) Power up GPRSBee - I will be adding this gradually in the coming weeks.
void gprspwr_on()
{
  Serial.println("Turning on GPRS");
  pinMode(5, OUTPUT);
  digitalWrite(5,LOW);
  delay(1000);
  digitalWrite(5,HIGH);
  delay(2000);
  digitalWrite(5,LOW);
  readATcommand("Call Ready",6,10000);
  if (answer == 1){
    Serial.println("GPRSbee is on!");
  }
}

void gprspwr_off()
{
  Serial.println("Turning off GPRS");
  pinMode(5, OUTPUT);
  digitalWrite(5,LOW);
  delay(1000);
  digitalWrite(5,HIGH);
  delay(2000);
  digitalWrite(5,LOW);
  answer = readATcommand("NORMAL POWER DOWN",2,2000);
  if (answer == 1){
    Serial.println("Sucessful Powerdown Complete");
  }
}

boolean gprspwr_status()
{
  Serial.println("GPRS Power Status");
  answer = sendATcommand("AT", "OK", 2, 2000);
  if (answer == 0){
    Serial.println("GPRSbee is Powered off!");
  }  
  else if (answer == 1){
    Serial.println("GPRSbee is on!");
  }
  return answer;
}

int8_t readATcommand(char* expected_answer1, unsigned int expected_answers, unsigned int timeout)
{

  uint8_t x=0,  answer=0;
  boolean complete = 0;
  char a;
  char response[100];
  unsigned long previous;
  String  incomingdata;
  boolean first;

  previous = millis();

  for(int i = 0; i < expected_answers; i++){
    x = 0;
    complete = 0;
    a = 0;
    first = 0;
    memset(response, '\0', 100);    // Initialize the string
    do{
      if(SIM900.available() != 0){
        a = SIM900.read();
        //Serial.println(a,DEC);
        if (a == 13){
          a = SIM900.read();
          //Serial.println(a,DEC);
          if (a == 10){
            if (first == 0){
              //keep going, just ignore it
            }
            else{
              Serial.print("string: #");
              Serial.print(response);
              Serial.println("#");
              complete = 1;
            }
          }
        }
        else if(a == 0){
          Serial.println("Found a blank");
        }
        else  {
          response[x] = a;
          x++;
          first = 1;
          //Serial.println(response);
        }
        if(strstr(response, expected_answer1) != NULL)
        {
          answer = 1;
          complete = 1;
          Serial.print("string: #");
          Serial.print(response);
          Serial.println("#");
          return answer;
        }
        else if(strstr(response, "ERROR") != NULL)
        {
          answer = 2;
        }
      }
    }
    while((complete == 0) && ((millis() - previous) < timeout));
    //Serial.println(i);
 
  }

  return answer;
}

3) Pull data from sensors - This is dependent on your application, so I'm not going to cover it.

4) Connect to wireless network & thingspeak - I will be adding this gradually in the coming weeks.

void loop() {
  if (SIM900.available())
  {
    Serial.write(SIM900.read());
  }
  //power up gprs
  gprspwr_on();

  //connect gprs to internet
  answer = sendATcommand("AT+CGATT?","OK",5,2000);
  answer = sendATcommand("AT+CSTT=\"CMNET\"","OK",3,2000);
  answer = sendATcommand("AT+CIICR","OK",3,2000);
  answer = sendATcommand("AT+CIFSR","OK",3,2000);
  answer = sendATcommand("AT+CIPSPRT=0","OK",3,2000);

  //connect gprs to thingspeak
  answer = sendATcommand("AT+CIPSTART=\"tcp\",\"api.thingspeak.com\",\"80\"","CONNECT OK",5,2000);

  //post data to thingspeak
  answer = senddata(battery_percent());

  delay(5000);

  //power down gprs
  gprspwr_off();

  //put arduino to sleep?
  for (int i=0; i<60; i++){
    delay(1000);
    Serial.println(i);
  }
}

int8_t sendATcommand(char* ATcommand, char* expected_answer1, unsigned int expected_answers, unsigned int timeout)
{

  uint8_t x=0,  answer=0;
  boolean complete = 0, first = 0;
  char a;
  char response[100];
  unsigned long previous;
  String  incomingdata;


  delay(100);
  //Serial.println("Send AT Command");
  while( SIM900.available() > 0) SIM900.read();    // Clean the input buffer
  SIM900.println(ATcommand);    // Send the AT command
  Serial.println(ATcommand);
  //Serial.println("AT Command Sent!");

  previous = millis();

  for(int i = 0; i < expected_answers; i++){
    x = 0;
    complete = 0;
    a = 0;
    first = 0;
    memset(response, '\0', 100);    // Initialize the string
    do{
      if(SIM900.available() != 0){
        a = SIM900.read();
        //Serial.println(a);
        //Serial.println(a,DEC);
        if (a == 13){
          a = SIM900.read();
          //Serial.println(a,DEC);
          if (a == 10){
            if (first == 0){
              //keep going, just ignore it
            }
            else{
              Serial.print("string: #");
              Serial.print(response);
              Serial.println("#");
              complete = 1;
            }
          }
        }
        else if(a == 0){
          Serial.println("Found a blank");
        }
        else  {
          response[x] = a;
          x++;
          first = 1;
          //Serial.println(response);
        }
        if (strstr(response, expected_answer1) != NULL)  
        {
          answer = 1;
          complete = 1;
          Serial.print("string: #");
          Serial.print(response);
          Serial.println("#");
        }
        else if(strstr(response, "ERROR") != NULL)
        {
          answer = 2;
          complete = 1;
        }
      }
    }
    while((complete == 0) && ((millis() - previous) < timeout));
 
  }
  return answer;
}

5) Push data to thingspeak - I will be adding this gradually in the coming weeks.

int8_t senddata(float data){

  Serial.print("Battery Percent = ");
  Serial.println(data);

  //while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  SIM900.println("AT+CIPSEND");
  //Serial.println("AT+CIPSEND");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("POST /update HTTP/1.1");    // Send the AT command
  //Serial.println("POST /update HTTP/1.1");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Host: api.thingspeak.com");    // Send the AT command
  //Serial.println("Host: api.thingspeak.com");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Connection: close");    // Send the AT command
  //Serial.println("Connection: close");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("X-THINGSPEAKAPIKEY: J79IQXQ0EOM6NCZX");    // Send the AT command
  //Serial.println("X-THINGSPEAKAPIKEY: J79IQXQ0EOM6NCZX");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Content-Type: application/x-www-form-urlencoded");    // Send the AT command
  //Serial.println("Content-Type: application/x-www-form-urlencoded");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Content-Length:12");    // Send the AT command
  //Serial.println("Content-Length:12");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("");    // Send the AT command
  //Serial.println("");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.print("field1=");    // Send the AT command
  SIM900.println(data);
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println((char)26);
  delay(500);
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);

  answer = 0;
  return answer;
}


Complete Code:

GPRS ThingSpeak v0.1 Beta

Useful Links:

Seeeduino Stalker v3 Wiki:
http://www.seeedstudio.com/wiki/Seeeduino-Stalker_v3

Original GPRSBee Site:
 http://old.gprsbee.com/

GSM Particulate Sensor - Thanks alcomposer!!! This code helped me a lot and some of my code is base on this.
https://github.com/alcomposer/GSM-Particulate-Meter/blob/master/ParticulateSensorSIM900.ino

SIM900 Thingspeak Code - Thanks maliki!!! This code was also key in helping me get all of this together.
https://codebender.cc/sketch:267851#sim900%20thingspeak.ino

Misc Others:
http://community.thingspeak.com/forum/thingspeak-api/http-post-using-gsm-module/
https://www.pubnub.com/blog/2015-02-17-connect-arduino-gsm-gprs-shield-to-the-internet/
https://community.particle.io/t/uploading-sensor-data-to-thingspeak/5497
http://www.seeedstudio.com/wiki/Seeeduino_GPRS

Sunday, April 3, 2016

New 3020 CNC Controller Box


  I'm not happy with my current controller setup. It just looks terrible, consists of two separate boxes, with a hanging out a-axis stepper driver. My plans are to design and entirely new controller box with all new hardware (almost). The plan is to make it an affordable upgrade since I'm on a tight budget these days. That means no Gecko drives '-( In addition to the 4 axes, there will be a spindle controller and an Arduino for controlling the heaters on the 3D printer. The intention is to have a dual purpose box for both CNC routing and 3D printing.

Component List:
1x 200 x 400 x 40mm Enclosure
4x RATTM RTM5742A Stepper Drivers - Details
1x Generic 480Watt 24V 20A Power Supply
5x 5-Pin Twist-Lock Connectors
4x 12mm Assorted Connectors
1x SCR Motor Driver - Reused from original controller box
1x 5-Axis Isolated Breakout Board
1x 5V Isolated Regulator - To Power the Breakout Board






Later I will be adding an Arduino board to control the heaters as well as machining new front and rear panels to the box.

Stepper Motor Drivers - Rattm RTM5742A Review

I'm currently in the planning/ordering stage of  my build of a new controller box for the 3020 CNC router/printer. I've been looking around for motor drivers and there are a lot of cheap options and some expensive options. There are not many good options in the $20-$40 range. Gecko drives are of course always ideal, but $100 per axis is out of my budget. I have been hunting on eBay for a while and have previously posted on the notorious HY-DIV268N-5A. In my eBay searches  I also saw a few drives that looked similar the the HY-DIV268N-5A, but had are rumored to have performed much better. I wanted to try them out!


They appear to all be based on Leadshine and rebranded into at least two other names, Rattam and Wantai.


Rattam Motor RTM5740A
Price: $25

I have purchased 4x RTM5742A drives and plan to do some analysis of the hardware. I hope to get a good idea of the quality and share this with you.

Based on the ON Semiconductor LV8727. I have sadly found that there are several other boards based on the same IC for much cheaper, some as low as $10 each. Just search for "DD8727v1" on google or eBay.

To be continued....

Saturday, November 14, 2015

Extruded Controller Shield PCB Design

This weekend I ordered my first set of professionally manufactures circuit boards from Osh Park. I designed the board in Fritzing, so I will upload the layout shortly. It's based on the old RepRap extruded controller, but instead of using an integrated ATmega328, it will use an Arduino Uno R3. The board supports 2 thermocouples, 2 thermistors, and 3 PW.M outputs for controlling heaters.

Here are a couple previews of the board. It is expected to be complete by the end of the month. I should be able to start assembly in early December.



Here's the current Fritzing file for the board:
 Arduino Extruder Controller v1.2