Skip to content

Carbot/370 State of Play

December 7, 2018

As of today the Carbot hardware and software are basically functional, if rough.  The control program written in C runs on the MVS operating system on a simulated IBM 370 computer under the Hercules emulator running on a raspberry Pi Zero W.  The Pi is housed in a miniature mainframe case with an infrared rangefinder mounted on it and rides on a converted radio control car chassis.  The car’s motors are controlled by a pimoroni explorer pHAT mounted on the Pi.

I’m missing the side facing sensor needed for wall following and I’m using direct drive for the motors rather than using PWM to modulate them.  I do think it’s funny to see the mini-mainframe darting around getting stuck under the furniture.

I had been worried that running the motors from the same 5V supply as the Pi would be a problem but it seems not to be an issue so far.

 The Carbot software is pretty simple at the moment it’s meant to be run as a TSO command or a batch job and it does one action per run as controlled by parameters on the command line for example “carbot f” as a TSO command or // EXEC PGM=CARBOT,PARM=’F’ will each start the motors going forward. In the demo video “carbot g” starts a “Go” routine that runs forward and turns left when it sees an obstacle.

void go(int ttl){
    int maxprox=7500,tprox=7000;
    int fprox,now,start=millis();
    fprox=analogRead(0); //read front sensor
    printf("Go starts at %d\n",start);
    while (now-start< ttl){
    	if (fproxtprox) &&(now-start<ttl)){
    	    	drive(1,0,0,1); //hardleft
	    	now=millis();
	    	fprox=analogRead(0);
    	    }
    	    drive(0,0,0,0);
    	}
    	now=millis();
    	fprox=analogRead(0);
    }
    drive(0,0,0,0);
}

The "drive(r1,r2,l1,l2)" routine used above controls the right and left motors such that drive(1,0,1,0) starts both motors going forward while drive(1,0,0,1) runs lthe right motor full forward and the left motor full reverse so we get a hard left turn.

//CARBOT01 JOB CLASS=A,MSGCLASS=A,REGION=4096K,MSGLEVEL=(0,0),
// USER=HERC01,PASSWORD=CUL8TR
//S1 EXEC GCCCL,COS1='-S',
// PARM.ASM='DECK,NOLIST,TEST,NOXREF,NOMLOGIC,NORLD',
// PARM.LKED='TEST'
//COMP.INCLUDE DD DSN=HERC01.WIRINGMV.INCLUDE,DISP=SHR
//SYSIN DD *
#include 
#include 
#include "wiring.h"
int rfw=24,lfw=25; // forward right and left wheels
int rrv=28,lrv=29; // reverse right and left wheels
void init(){
  printf("init\n");
  pinMode(rfw,OUTPUT);pinMode(lfw,OUTPUT);
  pinMode(rrv,OUTPUT);pinMode(lrv,OUTPUT);
}
void drive(int rf,int rr,int lf,int lr){
    digitalWrite(rfw,rf);digitalWrite(rrv,rr);
    digitalWrite(lfw,lf);digitalWrite(lrv,lr);
}
void keepaway(int ttl){
    int minprox=5000, maxprox=8000;
    int fprox,now,start=millis();
    fprox=analogRead(0); //read front sensor
    printf("keepaway starts at %d\n",start);
    while (now-start< ttl){
    	//printf("keepaway at t=%d, prox is %d\n",now,fprox);
    	if (fproxmaxprox){
    	    drive(0,1,0,1);
    	} else {
    	    drive(0,0,0,0);
    	}
    	delay(100);
    	now=millis();
    	fprox=analogRead(0);
    }
    drive(0,0,0,0);
}
void go(int ttl){
    int maxprox=7500,tprox=7000;
    int fprox,now,start=millis();
    fprox=analogRead(0); //read front sensor
    printf("Go starts at %d\n",start);
    while (now-start< ttl){
    	if (fproxtprox) &&(now-start<ttl)){
    	    	drive(1,0,0,1); //hardleft
	    	now=millis();
	    	fprox=analogRead(0);
    	    }
    	    drive(0,0,0,0);
    	}
    	now=millis();
    	fprox=analogRead(0);
    }
    drive(0,0,0,0);
}

