Itchy: End Stops

An end stop has two states. So, if A is triggered to make Dir explicitly head away from the stop, then /A will also have a change in state, which can be used to feed in info telling the machine there has been a hard stop. This can be used both for zeroing, and for a full ‘WTF all brakes on how did you get out of bounds’ that happens in software – but that is a slave to the directional change we apply directly to the DIR pin. It might be a toggle gate/flip-flop.

The electronics of this may need testing, but it should be possible to hit a high pin to ground and not have the direction go high. That is, to have the grounding effect be bigger than the directional instruction, If not, the software still works. Pull-up/pull-down resistors may be involved at the pin end. Need to dig out whether you can have a resistor as an out pin. Don’t think so. But as an in pin would be fine. Still, it takes an extra pin in.

Itchy: microcontroller

So, I have an arduino breadboarded to a stepper driver right now, and I’m staring at it, and thinking about how to control several of them. If I want tiny steps, I need to be able to switch different pins on and off, and I’m going to want tiny steps. That uses up a lot of pins.

I have two possible options. The hardware one is to have all of the driver speed pins run from one analogue pin, which I then run through a couple of comparators to get the level I want. That’ll give me output from one pin, but I do have to write out some logic tables and make the board more complicated.

The software method is to have three arduinos, slaved to a master computer (probably a Raspberry Pi by serial interface to the Pi GPio) and send the full movement to each, but screen it so that each Arduino only moves for its own movements, and hence can’t get out of step. (It could miss steps and not recover them, but that’s an issue to deal with in software, and I have ideas anyhow.)

The slot-in solution is probably a Reprap RAMPS controller, so I should look into that, but it’s extra money and a Pro Mini costs under a fiver, plus I have a couple hanging around.

I could /just/ manage a two-axis machine where I operate the z axis by hand and call the machine a plotter. That’s not likely to satisfy me, though. So, it’s time to talk with the programmer I’ve roped in – she’s going to know more than me about timings, multiple threads, and the like. She thinks I know what I’m doing. Don’t tell her!

Project: Itchy

I have just been given a lot of aluminium profile. I want to make a cnc router to allow me to engrave acrylic sheets and cut lino. The lino cutting will be the easiest problem, as it just needs a 2d movement and some human setting of the x axis. Plus a lot of glue.

So, the first thing I need to know is how the heck to build it. I don’t want to move a plate under a fixed head, if I can help it, as that makes the entire base way too big, and I don’t want to take up too much space. If I wanted to engrave an area a x b I’d need twice the run, 2a x 2b, to go from left to right. Given I might create big stuff, it’s too large for storage, and too clumsy, and I don’t want to move the platen. I think it’s called a platten. I don’t know how to spell that, so I’ve tried both ways.

So, I’m going to have to move the head, which means linear bearings and stepper motors. And stepper drivers. There should be plenty of explanations out on the internet, and I just need to find an explanation that isn’t geared to solutions I’m not using.

On the internet.

Fuck.

Pi-Puter Notes

Useful and not so useful notes on this project.

I’m breaking it down into pre-computer tasks, rather than trying it all at once. So, organising the power supply for the pi, organising the power supply for the peripherals, and so on. I’ll need to do sound and video, wireless, and a few other things.

Sparky v2 – latest code

The code for Sparky Version 2 is just about finished. I need to swap something I did back-to-front with something Mat did far more elegantly and in fewer lines, but the logic’s sound. Here, with a bit of editing, is Oxygen v7. V1-5 were debugging programs of various sorts.

/* Version 7 of Oxygen is the software implementation.
 * 
 * We do not use pins 0 & 1 (RX/TX) for the main board.
 * We scan LVL after smoothing, compare to the set voltages of 'max_trigger', and 'min_trigger' trigger DIR to 1 or 0 if we want to move.
 * We then hit STEP.
 * Pins should be set to cross directly to DIR and STEP, on veroboard.
 * For convenience, we begin crossing at pin 3, with pin 2 being the zoom toggle
 * 
 * For debugging, we output LVL, MAX, MIN, DIR to serial, and comment that out.
 * 
 * Arduino takes in LVL and four cut-out or direction override pins, plus one 'zoom' pin to speed up or slow down stepping in software, and outputs 7 pins - M0, 1, 2, Step, Dir, /Sleep, /Reset

 */

// hardware constants for board input/output

const int ledPin = 13;
const int zoomPin = 2;  // earth to 0v on Arduino board to increase speed (decrease software delay)

// digital (output) pins (Arduino Pro Mini matched to DRV8825 Stepper Driver)
const int dirPin = 3;
const int stepPin = 4;
const int sleepPin = 5;
const int resetPin = 6;

// step size pin array
int mPins[3] = {7, 8, 9};
const int mPinCount = sizeof(mPins)/sizeof(int);
int mPinStates[mPinCount] = {};
// char *mPinNames[mPinCount] = {"M0", "M1", "M2"};  // Probably only ever in debugging/humanised printing

// Input for cut-outs and manual drive
const int upperCutoutPin = 10;
const int lowerCutoutPin = 11;
const int driveUpPin = 15;  // A1 Can be used as digital pin.
const int driveDownPin = 16;// A2 can be used as digital pin.

