writing an expression for box spiral robot

I want a simple stepper driven robot device to push buttons (cross configuration) on a hand controller, controlling two perpendicular axis. Thinking 2D, turning right and moving forward only.

An arm attached to the stepper shaft sweeps over the pushbuttons activating them. To move forward two steps the arm sweeps left then right and vice versa. To turn right, the arm sweeps over two adjacent buttons, going clockwise.

The sequence to do this is as follows - where -1 == left sweep and 1 == right sweep. 2 == right and right again. The arm travels 90deg with each sweep.

Each sequence is repeated before being incremented and actioned twice - and so on in the following pattern - a box spiral.

2, -1, 2, -1, 2, -1, 1, -1, 2, -1, 1, -1, 2, -1, 1, -1, 1, -1, 2, -1,1,-1,1,-1, 2,...

I am baffled as to how to express this to run as a for or while statement or other expression.

Why am I doing this? Besides moving an imaging sensor between shots to increase signal to noise ratio in the finished image, the instrument is practically a collectors item. It has a +ve earth! And I don't want to affect it cosmetically.

A bit left field, but thanks for looking.

Rowland.

Could you give a bit more detail about how this works and how that sequence you've provided breaks out into repeated subsequences. I'm struggling to see what it does.

edit: a picture might help

This will repeat the sequence you showed:

void doSomethingWithIt(int m)
{
  Serial.println(m);
}
void sequence(void)
{
  int seq2=1;
  while (1)
  {
    for (int i=0;i<2;++i)
    {
      doSomethingWithIt(2);
      for (int k=0;k<seq2;++k)
        doSomethingWithIt( ( k&1 ? 1 : -1 ) );
    }
    seq2+=2;
  }
}

Just replace doSomethingWithIt() internals with your control code.

Of course, maybe you want to call a function and get a single value back - here's that:

int sequence2(int reset)
{
  static seq2=-1, i=99, k=99;
  if (reset)
  {
    i = k = 99;
    return 0; // dummy value - ignore
  }
  if (k>=seq2)
  {
    ++i;
    k=-1;
  }
  if (i>=2)
  {
    i=0;
    k=-1;
    seq2+=2;
  }
  if (k++<0)
  {
    return 2;
  }
  return ( k&1 ? -1 : 1 );
}

Every time you call sequence2(0); it will return the next number in your sequence - if you want to restart back at the beginning again, then call it with sequence2(1) once, then continue with sequence2(0) from then on for the sequence

Thanks, once again, David. I will look at fitting these options into the existing sketch this week.

Rowland

geoland:
I presume this is what you intended - I couldn't get it to compile otherwise.
...
If I understand the intent of your code. It is the stepping sequence that is controlled in this case with a constant motor speed.

Yes, the functions will need to be put in front so later functions can 'see' them.

The two functions simply take the sequence you listed and calculate them. The first one is an infinite loop, so you may want to consider using the second so you have more control over the sequence. Also, you can see in the code where you pass the 2, 1, and -1 - if you need to change their values, just change those.

Thanks David.

I get the error;

ISO C++ forbids declaration of 'seq2' with no type -

this is repeated for the values i and k in the same line.

This is how I've implemented your second code, between setup and loop.