int main(int argc, char *argv[]){   
    int retval=42;
    int fprox=43;
    printf("Oh Hello - Carbot Here\n");
    init();
    switch(argv[1][0]){
    case 'G': case 'g': //"Go" for 3 seconds
        go(3000);    
        break;
    case 'K': case 'k': //play keepaway for 10 seconds
        keepaway(10000);    
        break;
    case '?': //read the front sensor
        fprox=analogRead(0);    
        printf("front sensor says %d\n",fprox);
        break;
    case 'T': case 't':
        drive(1,0,0,1);    
        break;
    case 'F': case 'f':
        drive(1,0,1,0);    
        break;
    case 'R': case 'r':
        drive(0,1,0,1);    
        break;
    case 'X': case 'x': //stop
        drive(0,0,0,0);
        break;
    default:
        printf("not doing %s(%x %x) \n",argv[1],argv[1][0],argv[1][1]);
    }
    //asm(" WTO 'OK Bye' ");
    return retval;
}
//LKED.SYSLMOD DD DSN=HERC01.LOAD(CARBOT),DISP=SHR
//* DISP=(,CATLG),
//* UNIT=SYSDA,SPACE=(TRK,(10,5,5)),
//* DCB=(RECFM=U,BLKSIZE=19069)
//*     EXEC PGM=*.S1.LKED.SYSLMOD,
//*     PARM='write 0 low'
//*SYSPRINT DD SYSOUT=*
//*SYSTERM DD SYSOUT=*
//*SYSIN DD DUMMY
//*     EXEC PGM=*.S1.LKED.SYSLMOD,
//*     PARM='read 0'
//*SYSPRINT DD SYSOUT=*
//*SYSTERM DD SYSOUT=*
//*SYSIN DD DUMMY

I had to update the SVC intercept hook code in Hercules and the wiring.h GCCMVS macros to support the millis() call.

//INCLUDE JOB CLASS=A,MSGCLASS=A,REGION=4096K,
// USER=HERC01,PASSWORD=CUL8TR
//*ALLOC EXEC PGM=IEFBR14
//*SYSUT2   DD  DSNAME=HERC01.WIRINGMV.INCLUDE,DISP=(,CATLG),
//*             UNIT=SYSDA,SPACE=(TRK,(10,5,5)),
//*             DCB=(RECFM=VB,LRECL=255,BLKSIZE=6233)
//LOAD EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=A
//SYSIN DD DUMMY
//SYSUT2 DD DSNAME=HERC01.WIRINGMV.INCLUDE(WIRING),DISP=SHR
//SYSUT1 DD *
  //18-12-06 including millis() code 9