// analogue (measurement) pins
const int levelPin = A0;

// measurement constants
/* lvl = 0...1023 (corresponding to 0 to 5v ish) */

const int AnalogReadsPerVolt = 200;  //1000 ish corresponds to 5v

#define volts  // defines volts as a word to ignore by defining it as blank

const int max_trigger = 1 volts * AnalogReadsPerVolt;
const int min_trigger = .1 volts * AnalogReadsPerVolt;

// measurement variables

int lvl = 0;

// move-related variables and calculations

int move_rate = 100;  // Used for speeding up/slowing down in software
int step_ratio = 1;   // Valid options, 1, 2, 4, 8, 16, 32
int step_index = 0;   // used to keep track of which result we want
int stepsize_results[] = {32, 16, 8, 4, 2, 1};
const int stepsize_count = sizeof(stepsize_results) / sizeof(int);
int modePinSettings[stepsize_count] = {5, 4, 3, 2, 1, 0}; // read from High/Low table in docs, M2 first

/* Finds index within modePinSettings, to give us a later result */
int find_index(int array[], int count, int value)
{
  int i;
  for(i=0; i>= 1;
  }
  
  
  digitalWrite(sleepPin, HIGH); // /SLEEP - high to suppress behaviour
  
  // Reset Stepper Board 
  digitalWrite(resetPin, LOW);
  delay(5);
  digitalWrite(resetPin, HIGH); // /RESET
  digitalWrite(ledPin, HIGH);

  //Serial.print("Initialised with min ");
  //Serial.println(min_trigger);
  
}

void loop()  {
  
  
  if(digitalRead(zoomPin) == LOW){  // move rate will appear twice in each loop that moves, once in each loop that does not move
    move_rate = 50;
  } else {
    move_rate = 500;}
  //Serial.print("zoomPin: ");
  //Serial.print(digitalRead(zoomPin));
  //Serial.print("move_rate: ");
  //Serial.println(move_rate);
  
  
  if(digitalRead(driveUpPin) == LOW) {
    //Serial.println("Drive pin: Up.");
    stepUp(move_rate);
  } else if(digitalRead(driveDownPin) == LOW) {
    //Serial.println("Drive pin: Down.");
    stepDown(move_rate); // Behaviour under thick fingers: shout at clumsy person
  } else {  

    lvl = analogRead(levelPin);
    
    if(lvl < min_trigger) {
      //Serial.println("Calling stepUp()");
      stepUp(move_rate);
      // //Serial.println("Moving Up.");  // debugging line
    }
    else if(lvl > max_trigger) {
      //Serial.println("Calling stepDown()");
      stepDown(move_rate);
      // //Serial.println("Moving Down.");  // debugging line
    } else {//Serial.println("Fallthrough.");
    } // lvl not triggering either threshold.  Try earthing it to be sure it goes up.
  }
}

Sparky v2 – analogue and digital

Veroboard with wires, an arduino, and some smoothing capacitorsI’ve soldered up most of the board for Sparky v2, meaning I now know which pins connect where. The Arduino has analogue pins that can also be used for digital input, so although I’m technically out of digital pins, that’s not really a problem. I’ll be testing that theory soon, using a digital read instead of an analogue read, and I’m pretty sure it’ll end up fine. I’ve written the code, soldered most things, but need some small push buttons to test the code entirely, and I don’t want to put on the stepper driver chip before it’s entirely tested.

Learn C the Hard Way – inStructions

Mmmm, pun headlines. Not sorry.

So, looking at structs. The write-up for Ex 16 starts with ‘OK, do the write-up’. So, what does the #includes stuff get?

#include <stdio.h> I know about. It lets you put things in and out, so printf lives there.
#include <assert.h> apparently crashes my browser when I search for it. Which is apposite.

Apparently ‘assert’ makes the case that something exists, and then if it doesn’t, throws up a warning to stderr. I guess stderr is also controlled by stdio, as it’s a line to print to. 2/dev/null is my favourite way of stopping the screaming. So in this case it’s checking that who is not NULL. We’re not just picking up a non-entity and trying to work with it, and if who != NULL then I guess that’s the check we’ve just succeeded at what we’ve done.

#include <stdlib.h> gives us malloc() – memory allocation. We’re grabbing a chunk of memory to use for each copy of the struct. So, for obvious reasons, it also gives us free(). Once we’ve allocated, we need to be able to free that up, or our little ghost people will wander in electronic halls forever and there will be a bad Tron sequel.

#include <string.h> must let us play with strings. We have strdup() to handle our name. It also gives us NULL, which is cool, as stlib.h also seems to give that to us. It’s probably very popular at parties.

struct Person defines what a struct called person is. It’s got some attributes inside. So, when we get to struct Person *Person_create we’ve got something to look to and check. It’s sort of like defining an int and then putting a number into it. We define a Thing and then we put how to create the thing as a subsidiary part of that.

