8888ye

8888ye

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

Monday, September 7, 2015

3020 CNC 3D Printer Conversion Part 3: First Prints

 This weekend I finally got my 3020 CNC Router converted to a 3D printer setup. It was actually much easier than I expected! As I previously stated in my post on the MIB heater controller, I am using a conversion kit purchased from MIB instruments.


The kit did not include a mount for the spool of filament, so I grabbed some spare 8020 aluminum extrusion and fabbed one up. Also, the mount they provided to attach the extruder to the Z-axis carriage was not a direct fit because it was designed for a MIB 3020 machine, not the generic one I have. I don't like the way it mounts, especially that holds the extruder with only one bolt. This will have to be improved later. I also need to run the wires for the heater and thermocouple through the cable track. One important addition was a connector on the cable that was previously used to run the spindle. With this connector I can easily swap out the extruder head for the spindle again without running a separate cable. Then I just switch with port I'm attached to on the controller box (A-axis or Spindle).



The heated glass bed they sell is a standard 200mm x 200mm size. Again, the holes did not match up to my generic 3020 bed, so I had to re-drill them.


First and second print results of a 35 tooth gear wheel for a Harbor Freight 7x10 lathe. The original gear from HF is on the left in the first picture. The second picture shows the tops and the third picture shows the bottoms. The difference between the two prints was adjustments in the feed rate of filament and the temperature of the extruder nozzle.


I guess I need a post on my software setup as there is a lot missing as far as explanation for that aspect of this project. I am using LinuxCNC and Slic3r currently.

3020 CNC 3D Printer Conversion Part 2: A-axis Stepper Driver

The next two images you can see the HY stepper controller that I use for the new A-axis that my feeds the filament. This was shoe-horned into my existing controller once I did a little reverse engineering in one of my previous posts. See YooCNC reverse engineering and HY-DIV268N-5A driver. Long story short, there are some extra pins that drive the added motor controller. I will have to design a new enclosure now!
 

I will add some pictures of which pins I am connected to on the YooCNC driver board the next time I have it apart.