#define INPUT 0
#define OUTPUT 1
#define LOW 0
#define HIGH 1
int adcSetup(){
    int retval='s';
    asm(" LA 0,X'42' FLAG FOR SVC 255 ");
    asm(" LA 1,7 MCP3003 ADC SETUP ");
    asm(" LA 2,0 ");
    asm(" SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval));
    if((retval<0)){
        printf("mcp3002Setup return value is %d\n",retval);
    }
    return retval;
}
int millis(){
    int retval='R';
    asm(" LA 2,0 \n"
        " LA 1,9\n" //code for analog read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        :); //no inputs to asm()
    return retval;
}
int analogRead(int pin){
    int retval='R';
    asm(" LR 2,%1 \n"
        " LA 1,8\n" //code for analog read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        : "r" (pin));
    return retval;
}
int setup(){
    int retval='s';
    asm(" LA 0,X'42' FLAG FOR SVC 255 ");
    asm(" LA 1,6 SETUP ");
    asm(" LA 2,0 ");
    asm(" SVC 255 ISSUE SVC\n"
        " LR %0,15"
        : "=r" (retval));
    if((retval!=0) && (retval!=180923)){
        printf("setup return value is %d\n",retval);
    }
    return retval;
}
int digitalWrite(int pin, int value){
    asm(" LR 2,%0 \n"
        " LR 1,%1\n"
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (pin), "r" (value+2));//((value!=0)+2));
}
int digitalRead(int pin){
    int retval='R';
    asm(" LR 2,%0 \n"
        " LA 1,4\n" //code for read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        : "r" (pin));
    return retval;
}
int pinMode(int pin, int value){
    asm(" LR 2,%0 \n" //pin
        " LR 1,%1\n"  //value
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (pin), "r" ((value!=0)));
}
void delay(int value){
    asm(" LR 2,%0 \n" //ddelay time in MS
        " LA 1,5\n"   //code for delay
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (value));
}
//INCLUDE JOB CLASS=A,MSGCLASS=A,REGION=4096K,
// USER=HERC01,PASSWORD=CUL8TR
//*ALLOC EXEC PGM=IEFBR14
//*SYSUT2   DD  DSNAME=HERC01.WIRINGMV.INCLUDE,DISP=(,CATLG),
//*             UNIT=SYSDA,SPACE=(TRK,(10,5,5)),
//*             DCB=(RECFM=VB,LRECL=255,BLKSIZE=6233)
//LOAD EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=A
//SYSIN DD DUMMY
//SYSUT2 DD DSNAME=HERC01.WIRINGMV.INCLUDE(WIRING),DISP=SHR
//SYSUT1 DD *
  //18-12-06 including millis() code 9
#define INPUT 0
#define OUTPUT 1
#define LOW 0
#define HIGH 1
int adcSetup(){
    int retval='s';
    asm(" LA 0,X'42' FLAG FOR SVC 255 ");
    asm(" LA 1,7 MCP3003 ADC SETUP ");
    asm(" LA 2,0 ");
    asm(" SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval));
    if((retval<0)){
        printf("mcp3002Setup return value is %d\n",retval);
    }
    return retval;
}
int millis(){
    int retval='R';
    asm(" LA 2,0 \n"
        " LA 1,9\n" //code for analog read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        :); //no inputs to asm()
    return retval;
}
int analogRead(int pin){
    int retval='R';
    asm(" LR 2,%1 \n"
        " LA 1,8\n" //code for analog read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        : "r" (pin));
    return retval;
}
int setup(){
    int retval='s';
    asm(" LA 0,X'42' FLAG FOR SVC 255 ");
    asm(" LA 1,6 SETUP ");
    asm(" LA 2,0 ");
    asm(" SVC 255 ISSUE SVC\n"
        " LR %0,15"
        : "=r" (retval));
    if((retval!=0) && (retval!=180923)){
        printf("setup return value is %d\n",retval);
    }
    return retval;
}
int digitalWrite(int pin, int value){
    asm(" LR 2,%0 \n"
        " LR 1,%1\n"
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (pin), "r" (value+2));//((value!=0)+2));
}
int digitalRead(int pin){
    int retval='R';
    asm(" LR 2,%0 \n"
        " LA 1,4\n" //code for read
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC\n"
        " LR %0,15\n"
        : "=r" (retval) //returned value
        : "r" (pin));
    return retval;
}
int pinMode(int pin, int value){
    asm(" LR 2,%0 \n" //pin
        " LR 1,%1\n"  //value
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (pin), "r" ((value!=0)));
}
void delay(int value){
    asm(" LR 2,%0 \n" //ddelay time in MS
        " LA 1,5\n"   //code for delay
        " LA 0,X'42' FLAG FOR SVC 255 \n"
        " SVC 255 ISSUE SVC"
        : /*no outputs*/
        : "r" (value));
}
Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: