Servos in uLisp


#1

Hello. I am a beginner in programming and microcontrollers.
I bought a couple of weeks ago an Arduino kit, which includes the Uno R3. I am doing the projects included in the manual without any problem. I program them in the Arduino language and also in uLisp (much clearer, cleaner and more elegant). But I have a problem activating a servo. I can do it in Arduino language using the Servo.h library, but not in uLisp. Is this not possible? Is there a way to use the library in uLisp?
Or some other solution accessible to a beginner?
I am not in a position to program something like this.
Any advice or help will be welcome.
This world is fascinating!!
Thank you very much


#2

Servos aren’t built-in to uLisp, but you could easily add them with an extension.


#3

Here is a little extension that manages an arbitrary number of servos:

#include <Servo.h>

 struct ulservo {
  int snum;
  int pin;
  struct ulservo* nextservo;
  Servo servo;
};

struct ulservo* servolist = NULL;
struct ulservo* curservo = NULL;

/*
  (servo-attach snum pin [usmin] [usmax])
  Attach servo snum to pin. Optionally define new pulse width min/max in microseconds.
*/
object *fn_ServoAttach (object *args, object *env) {
  (void) env;
 
  int snum = checkinteger(first(args));   // zero based index!;
  int pin = checkinteger(second(args));
  int usmin = 544;
  int usmax = 2400;

  args = cdr(args);
  args = cdr(args);
  if (args != NULL) {
    usmin = checkinteger(first(args));
    args = cdr(args);
    if (args != NULL) {
      usmax = checkinteger(first(args));
    }
  }

  if(servolist == NULL) {
    if((servolist = (struct ulservo*)malloc(sizeof(struct ulservo))) == NULL) {
       pfstring("Out of memory", (pfun_t)pserial);
       return nil;
    }

    servolist->snum = snum;
    servolist->pin = pin;
    servolist->nextservo = NULL;
    servolist->servo = Servo();
    servolist->servo.attach(pin, usmin, usmax);
  }
  else {
    curservo = servolist;
    while(curservo->nextservo != NULL) {
      if ((curservo->snum == snum) || (curservo->pin == pin)) {
        pfstring("Servo number or pin already in use!", (pfun_t)pserial);
        return nil;
      }
      curservo = curservo->nextservo;
    }

    if ((curservo->snum == snum) || (curservo->pin == pin)) {
      pfstring("Servo number or pin already in use!", (pfun_t)pserial);
      return nil;
    }

    if((curservo->nextservo = (struct ulservo*)malloc(sizeof(struct ulservo))) == NULL) {
        pfstring("Out of memory", (pfun_t)pserial);
        return nil;
    }

    curservo = curservo->nextservo;

    curservo->snum = snum;
    curservo->pin = pin;
    curservo->servo = Servo();
    curservo->servo.attach(pin, usmin, usmax);
    curservo->nextservo = NULL;
  }
  return tee;
}

/*
  (servo-write snum angle)
  Set angle of servo snum in degrees (0 to 180).
*/
object *fn_ServoWrite (object *args, object *env) {
  (void) env;
 
  int snum = checkinteger(first(args));
  int angle = checkinteger(second(args));
  curservo = servolist;

  if (curservo != NULL) {

    while(curservo->snum != snum) {
      curservo = curservo->nextservo;
      if (curservo == NULL) break;
    }

    if(curservo != NULL) {
      curservo->servo.write(angle);
      return number(angle);
    }
  }

  pfstring("Servo not found", (pfun_t)pserial);
  return nil;
}

/*
  (servo-write-microseconds snum usecs)
  Set angle of servo snum using a pulse width value in microseconds.
*/
object *fn_ServoWriteMicroseconds (object *args, object *env) {
  (void) env;
 
  int snum = checkinteger(first(args));
  int us = checkinteger(second(args));
  curservo = servolist;

  if (curservo != NULL) {

    while(curservo->snum != snum) {
      curservo = curservo->nextservo;
      if (curservo == NULL) break;
    }

    if(curservo != NULL) {
      curservo->servo.writeMicroseconds(us);
      return number(us);
    }
  }

  pfstring("Servo not found", (pfun_t)pserial);
  return nil;
}

/*
  (servo-read snum)
  Read current angle of servo snum in degrees.
*/
object *fn_ServoRead (object *args, object *env) {
  (void) env;

  int snum = checkinteger(first(args));
  curservo = servolist;

  if (curservo != NULL) {

    while(curservo->snum != snum) {
      curservo = curservo->nextservo;
      if (curservo == NULL) break;
    }

    if(curservo != NULL) {
      return number(curservo->servo.read());
    }
  }

  pfstring("Servo not found", (pfun_t)pserial);
  return nil;
}

/*
  (servo-detach snum)
  Detach servo snum, thus freeing the assigned pin for other tasks.
*/
object *fn_ServoDetach (object *args, object *env) {
  (void) env;

  int snum = checkinteger(first(args));
  curservo = servolist;
  struct ulservo* lastservo = servolist;

  if (curservo != NULL) {

    while(curservo->snum != snum) {
      lastservo = curservo;
      curservo = curservo->nextservo;
      if (curservo == NULL) break;
    }

    if(curservo != NULL) {
      curservo->servo.detach();
      if (curservo == servolist) {    // delete first element of list
        servolist = curservo->nextservo;
      }
      else {
        lastservo->nextservo = curservo->nextservo;
      }
      free(curservo);
      return tee;
    }
  }

  pfstring("Servo not found", (pfun_t)pserial);
  return nil;
}

// Symbol names
const char stringServoAttach[] PROGMEM = "servo-attach";
const char stringServoWrite[] PROGMEM = "servo-write";
const char stringServoWriteMicroseconds[] PROGMEM = "servo-write-microseconds";
const char stringServoRead[] PROGMEM = "servo-read";
const char stringServoDetach[] PROGMEM = "servo-detach";

// Documentation strings
const char docServoAttach[] PROGMEM = "(servo-attach snum pin [usmin] [usmax])\n"
"Attach servo snum to pin. Optionally define new pulse width min/max in microseconds.";
const char docServoWrite[] PROGMEM = "(servo-write snum angle)\n"
"Set angle of servo snum in degrees (0 to 180).";
const char docServoWriteMicroseconds[] PROGMEM = "(servo-write snum usecs)\n"
"Set angle of servo snum using a pulse width value in microseconds.";
const char docServoRead[] PROGMEM = "(servo-read snum)\n"
"Read current angle of servo snum in degrees.";
const char docServoDetach[] PROGMEM = "(servo-detach snum)\n"
"Detach servo snum, thus freeing the assigned pin for other tasks.";

// Symbol lookup table
const tbl_entry_t lookup_table2[] PROGMEM = {

  { stringServoAttach, fn_ServoAttach, 0224, docServoAttach },
  { stringServoWrite, fn_ServoWrite, 0222, docServoWrite },
  { stringServoWriteMicroseconds, fn_ServoWriteMicroseconds, 0222, docServoWriteMicroseconds },
  { stringServoRead, fn_ServoRead, 0211, docServoRead },
  { stringServoDetach, fn_ServoDetach, 0211, docServoDetach },

};

// Table cross-reference functions - do not edit below this line

tbl_entry_t *tables[] = {lookup_table, lookup_table2};
const unsigned int tablesizes[] = { arraysize(lookup_table), arraysize(lookup_table2) };

const tbl_entry_t *table (int n) {
  return tables[n];
}

unsigned int tablesize (int n) {
  return tablesizes[n];
}

Save the code above as “ServoExtension.ino” (for example) in the same directory as your ulisp.ino file. When you compile uLisp within the Arduino ide, the extension should automatically be included. Before that please uncomment

#define extensions

in the main .ino file. These are the new uLisp functions the extension provides:

(servo-attach snum pin [usmin] [usmax]) 
"Attach servo snum to pin. Optionally define new pulse width min/max in microseconds."
(servo-write snum angle)
"Set angle of servo snum in degrees (0 to 180)."
(servo-write snum usecs)
"Set angle of servo snum using a pulse width value in microseconds."
(servo-read snum)
"Read current angle of servo snum in degrees."
(servo-detach snum)
"Detach servo snum, thus freeing the assigned pin for other tasks."

This should work; I’ve extracted it from my ulisp-lispbox extension. If you run into problems, let me know!


#4

I hope I don’t have space problems with the board.
Thank you very much for your help