OWI ROBOT ARM CONTROL
 

The Archive's OWI Robot Arm is a USB-controlled version, obtained as a kit from Maplin Electronics sometime in 2012. Requiring simple tools to assemble and using four D-cells, the arm is designed to work with a range of home computers via a USB-1 connection.
 

The Archive's fully constructed Arm

 
In order to use the Robot Arm on a BBC micro there needs to be a USB interface connected. This project uses the USB interface of a Retroclinic Datacentre. Although, perhaps, primarily designed for use with USB memory sticks, the Datacentre USB interface can be programmed to work with a number of other devices, such as a mouse or a keyboard.

The Datacentre documentation included example programs to connect a USB mouse to the BBC micro and comprehensive details about programming the on-board USB controller chip. In addition the Robot Arm documentation included a booklet containing example control programs written in Python 2, Visual Basic and C#.

This information was studied and a prototype control program was produced to allow keyboard commands to control the Robot Arm's motors. Following a suggestion at the WROCC Show 2014, this prototype was modified to allow analogue joystick control of the arm.

The prototype was constructed in several stages;

  1. recognising that the arm was connected to the USB port,
  2. sending a simple command to the arm; this command being switch the light on and off,
  3. add commands for each motor in turn
Connecting the Robot Arm
The code shown below was developed to connect the arm to the USB port of the Datacentre.
 

   10REM> ARM1
   30REM J DALE
   40REM NOVEMBER 2012
   50REM VERSION 1.00
   60REM USES Retroclinic Datacentre and OWI Robot Arm
   70:
   71REM Set Break key to rest system on error
   80*KEY10OLD|MF.I%=1TO15000:N.|MRUN|M
   81:
   90MODE7
   91REM Set global variables
  110USB=&FCF8 : REM address of USB data buffer
  120:
  121REM Check if arm connected and switched on
  130PRINT"QUERY USB PORT 2"
  140B%=FN_FD
  150IFB%=0THENPRINTCHR$129"No USB device detected."
     'CHR$129"Switch on USB interface on arm"
     'CHR$129"and make sure arm connected to USB.":END
  160PRINTCHR$130"Robot arm detected."
  170:
  180REM Set current device to device 0
  190PROC_FB
  200PROC_CMD("IPA")
  210PROC_FB
  220PROC_CMD("SC 0")
  230END
  240:
 1051REM Check if USB device attached
 1060DEFFN_FD
 1070LOCALB%,C%
 1080REPEAT:PROC_FB
 1090PROC_CMD("QP2"):B%=?USB:C%=?USB:UNTILC%=0
 1100=B%
 1110:
 1111REM Send a command string to USB buffer; terminate with CR
 1120DEFPROC_CMD(A$)
 1130LOCALT%,V%
 1140FORT%=1TOLEN(A$):V%=ASC(MID$(A$,T%,1))
 1150?USB=V%
 1160NEXT
 1170?USB=13:ENDPROC
 1180:
 1181REM Clear USB buffer
 1190DEFPROC_FB:LOCALT%,X%:FORT%=0TO20:X=?USB:NEXT:ENDPROC

 
The code works in the following way. USB port 2 is the port used by the arm. FN_FD on line 140 clears the USB port data buffer and sends the string "QP2" to the USB port data buffer via PROC_CMD, returning a value marking the success of the command. If the result is zero, this indicates no device has been found and an error message is displayed and the program halts.

A non-zero result displays a message that the arm was detected and the program goes on to set the current device on USB port 2 to be device 0, the default device. This is accomplished by lines 190 to 220.

The Break key has been programmed to reset the USB connection and run the program. The Break key would be used if the arm had not been switched on, for example.
 

Arm Control Codes
To operate the robot arm the string "SSU $4006000100000300" is first sent to the arm USB interface. This string is followed by 3 bytes, which control the action of the arm motors and light.

The bytes 0, 0, 0 will stop all activity by the arm.

Part of Arm

Byte 1

Byte 2

Byte 3

Light On

0

0

1

Light Off

0

0

0

Gripper Close

1

0

LightOn%

Gripper Open

2

0

LightOn%

Gripper off

0

0

LightOn%

Wrist Forward

8

0

LightOn%

Wrist Back

4

0

LightOn%

Wrist Off

0

0

LightOn%

Elbow Forward

32

0

LightOn%

Elbow Back

16

0

LightOn%

Elbow Off

0

0

LightOn%

Shoulder Forward

128

0

LightOn%

Shoulder Back

64

0

LightOn%

Shoulder Off

0

0

LightOn%

Turntable Left

0

2

LightOn%

Turntable Right

0

1

LightOn%

Turntable Stop

0

0

LightOn%

The global variable LightOn% is initially set to 0 when the program runs. When the command to turn the light on is given this variable is set to 1 and set to 0 when the light is turned off. This global variable allows the light state to remain as set for all other commands.
 

Switching the light on and off
This was the next step to be completed as it would set/unset the state of the light for all other commands and would produce the necessary functions and procedures needed to add the motor control commands.
 

   10REM> ARM1
   30REM J DALE
   40REM NOVEMBER 2012
   50REM VERSION 1.00
   60REM USES Retroclinic Datacentre and OWI Robot Arm
   70:
   71REM Set Break key to rest system on error
   80*KEY10OLD|MF.I%=1TO15000:N.|MRUN|M
   81:
   90MODE7
   91REM Set global variables
  100LightOn%=0
  110USB=&FCF8 : REM address of USB data buffer
  120:
  121REM Check if arm connected and switched on
  130PRINT"QUERY USB PORT 2"
  140B%=FN_FD
  150IFB%=0THENPRINTCHR$129"No USB device detected."
     'CHR$129"Switch on USB interface on arm"
     'CHR$129"and make sure arm connected to USB.":END
  160PRINTCHR$130"Robot arm detected."
  170:
  180REM Set current device to device 0
  190PROC_FB
  200PROC_CMD("IPA")
  210PROC_FB
  220PROC_CMD("SC 0")

  222PROC_LIGHT("ON"):PROC_WAIT(5):PROC_LIGHT("OFF")
  230END
  240:
  870DEFPROC_LIGHT(C$)
  880IF C$="ON" THEN PROC_MSG(0,0,1):LightOn%=1 ELSE PROC_MSG(0,0,0)
     :LightOn%=0
  890ENDPROC
  900:
  910DEFPROC_WAIT(T)
  920LOCALT%:T%=TIME
  930REPEATUNTILTIME>T%+T*100
  940ENDPROC
  990DEFPROC_MSG(B1%,B2%,B3%)
 1000PROC_FB
 1010PROC_CMD("SSU $4006000100000300")
 1030?USB=B1%:?USB=B2%:?USB=B3%
 1040ENDPROC
 1050:
 1051REM Check if USB device attached
 1060DEFFN_FD
 1070LOCALB%,C%
 1080REPEAT:PROC_FB
 1090PROC_CMD("QP2"):B%=?USB:C%=?USB:UNTILC%=0
 1100=B%
 1110:
 1111REM Send a command string to USB buffer; terminate with CR
 1120DEFPROC_CMD(A$)
 1130LOCALT%,V%
 1140FORT%=1TOLEN(A$):V%=ASC(MID$(A$,T%,1))
 1150?USB=V%
 1160NEXT
 1170?USB=13:ENDPROC
 1180:
 1181REM Clear USB buffer
 1190DEFPROC_FB:LOCALT%,X%:FORT%=0TO20:X=?USB:NEXT:ENDPROC

 
Line 100 sets the global variable LightOn% to 0 so that the light will be off by default. Lines 910 to 940 provide a delay in seconds. The real parameter T allows fractional seconds to be entered.

Lines 990 to 1040 send the appropriate message to control the arm's functions as given in the Arm Control Codes section.

Lines 870 to 890 control the operation of the light. Once this was proven to work the commands for all the other arm functions were programmed along with a command-driven control program. The full prototype program is given in the listing below.
 

10REM> ARM9a
30REM J DALE
40REM NOVEMBER 2012 - APRIL 2014
50REM VERSION 2.09
60REM USES Retroclinic Datacentre and OWI Robot Arm
70:
71REM Set Break key to rest system on error
80*KEY10OLD|MF.I%=1TO15000:N.|MRUN|M
81:
90MODE7
91REM Set global variables
100LightOn%=0
110USB=&FCF8 : REM address of USB data buffer
120:
121REM Check if arm connected and switched on
130PRINT"QUERY USB PORT 2"
140B%=FN_FD
150IFB%=0THENPRINTCHR$129"No USB device detected."'CHR$129"Switch on USB interface on arm"'CHR$129"and make sure arm connected to USB.":END
160PRINTCHR$130"Robot arm detected."
170:
180REM Set current device to device 0
190PROC_FB
200PROC_CMD("IPA")
210PROC_FB
220PROC_CMD("SC 0")
240PROCScreen
250REMPROCREADPROG
280REPEAT
290INPUT"COMMAND: "C$:C$=FNU(C$)
291PROCExecuteCommand(C$)
292IF C$="HELP" OR LEFT$(C$,1)="H" THEN MODE3:PROC_HELP:MODE7:PROCScreen
300UNTILC$="QUIT" OR C$="Q"
310END
320:
330DEFPROCExecuteCommand(C$)
340LOCALC1$,C2$,C3$,P%
350C1$="":C2$="":C3$=""
360P%=INSTR(C$," ")
370IF P%=0 THEN 520
380C1$=LEFT$(C$,P%-1):C$=MID$(C$,P%+1,255)
390P%=INSTR(C$," ")
400IF P%=0 THEN C2$=C$:C$=C1$:C1$=C2$:C2$="":GOTO440
410C2$=LEFT$(C$,P%-1):C$=MID$(C$,P%+1,255)
420C3$=C$:C$=C1$:C1$=C2$:C2$=C3$
440IF C$="LIGHT" OR LEFT$(C$,1)="L" THEN PROC_LIGHT(C1$)
450IF C$="CLOSE" OR LEFT$(C$,1)="C" THEN PROC_GRIPPER(C$,C1$)
460IF C$="OPEN" OR LEFT$(C$,1)="O" THEN PROC_GRIPPER(C$,C1$)
470IF C$="TURN" OR LEFT$(C$,1)="T" THEN PROC_BASE(C1$,C2$)
480IF LEFT$(C$,4)="GRIP"OR LEFT$(C$,1)="G" THEN PROC_GRIPPER(C1$,C2$)
490IF C$="WRIST"OR LEFT$(C$,1)="W" THEN PROC_WRIST(C1$,C2$)
500IF C$="SHOULDER" OR LEFT$(C$,1)="S" THEN PROC_SHOULDER(C1$,C2$)
510IF C$="ELBOW" OR LEFT$(C$,1)="E" THEN PROC_ELBOW(C1$,C2$)
520ENDPROC
560:
570DEFPROC_GRIPPER(C1$,C2$)
580LOCAL T:T=VAL(C2$)
590IF C1$="CLOSE" OR LEFT$(C1$,1)="C" THEN PROC_MSG(1,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
600IF C1$="OPEN" OR LEFT$(C1$,1)="O" THEN PROC_MSG(2,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
610ENDPROC
620:
630DEFPROC_SHOULDER(C1$,C2$)
640LOCAL T:T=VAL(C2$)
650IF LEFT$(C1$,4)="BACK" OR LEFT$(C1$,1)="B" THEN PROC_MSG(64,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
660IF LEFT$(C1$,4)="FORW" OR LEFT$(C1$,1)="F" THEN PROC_MSG(128,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
670ENDPROC
680:
690DEFPROC_ELBOW(C1$,C2$)
700LOCAL T:T=VAL(C2$)
710IF LEFT$(C1$,4)="BACK" OR LEFT$(C1$,1)="B" THEN PROC_MSG(16,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
720IF LEFT$(C1$,1)="F" THEN PROC_MSG(32,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
730ENDPROC
740:
750DEFPROC_WRIST(C1$,C2$)
760LOCAL T:T=VAL(C2$)
770IF LEFT$(C1$,1)="B" THEN PROC_MSG(4,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
780IF LEFT$(C1$,1)="F" THEN PROC_MSG(8,0,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
790ENDPROC
800:
810DEFPROC_BASE(C1$,C2$)
820LOCAL T:T=VAL(C2$)
830IF LEFT$(C1$,1)="L" THEN PROC_MSG(0,2,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
840IF LEFT$(C1$,1)="R" THEN PROC_MSG(0,1,LightOn%):PROC_WAIT(T):PROC_MSG(0,0,LightOn%)
850ENDPROC
860:
870DEFPROC_LIGHT(C$)
880IF C$="ON" THEN PROC_MSG(0,0,1):LightOn%=1 ELSE PROC_MSG(0,0,0):LightOn%=0
890ENDPROC
900:
910DEFPROC_WAIT(T)
920LOCALT%:T%=TIME
930REPEATUNTILTIME>T%+T*100
940ENDPROC
950:
960DEFPROC_ERR
970LOCALX%:REPEAT:X%=?USB:VDUX%:UNTILX%=13:VDU10:ENDPROC
980:
990DEFPROC_MSG(B1%,B2%,B3%)
1000PROC_FB
1010PROC_CMD("SSU $4006000100000300")
1030?USB=B1%:?USB=B2%:?USB=B3%
1040ENDPROC
1050:
1051REM Check if USB device attached
1060DEFFN_FD
1070LOCALB%,C%
1080REPEAT:PROC_FB
1090PROC_CMD("QP2"):B%=?USB:C%=?USB:UNTILC%=0
1100=B%
1110:
1111REM Send command string to USB buffer; terminate with CR
1120DEFPROC_CMD(A$)
1130LOCALT%,V%
1140FORT%=1TOLEN(A$):V%=ASC(MID$(A$,T%,1))
1150?USB=V%
1160NEXT
1170?USB=13:ENDPROC
1180:
1181REM Clear USB buffer
1190DEFPROC_FB:LOCALT%,X%:FORT%=0TO20:X=?USB:NEXT:ENDPROC
1200:
1210DEFPROC_HELP
1220VDU19,0,4,0;0;
1230PRINT"ROBOT ARM COMMANDS"
1240PRINT
1250PRINT"All commands may be abbreviated to a single letter."
1260PRINT
1270PRINT"LIGHT ON/OFF - switches the light on or off."
1280PRINT
1290PRINT"OPEN t - Opens the gripper for a time t seconds."
1300PRINT"CLOSE t - Closes the gripper for a time t seconds."
1310PRINT"GRIPPER OPEN/CLOSE t - Opens or closes the gripper for t seconds."
1320PRINT
1330PRINT"TURN LEFT/RIGHT t - turns the base left or right for t seconds."
1340PRINT
1350PRINT"ELBOW BACK/FORWARDS t - moves the elbow joint for t seconds."
1360PRINT
1370PRINT"WRIST BACK/FORWARDS t - moves the wrist joint for t seconds."
1380PRINT
1390PRINT"SHOULDER BACK/FORWARDS t - moves the shoulder joint for t seconds."
1400PRINT
1410PRINT"HELP - Displays this page."
1420PRINT
1430PRINT"Press the SPACEBAR to continue."
1440REPEATUNTILGET=32
1450ENDPROC
1460:
1470DEFFNU(M$)
1480LOCALR$,I%,C%
1490R$=M$:R$=""
1500FORI%=1TOLEN(M$):C%=ASC(MID$(M$,I%,1))
1510IF C%>96ANDC%<123THENC%=C%AND223
1520R$=R$+CHR$(C%)
1530NEXT:=R$
1540:
1550DEFPROCScreen
1560CLS
1570PRINTCHR$129CHR$157CHR$135SPC6"ROBOT ARM CONTROL V9a"
1580FORI%=20TO24:PRINTTAB(0,I%)CHR$148CHR$157CHR$135;:NEXT
1590PRINTTAB(3,20)"COMMANDS"
1600PRINTTAB(2,21)CHR$131"Light:"CHR$135"L <ON/OFF>";
1610PRINTCHR$131" Turn:"CHR$135"T <L/R> N"
1620PRINTTAB(2,22)CHR$131"Wrist:"CHR$135"W <F/B> N";
1630PRINTCHR$131" Elbow:"CHR$135"E <F/B> N"
1640PRINTTAB(17,23)CHR$131"Shoulder:"CHR$135"S <F/B> N"
1650PRINTTAB(2,24)CHR$131" Quit:"CHR$135"Q";
1660PRINTTAB(18,24)CHR$131"Gripper:"CHR$135"O N/C N";
1670VDU28,1,19,39,1
1680ENDPROC
1690:

 
Evaluation
The OWI Robot Arm is a wonderful toy, especially when used with the joystick option. It is no good for precise work due to the large hysteresis in the gear trains and the lack of precision in the motors. There is also no feedback available so that the control program is unaware of the absolute position of the arm. Nevertheless children (and adults) love it, moving the arm to pick up an item and then moving the arm to drop the item elsewhere.

The D-cells last a very long time, so long that is is wise to remove them if the arm is to be stored for a period of time

The software works on both BBC model B computers and the BBC Master when equipped with a Datacentre. Internal Datacentres work just as well as external ones.

The software is presented 'as is'. It is a work in progress. One addition could be to allow simple control programs to be entered, edited, saved, loaded and run. In this respect the arm could be used as a 3-D version of the program 'Crash' or 'Elephant'.

Software download

   
   
Home
   
© 2018 - 2025 flaxcottage.com