struct Person *pointer-to-whatever-our-name-is instantiates a struct and the bits underneath fill it. Note it’s in the middle of our Person_create function. So we grab the attention of the computer, shout at it until it creates a struct with a pointer of the name ‘who’ like Joe or Mat or Cthulhu, and then we go forward from there and allocate memory from that point. For extra points, we choose a bit of memory that isn’t going to write over anything else because you put Cthulhu in the wrong place. (Cthulhu in the wrong place will /severely/ mess up your day.)

The =malloc(sizeof()) part makes sure we’ve allocated memory to the maximum size a Person can be. That’s pretty large in the case of some sedentary sorts.

I think assert(who !=NULL) checks that that happened right, but it might also be that ‘who’ is not a name of 0 characters. Those might look the same in the wrong light. It’s checking who, rather than checking the pointer named who. Someone call for the fucking Tardis.

who->name=stdrup(name) is the stand-out here, so let’s do the next line first.
who->age=age is pretty obvious. Within the struct sub-language, you’ve got -> which says ‘put this into the struct’. So assign ‘name’ from the input of the function into the bit of ‘who’ that is labelled ‘age’.

The same applies with who->name=stdrup(name) except we handle it a bit differently because it’s a string, not an integer. It’s string duplicate. It copies the string we want, the name, into the space we have reserved for the name. I don’t know why that’s explicitly different from int – maybe it’s for security, maybe it’s because it’s easiest to copy a string that way, I just dunno. But that’s what it does.

The return returns the whole object. Later, we’ll see that we run this function with a = in front of it. We’re making ‘who’ and then assigning it to a named pointer we create at the same time.

Person_destroy is my favourite… no, let me alter that. /Running/ Person_destroy is my favourite part of the program. I could sit there running it all day. Only I can’t, because the person has to exist to be destroyed. Again, if there’s a NULL entry, we can’t destroy it, and we output that. I can see a bit more sense in this than in checking the creation. You don’t want to typo the name of a poor unfortunate to be blatted to oblivion, and let them live, after all. But I’m also pretty sure both will be good practice, and if I’m going to have my fun at the end of a function’s life, I can build in sense at the start of it.

We free up the name separately from the rest. I guess because the name is a string, and has to be treated differently, so you only free up to the null byte at the end. Maybe you can group different strings to destr… uh, ‘free’ in the same way as we group everything else on the next line, but we’re doing the strings and then everything else as a one-er.

(Person_destroy($^). Mmmm. It’d be so peaceful.)

Person_print doesn’t check on the existence of the person in question, but I have people for that. It prints out everything we explicitly list, according to the -> syntax. This is likely a bit easier to remember than ***pointer-to_otherPointer(pointer002).

Then we hit main(). It’ll return an int. That int will be 0, because nothing will go wrong. Nothing, you hear me?

Now, we have that equals sign I was talking about up the page. We make a person we label ‘joe’ for the computer. We give him a memory address and fill in all the details, and then we link those details to pointer ‘joe’. He’s 32. His life will be short, although it will have some miraculous aging.

Ditto Frank. Name ‘Frank Blank’, pointer-name, ‘frank’.

%p is the only new-ish part of printf. It gives us the address at which the pointer-thing resides. *joe points to %p where %p is labelled ‘joe’. To find ‘joe’ we look up *joe and that gives us the address %p. Then we run the function that prints out their details, Person_print.

We do the same for Frank. Frank moved away from the neighbourhood and changed his name, but he’s still in his brother Joe’s shadow.

Person_destroy(joe); BAHWHAAWHAHAHAHA…

Ahem, yeah, we just call that function we discussed earlier. Joe’s brief, warm moment of existence is over, and we get back the memory. If we’ve had a /really/ bad moment and killed the wrong person and we know the memory address we might be able to copy him or install a new Joe very percisely over him, but frankly that’s advanced ninja work, and I’ll be having none of it.

Our crime is complete. Nobody can prove Frank or Joe ever existed. We return ‘0’ to say that all is well, and end the main function.

I should go back and write this up as comments in the code, but I had too much fun blorting it into a longer form. Don’wanna!

Probably will, though.

ETA: Did.

Extra credit – can’t work out how to remove memory allocation from stack. I’m not using malloc() so I can’t use free(). Everything else works.

Learn C the Hard Way – reference book

Now that I’ve got a project where I’m using C in the wild, I’m concentrating more on that than on learning. It’s definitely rubbing in the stuff I need to know, but I’m also aware I’m using some very basic tools and there might be better stuff out there. I’m about to approach structs in the book, but so far they haven’t reared their ugly head in anything I need to do. I think.

This is a thing I found with LPythonTHW as well. I took what I needed, and moved on a lot more slowly from that point, but I also went back pretty much constantly to the earlier lessons, to use them for syntax. Every time I’m unsure how to type something, I know that there will be an example somewhere in LCTHW that shows me the thing I’m after. That’s good.

I’ll likely drift away from that model too, unless it turns out it covers things I’m picking up here and there. Stuff like bitshifts are really useful when I’m setting an array of pins and need to go through a binary number in order. I’m sure that’ll come up as an operator, but it hasn’t yet. Having learned how to do it, if I get things wrong there’s still the internet, but for now there’s mostly Zed’s book.