void setup() {
  pinMode(shutterPin, OUTPUT);
  pinMode(mirrorPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
}
// dither routine
 int sequence2(int reset) 
{
  static seq2=-1, i=99, k=99;
  if (reset)
  {
    i = k = 99;
    return 0; // dummy value - ignore
  }
  if (k>=seq2)
  {
    ++i;
    k=-1;
  }
  if (i>=2)
  {
    i=0;
    k=-1;
    seq2+=2;
  }
  if (k++<0)
  {
    return 2;
  }
  return ( k&1 ? -1 : 1 );
} 
void loop() {

geoland:
I get the error;
ISO C++ forbids declaration of 'seq2' with no type -
this is repeated for the values i and k in the same line.

Sorry - change

static seq2=-1, i=99, k=99;

to

static int seq2=-1, i=99, k=99;

The compiler I used to test on allows implied int there, but the (better) Arduino compiler rightly complains about it.

I have set up the spiral pattern as below - frame count calling steps0, steps1... etc by if() statements. The stepper rotates and pushes a button as it goes, stops and pushes the next button, either forward or reverse to trace out the box spiral. A bit clunky, but eminently easier for a newbie. I've implemented a wake up delay and hardware switch inputs for pause and stop along with an automatic stop after the desired number of frames is complete.

It was easier to do it this way and have control over image number instead of using a session time that had to be calculated based on image count anyway. The user can input the desired number of images and exposure time and wake up and the session time is calculated automatically and accurately.

The only issue is that 100 frames is 300 lines of code? Only 40 at the moment. This is pretty much finished for now and ready to go into production.

#include <Stepper.h>

/* Ditherbot/Sparehand.

Rowland Cheshire 2011
 
 This sketch automates multiple long exposure with a Canon DSLR 
 Camera and includes a stepper driven dithering mechanism 
 to press 4 pushbutton switches on a hand controller.
 
 Dithering, is moving the camera sensor between shots 
 so that subsequent images does not fall on the same pixels,
 which improves final image quality. The camera will be mounted 
 on an equatorial mount with the Ditherbot/Sparehand 
 repositioning in RA and DEC between exposures.
 
 The image sequencing and dithering is independent of equatorial 
 mount electronics which is '+ve' 
 earth.
 
 Written for a bipolar/unipolar stepper motor - some 
 rewriting will be needed for 3 wire variable reluctance 
 motors - CDROM drives */

// Variables - set next 3 lines as required

// set number of images
#define images 40

// set exposure time
unsigned long exposure_tm = 420000; //default

// set wake up time
unsigned long wake_tm = 300000; //default

/* generally fixed variables - set and forget */

# define pre_shutter 100

#define mirror_delay 2900

#define predither_tm 2000

#define interval_tm 2000

#define motor_delay 3000

#define motorSteps 200 

#define motorspeed 5

// comment out boolean statement and substitute with milliseconds if desired
unsigned long session_tm = ((exposure_tm + mirror_delay + predither_tm + motor_delay + interval_tm + pre_shutter)*images) + wake_tm;

/* fixed - no changes */

#define image_session images

#define pin2 2

#define pin3 3

#define shutter_pin 8

#define focus_pin 11 // to be implemented - manual focus

#define led_pin 13

int pinval2;

int pinval3;

int frames = 0;

int steps;

long time = millis();

/* stepper motor - dither sequence */

#define motorPin1 4
#define motorPin2 5
#define motorPin3 6
#define motorPin4 7

Stepper stepper(motorSteps, motorPin1,motorPin2,motorPin3,motorPin4);

/* dither pattern - call these lines sequentially */
#define steps0 50
#define steps1 50
#define steps2 -50
#define steps3 50
#define steps4 50
#define steps5 -50
#define steps6 50
#define steps7 50
#define steps8 -50
#define steps9 50
#define steps10 -50
#define steps11 50
#define steps12 50
#define steps13 -50
#define steps14 50
#define steps15 -50
#define steps16 50
#define steps17 50
#define steps18 -50
#define steps19 50
#define steps20 -50
#define steps21 50
#define steps22 -50
#define steps23 50
#define steps24 50
#define steps25 -50
#define steps26 50
#define steps27 -50
#define steps28 50
#define steps29 -50
#define steps30 50
#define steps31 50
#define steps32 -50
#define steps33 50
#define steps34 -50
#define steps35 50
#define steps36 -50
#define steps37 50
#define steps38 -50
#define steps39 50

/* focus is manual for this application
 will implement with hardware switch on/off */

// void sequences start here

/* this is the automated image capture dithering cycle. Session 
 end is automatic for session time and 40 frames or pause and user
 end session */

// exposure
void cycle() {

  // mirror lock up
  digitalWrite(shutter_pin, HIGH);
  delay(pre_shutter);

  // reset camera_pin LOW, ready to fire shutter
  digitalWrite(shutter_pin, LOW);

  // hold open for 3 seconds
  delay(mirror_delay);

  // add focus here pin 11
  // press 2 - fire shutter
  digitalWrite(shutter_pin, HIGH);
  delay(exposure_tm);

  // close shutter
  digitalWrite(shutter_pin, LOW);
  delay(predither_tm);

  // dithering
  digitalWrite(led_pin, HIGH); 
  frames++;
  Serial.println(frames);
  if (frames == 1)
    steps = steps0;
  if (frames == 2)
    steps = steps1;
  if (frames == 3)
    steps = steps2;
  if (frames == 4)
    steps = steps3;
  if (frames == 5)
    steps = steps4;
  if (frames == 6)
    steps = steps5;
  if (frames == 7)
    steps = steps6;
  if (frames == 8)
    steps = steps7;
  if (frames == 9)
    steps = steps8;
  if (frames == 10)
    steps = steps9;
  if (frames == 11)
    steps = steps10;
  if (frames == 12)
    steps = steps11;
  if (frames == 13)
    steps = steps12;      
  if (frames == 14)
    steps = steps13;
  if (frames == 15)
    steps = steps14;
  if (frames == 16)
    steps = steps15;
  if (frames == 17)
    steps = steps16;
  if (frames == 18)
    steps = steps17;
  if (frames == 19)
    steps = steps18;
  if (frames == 20)
    steps = steps19;
  if (frames == 21)
    steps = steps20;
  if (frames == 22)
    steps = steps21;
  if (frames == 23)
    steps = steps22;
  if (frames == 24)
    steps = steps23;
  if (frames == 25)
    steps = steps24;
  if (frames == 26)
    steps = steps25;
  if (frames == 27)
    steps = steps26;
  if (frames == 28)
    steps = steps27;
  if (frames == 29)
    steps = steps28;
  if (frames == 30)
    steps = steps29;
  if (frames == 31)
    steps = steps30;
  if (frames == 32)
    steps = steps31;
  if (frames == 33)
    steps = steps32;
  if (frames == 34)
    steps = steps33;
  if (frames == 35)
    steps = steps34;
  if (frames == 36)
    steps = steps35;
  if (frames == 37)
    steps = steps36;
  if (frames == 38)
    steps = steps37;
  if (frames == 39)
    steps = steps38;
  if (frames == 40)
    steps = steps39;

  // run stepper
  stepper.setSpeed(motorspeed);
  stepper.step(steps); 

  // testing
  Serial.println(steps);
  digitalWrite(led_pin, LOW);

  // delay for next round
  delay(interval_tm);

  //testing     
  Serial.print("Time: ");
  time = millis();
  Serial.println(time);
}

// pause cycle after last cycle complete
void pause() {
  digitalWrite(shutter_pin, LOW);   
  stepper.setSpeed(0); 
  stepper.step(0);
}

void end_session() {

  digitalWrite(shutter_pin, LOW);   
  stepper.setSpeed(0); 
  stepper.step(0);

  while (1) { 
  }
}

void setup() {

  pinMode(pin2, INPUT); // switch input
  pinMode(pin3, INPUT);
  digitalWrite(pin2, HIGH); // activate pull-up resistors
  digitalWrite(pin3, HIGH);
  pinMode(shutter_pin, OUTPUT);
  pinMode(led_pin, OUTPUT);
  Serial.begin(19200);
}

void loop() {

  // cycle exposure/dither to end of session - exits end_session
  pinval2 = digitalRead(pin2); // read pin value
  pinval3 = digitalRead(pin3);
  if (pin2 == HIGH && pin3 == HIGH ) {
    // for testing without hardware switch
    //if (millis() < session_tm) {
      cycle();
    }

    /* pause/stop - interupts exposure and completes dither cycle, 
     ready for next shot in sequence */

    pinval2 = digitalRead(pin2); // read pin value
    pinval3 = digitalRead(pin3);
    while (pin2 == LOW && pin3 == HIGH) {
      pause();
    }

    /* Note: resetting the board or turning the power off will 
     reset the entire session. However, the dither position will 
     be retained */

    // stop - user end session
    pinval2 = digitalRead(pin2); // read pin value
    pinval3 = digitalRead(pin3);
    if (pin2 == LOW && pin3 == LOW) {
      end_session();
    }
    // end session automatically
    if (frames == 40 || frames == images || millis() >= session_tm) {
      end_session();     
    }
 }