Instructions for building a complete moving skeleton
This is the Skeleton that I started with. I got it at Spencer Gifts last October for $25. From a stamp on the back shoulder blade, it appears that it was made by a company called "The Paper Magic Group" and has a date of 1998. It was made in China and is about three feet tall. I removed the top of the skull by gently prying it apart along the glue seam with an exacto knife. The wire you see sticking up out of the skull is for the LED's I added to his eyes.To see a larger version, click on the picture.The tools I used included a battery powered hand drill and various bits. A Dremel Tool and cutoff bits, wire cutters, pliers, and screwdrivers, exacto knife, and a soldering iron. All parts except the skeleton, gears, and electronics can be purchased at the hardware store and hobby shop.
The Skeleton is made of a very brittle plastic and breaks easily, but can also be easily repaired with a little putty epoxy (there are several brands, any will do)
To animate the arm, I broke it off at the movable joint (that takes guts!), then I drilled out the joint and filled it with putty epoxy (there are several brands available from most hardware stores, any will do. ). Before the epoxy hardened, I inserted a 3 to 4 inch stove bolt and positioned it correctly, then packed the putty around it. Once the epoxy had hardened (full cure in about half an hour), I threaded a small gear (T30) that I got from All Electronics (CAT# GR-5 $2.75 per set of 5) and snugged it into place with a little more epoxy and a nut.
On the body side, I filled it with epoxy and inserted another stove bolt to align the hole, but before it hardened, I removed the bolt. Once it was hard, I drilled it out a bit more and inserted a piece of brass tubing just large enough to hold the bolt. You can see the end in the picture below near the large gear.
Next I took a CIRRUS CS-60BB servo I purchased from Sheldon's Hobby for $24.99 and replacing the short center screw with a longer one from the servo parts pack, I attached a T40 gear (from the same 5 pack I got above) to the servo horn (the white piece). I drilled a small hole for an additional screw to tie the servo horn and the gear together.
When you choose a servo, there are two numbers that you want to look at. The Torque and the Speed. The shoulder requires a 60 to 100 oz/in servo, but a slower speed servo in this case is better. The servo will only move about 180 degrees. With the gears that I chose, the small gear will turn about 3/4 of a turn, giving the arm a range of over the head to behind the back which is about what a human arm will do. Since even the slowest servos will move the full 180 degrees in less than 1 1/2 seconds, a slow servo will still sling the arm around pretty fast, fast enough for a startle.
The first time I tried this, I used a faster servo and a smaller gear (a T20). The servo had plastic internal gears. The arm moved much faster, but after about an hour of use, the internal gears started breaking off.
I switched to a slower servo with metal internal gears and a T30 gear on the arm. This servo has held up much better even though the oz/in rating was about the same. As of this writing, it has over 20 hours of operation with no problems.
To attach the servo to the shoulder, with the gears in place, I mixed up another batch of epoxy putty and shaped it onto the shoulder blade and pressed the servo into it until the gears met, keeping them straight and tight. I had to hold them in place for a few minutes while the epoxy hardened. Then I added more epoxy to fill in the gaps around the edges so that I had a solid base for the servo.
Since the first servo failed, I pried it loose from the epoxy with a screwdriver and attached the new servo to the same place with some gap-filling super glue.
Next I went to work on the skull. The skeleton I chose comes with a skull that has a movable jaw. I got a piece of piano wire from the hardware store and bent it into fit along the jaw and stick up through the jaw hinge holes (I had to make the hole a bit larger with an exacto knife). You can see the wire along the back edge of the jaw in the pictures below. I drilled a small hole in the jaw and bent the piano wire to fit through it. I also bent the top of the piano wire to fit into the linkage to the servo in the skull. (see below)
When the servos turn the head and the jaw opens and closes, the jaw hits the collar bone. To reduce this problem, I added metal washers on the neck to lift the skull up a bit higher so that when the jaw opens, it will clear the collar bone. Three washers are not quite enough, but any more and the neck does not protrude into the skull enough for control.
I then covered the piano wire with putty epoxy to prevent the wire from moving in relationship to the jaw when the servo pushed or pulled the wire. This makes the jaw movement much more exact.
This is the inside of the skull. If you look hard, you can see the piano wire sticking up out of the jaw hinge near the bottom of the picture. You can also see the wiring of the LEDs for the eyes.
The putty was just some left over from the shoulder work. I knew that I would need to fill in some space for the jaw servo mount.
To connect the servo to the neck, I used a 2-liter pop bottle cap and a control horn. I hacked a hole into the top of the cap, then I glued the control horn inside the cap with some putty.
I glued the two servos that fit into the skull together with some thick super glue. The round control horn gets removed and replaced with the bottle cap I prepared above. I then cut one side of the lever control horn off. This servo controls the jaw.
Here, I am using FMA S355M servos that I got for $21.95 by mail order from FMA Direct. It took about 10 days to get them. I do not need the high 114 oz/in torque here, but the servos were handy. These would have been a good choice for the arm, but I had not received them yet.
Here are the servos mounted inside the skull. The jaw servo is connected to the jaw lever (piano wire) with a piece of square brass tube with a hole drilled in either end. When I took this picture, I had a spacer between the control horn and the brass link, but I later removed it to make things align better.
This is another view of the skull servos. Here you can see that the bottle cap is pined to the neck by drilling a hole through it and the neck and inserting a pin. The bottle cap is bigger than the neck which allows it to float. That way, even if the servo and the neck are not aligned exactly, they still work well together as the neck is free to move small amounts along the pin as the skull turns.
It is a bit hard to see since it is off white, by if this picture shows the putty that I used to form a mounting platform for the servos. I just mixed up a batch of putty, put it in place, then pushed the servo into it until it was in the right position. A few minutes later it was solid and hard.
The SYNTAX PCB board is a good quality board and is relatively inexpensive. I generally keep several around. In this case, I want to put the board inside the Skull, so I cut the board (tin snips) and will only use one corner. The two smaller pictures are the front and back of the corner I chose. After cutting the PC board, take the small piece of sandpaper that comes with the epoxy putty and sand the edges and the board will be much nicer to work with.
If you look at the board, it is arranged the same as a solder-less bread board. This allows you to lay out things on the breadboard, then transfer them directly to the PCB. In this case, the circuit is so simple, that we can just solder it up.
The circuit we are building is really quite simple. Click on the picture to see a larger version.
In the picture,
Red is the power (+5V),
Green is ground,
Brown is the RS232 signal from the controlling computer,
Blue is the servo signal.
Although they are often not shown in schematics, as always in digital circuits, we add some 0.1 µf capacitors from +5V to ground. These prevent noise from the motors inside the servos from affecting the logic.
Caution: I think that AirTronic Servos (and maybe others) reverse the ground and +5V lines on their connectors. Make sure that you check polarity.
This is the board with the parts in place, ready to be soldered. The blue and orange lines are the servo signal lines. The 3 by 5 array of pins is where you plug the servos in. The center column of 5 pins all carry +5 volts. The left 5 are all ground, and the right 5 are the 5 servo signal lines. Each servo uses three pins, ground, +5, and one of the signal pins.
The small connector in the upper left hand corner is for power (+5V) and the other connector in the left center is for the serial port (2400 bps from the PC or Macintosh).
RS232 is a -12V to +12V signal. We want logic levels (0 to +5V) so we add a diode to clip the voltage, throwing away the negative part, and we use the two resistors as a voltage divider to drop the (up to) +12V down to a max of +5V.
Here is the board at a different angle. You can see the two 0.1µf (104) capacitors better here. These caps absorb any noise from the power lines.
The back side of the board. If you have never soldered before, take a look at Harry Lythall's page on basic soldering techniques.
Now we are ready to mount the board. The side of the servo looked like a likely place, so I mixed up a tiny bit of putty epoxy and rolled it into four pea sized balls and stuck them to the side of the servo. Then I pressed the finished PC board into them.
Finally, I plugged the three servos and the LED eyes into the board. The LED's only use the power and ground pins. If I decide to add two more servos, I will add two more pins for the eyes, but for now, it is handy to just use an unused servo connector to power them.
Here you can see the routing of the servo wires to the PC board and the putty holding the PC board to the side of the neck servo.
Many thanks to D. Zouras for this module. Unfortunately, I have lost the link to his page. If anyone knows where it is, let me know.
Original author: Chuck Rice
Original URL: http://www.wildrice.com/Halloween/Construction/Skeleton/
This is the Skeleton that I started with. I got it at Spencer Gifts last October for $25. From a stamp on the back shoulder blade, it appears that it was made by a company called "The Paper Magic Group" and has a date of 1998. It was made in China and is about three feet tall. I removed the top of the skull by gently prying it apart along the glue seam with an exacto knife. The wire you see sticking up out of the skull is for the LED's I added to his eyes.To see a larger version, click on the picture.The tools I used included a battery powered hand drill and various bits. A Dremel Tool and cutoff bits, wire cutters, pliers, and screwdrivers, exacto knife, and a soldering iron. All parts except the skeleton, gears, and electronics can be purchased at the hardware store and hobby shop.
The Skeleton is made of a very brittle plastic and breaks easily, but can also be easily repaired with a little putty epoxy (there are several brands, any will do)
The Shoulder
The side view shows the gears used to move the shoulder. The small gear is attached directly to the arm. It is driven by the larger gear which is attached to the servo. The servo is connected to the skeleton with epoxy.To animate the arm, I broke it off at the movable joint (that takes guts!), then I drilled out the joint and filled it with putty epoxy (there are several brands available from most hardware stores, any will do. ). Before the epoxy hardened, I inserted a 3 to 4 inch stove bolt and positioned it correctly, then packed the putty around it. Once the epoxy had hardened (full cure in about half an hour), I threaded a small gear (T30) that I got from All Electronics (CAT# GR-5 $2.75 per set of 5) and snugged it into place with a little more epoxy and a nut.
On the body side, I filled it with epoxy and inserted another stove bolt to align the hole, but before it hardened, I removed the bolt. Once it was hard, I drilled it out a bit more and inserted a piece of brass tubing just large enough to hold the bolt. You can see the end in the picture below near the large gear.
Next I took a CIRRUS CS-60BB servo I purchased from Sheldon's Hobby for $24.99 and replacing the short center screw with a longer one from the servo parts pack, I attached a T40 gear (from the same 5 pack I got above) to the servo horn (the white piece). I drilled a small hole for an additional screw to tie the servo horn and the gear together.
When you choose a servo, there are two numbers that you want to look at. The Torque and the Speed. The shoulder requires a 60 to 100 oz/in servo, but a slower speed servo in this case is better. The servo will only move about 180 degrees. With the gears that I chose, the small gear will turn about 3/4 of a turn, giving the arm a range of over the head to behind the back which is about what a human arm will do. Since even the slowest servos will move the full 180 degrees in less than 1 1/2 seconds, a slow servo will still sling the arm around pretty fast, fast enough for a startle.
The first time I tried this, I used a faster servo and a smaller gear (a T20). The servo had plastic internal gears. The arm moved much faster, but after about an hour of use, the internal gears started breaking off.
I switched to a slower servo with metal internal gears and a T30 gear on the arm. This servo has held up much better even though the oz/in rating was about the same. As of this writing, it has over 20 hours of operation with no problems.
To attach the servo to the shoulder, with the gears in place, I mixed up another batch of epoxy putty and shaped it onto the shoulder blade and pressed the servo into it until the gears met, keeping them straight and tight. I had to hold them in place for a few minutes while the epoxy hardened. Then I added more epoxy to fill in the gaps around the edges so that I had a solid base for the servo.
Since the first servo failed, I pried it loose from the epoxy with a screwdriver and attached the new servo to the same place with some gap-filling super glue.
The Skull
Next I went to work on the skull. The skeleton I chose comes with a skull that has a movable jaw. I got a piece of piano wire from the hardware store and bent it into fit along the jaw and stick up through the jaw hinge holes (I had to make the hole a bit larger with an exacto knife). You can see the wire along the back edge of the jaw in the pictures below. I drilled a small hole in the jaw and bent the piano wire to fit through it. I also bent the top of the piano wire to fit into the linkage to the servo in the skull. (see below)
When the servos turn the head and the jaw opens and closes, the jaw hits the collar bone. To reduce this problem, I added metal washers on the neck to lift the skull up a bit higher so that when the jaw opens, it will clear the collar bone. Three washers are not quite enough, but any more and the neck does not protrude into the skull enough for control.
I then covered the piano wire with putty epoxy to prevent the wire from moving in relationship to the jaw when the servo pushed or pulled the wire. This makes the jaw movement much more exact.
This is the inside of the skull. If you look hard, you can see the piano wire sticking up out of the jaw hinge near the bottom of the picture. You can also see the wiring of the LEDs for the eyes.
The putty was just some left over from the shoulder work. I knew that I would need to fill in some space for the jaw servo mount.
To connect the servo to the neck, I used a 2-liter pop bottle cap and a control horn. I hacked a hole into the top of the cap, then I glued the control horn inside the cap with some putty.
I glued the two servos that fit into the skull together with some thick super glue. The round control horn gets removed and replaced with the bottle cap I prepared above. I then cut one side of the lever control horn off. This servo controls the jaw.
Here, I am using FMA S355M servos that I got for $21.95 by mail order from FMA Direct. It took about 10 days to get them. I do not need the high 114 oz/in torque here, but the servos were handy. These would have been a good choice for the arm, but I had not received them yet.
Here are the servos mounted inside the skull. The jaw servo is connected to the jaw lever (piano wire) with a piece of square brass tube with a hole drilled in either end. When I took this picture, I had a spacer between the control horn and the brass link, but I later removed it to make things align better.
This is another view of the skull servos. Here you can see that the bottle cap is pined to the neck by drilling a hole through it and the neck and inserting a pin. The bottle cap is bigger than the neck which allows it to float. That way, even if the servo and the neck are not aligned exactly, they still work well together as the neck is free to move small amounts along the pin as the skull turns.
It is a bit hard to see since it is off white, by if this picture shows the putty that I used to form a mounting platform for the servos. I just mixed up a batch of putty, put it in place, then pushed the servo into it until it was in the right position. A few minutes later it was solid and hard.
The Electronics
Description
|
Part Number
|
Source
|
Approx Cost
|
PC-462905
|
HSC
|
$3.95
|
|
FT639
|
FerretTronics
|
$22.95
|
|
Radio Shack
|
|||
271-1335
|
Radio Shack
|
$0.49
|
|
271-1339
|
Radio Shack
|
$0.49
|
|
276-1122
|
Radio Shack
|
$1.19
|
|
Radio Shack
|
|||
307SS40G
|
HSC
|
$0.79
|
|
Mouser
|
$20.18
|
||
???
|
Junk PC
|
$0 to $20
|
The SYNTAX PCB board is a good quality board and is relatively inexpensive. I generally keep several around. In this case, I want to put the board inside the Skull, so I cut the board (tin snips) and will only use one corner. The two smaller pictures are the front and back of the corner I chose. After cutting the PC board, take the small piece of sandpaper that comes with the epoxy putty and sand the edges and the board will be much nicer to work with.
If you look at the board, it is arranged the same as a solder-less bread board. This allows you to lay out things on the breadboard, then transfer them directly to the PCB. In this case, the circuit is so simple, that we can just solder it up.
The circuit we are building is really quite simple. Click on the picture to see a larger version.
In the picture,
Red is the power (+5V),
Green is ground,
Brown is the RS232 signal from the controlling computer,
Blue is the servo signal.
Although they are often not shown in schematics, as always in digital circuits, we add some 0.1 µf capacitors from +5V to ground. These prevent noise from the motors inside the servos from affecting the logic.
Caution: I think that AirTronic Servos (and maybe others) reverse the ground and +5V lines on their connectors. Make sure that you check polarity.
This is the board with the parts in place, ready to be soldered. The blue and orange lines are the servo signal lines. The 3 by 5 array of pins is where you plug the servos in. The center column of 5 pins all carry +5 volts. The left 5 are all ground, and the right 5 are the 5 servo signal lines. Each servo uses three pins, ground, +5, and one of the signal pins.
The small connector in the upper left hand corner is for power (+5V) and the other connector in the left center is for the serial port (2400 bps from the PC or Macintosh).
RS232 is a -12V to +12V signal. We want logic levels (0 to +5V) so we add a diode to clip the voltage, throwing away the negative part, and we use the two resistors as a voltage divider to drop the (up to) +12V down to a max of +5V.
Here is the board at a different angle. You can see the two 0.1µf (104) capacitors better here. These caps absorb any noise from the power lines.
The back side of the board. If you have never soldered before, take a look at Harry Lythall's page on basic soldering techniques.
Now we are ready to mount the board. The side of the servo looked like a likely place, so I mixed up a tiny bit of putty epoxy and rolled it into four pea sized balls and stuck them to the side of the servo. Then I pressed the finished PC board into them.
Finally, I plugged the three servos and the LED eyes into the board. The LED's only use the power and ground pins. If I decide to add two more servos, I will add two more pins for the eyes, but for now, it is handy to just use an unused servo connector to power them.
Here you can see the routing of the servo wires to the PC board and the putty holding the PC board to the side of the neck servo.
The Software
The initial RealBasic code is intended to serve as an example of how you control the animatronic. It allows you to control any of the three servos by sliding one of the three sliders in the Manual Box, or you can press one of the buttons to generate random movements.
Main Routines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | Main.Open: Sub Open() dim r as boolean dim i,rc as integer bugLog = new debugWindow bugLog.write "Surveyor Startup" appPrefs= New prefFileItem appPrefs.fileInfo= new folderItem rc=appPrefs.getText("Surveyor.prf") if rc=1 then 'create default prefs appPrefs.setCreatorType "smpl","pref" appPrefs.writeitem "Surveyor","SerialPortName",str(1) appPrefs.writeitem "Surveyor","MaxDelay",str(100) appPrefs.putText end if SerialPortName.listindex = val(appPrefs.readItem("Surveyor","SerialPortName")) MaxDelay.text = appPrefs.readItem("Surveyor","MaxDelay") 'me.top = screen(0).top + 23 'me.left = screen(0).left + 10 'me.width = 685 'me.height = 200 me.visible = true me.show me.refresh ft.servoinit(1) ft.servoinit(2) ft.servoMove(0,neck,75) ft.servoMove(0,jaw,0) ft.servoMove(0,arm,150) MoviePlayer1.play End Sub Main.SerialPortName.Open: Sub Open() dim count,i as integer dim x as string count = System.SerialPortCount if count <> 0 then for i = 0 to count-1 me.addrow System.SerialPort(i).Name next end End Sub Main.SerialPortName.Change: Sub Change() dim r as boolean dim i,rc as integer appPrefs.writeitem "Surveyor","SerialPortName",str(SerialPortName.listindex) appPrefs.putText if sp <> nil then sp.close sp = nil end if thePort.SerialPort = System.SerialPort(SerialPortName.listindex) r = thePort.open sp = thePort if r then bugLog.write System.SerialPort(SerialPortName.listindex).name + " opened ------------*" ft = new FerretTronics(sp) me.refresh else msgbox "Could not open Serial Port" //quit end if End Sub Main.JawSlider.ValueChanged: Sub ValueChanged() ft.servoMove(0,jaw,me.Value) End Sub Main.HeadTurn.ValueChanged: Sub ValueChanged() ft.servoMove(0,neck,me.Value) End Sub Main.RunSkel1Head.Action: Sub Action() ft.servoinit(1) ft.servoMove(1,neck,75) ft.servoMove(1,jaw,0) if SkeletonThread = nil then bugLog.write me.name + " started" SkeletonThread = new SkeletonThreadClass SkeletonThread.run me.caption = "Stop" else SkeletonThread.notDone = false SkeletonThread = nil bugLog.write me.name + " stopped" me.caption = "Run" end if End Sub Main.MaxDelay.KeyDown: Function KeyDown(Key As String) As Boolean if val(me.text) > 6000 then beep me.text = "6000" end 'appPrefs.writeitem "Surveyor","MaxDelay",me.text 'appPrefs.putText End Function Main.ArmSlider.ValueChanged: Sub ValueChanged() ft.servoMove(1,arm,me.Value) End Sub Main.RunSkel1Arm.Action: Sub Action() ft.servoinit(1) ft.servoMove(1,arm,150) if Skel1RightArmThread = nil then bugLog.write me.name + " started" Skel1RightArmThread = new Skel1RightArmClass Skel1RightArmThread.run me.caption = "Stop" else Skel1RightArmThread.notDone = false Skel1RightArmThread = nil bugLog.write me.name + " stopped" me.caption = "Run" end if End Sub Main.MoviePlayer1.Open: Sub Open() dim f as folderItem f=New FolderItem f=GetFolderItem("Cauldron.mov") MoviePlayer1.movie=f.OpenAsMovie MoviePlayer1.play End Sub |
FerretTronics Subroutines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | FerretTronics.FerretTronics: Sub FerretTronics(serialPort as serial) '--------------------------------------------------------------- 'Constructor - Inits the FerretTronics Class '--------------------------------------------------------------- dim r as boolean dim i as integer cCHIPSELECT = 239 cACTIVE = 117 cLONGPULSE = 90 cSHORTPULSE = 85 cHEADER = 96 cSETUP = 122 '---------------------------------------------------------------------- sp = serialPort bugLog.write "FerretTronics Object Initialized - Copyright 1999, FerretTronics Inc." End Sub FerretTronics.servoMove: Sub servoMove(chip as integer,servo as integer, position as integer) '------------------------------------------------------------------ 'sends the bytes required to move a servo (FT639) to a new position '------------------------------------------------------------------ DIM uV as integer DIM lV as integer me.routeChipSelect(chip) uV = position / 16 lV = position - (uV * 16) uV = uV + 128 + (servo - 1) * 16 lV = lV + (servo - 1) * 16 sp.write chr(lV) + chr(uV) 'waitTicks(10) bugLog.write "Moving Servo " + str(servo) + " to " + str(position) End Sub FerretTronics.routeChipSelect: Sub routeChipSelect(chip as integer) '--------------------------------------------------------------- 'Sends a chip select signal to the FT649 to select one of five 'attached FT609 or FT639 chips '--------------------------------------------------------------- dim xchip as integer xchip = chip 'copy so we can modify it if (xchip < 0) or (xchip > 5) then msgbox "The selected chip (" + str(chip) + ") is out of range (0 to 5)" xchip = 0 beep end if if xchip <> 0 then sp.write chr(cCHIPSELECT+xchip) buglog.write "Chip " + str(xchip) + " selected" end if End Sub FerretTronics.servoLongPulse: Sub servoLongPulse() '--------------------------------------------------------------- 'Sets FT639 Longpules mode '--------------------------------------------------------------- sp.write chr(cSETUP) + chr(cLONGPULSE) + chr(cACTIVE) End Sub FerretTronics.servoShortPluse: Sub servoShortPluse() '--------------------------------------------------------------- 'Sets FT639 ShortPulse mode '--------------------------------------------------------------- sp.write chr(cSETUP) + chr(cSHORTPULSE) + chr(cACTIVE) End Sub FerretTronics.servoSetHeader: Sub servoSetHeader(head as integer) '--------------------------------------------------------------- 'Sets FT639 Header value '--------------------------------------------------------------- sp.write chr(cSETUP) + chr(cHEADER+head) + chr(cACTIVE) End Sub FerretTronics.servoInit: Sub servoInit(chip as integer) '--------------------------------------------------------------- 'Sets FT639 chip to a known state '--------------------------------------------------------------- me.routeChipSelect(chip) me.servoLongPulse me.servoSetHeader(4) bugLog.write "Initialization commands sent to Servo " + str(chip) End Sub FerretTronics.waitTicks: Sub waitTicks(delayticks as double) dim targetTick as double targetTick = Ticks + delayTicks while targetTick > Ticks wend End Sub FerretTronics.DataAvailable: Sub DataAvailable() '--------------------------------------------------------------- 'Reads incoming data from the FT629 and stores the switch states 'array. To access, use ft.switch(n) '--------------------------------------------------------------- dim n,i as integer dim buffer as string beep buffer = sp.readAll n = len(buffer) while n > 0 for i = 0 to 4 'Check each of the five switch values if bitwiseAnd(asc(mid(buffer,n,1)),pow(2,i) ) <> 0 then switch(i) = true 'Switch is on else switch(i) = false 'Switch is off end if next n = n - 1 wend End Sub |
Skeleton Thread
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | SkeletonThreadClass.Run: Sub Run() dim i,r,r2 as integer dim arm,narm as integer me.notDone = true while me.notDone ft.servoinit(1) r = (rnd*val(main.MaxDelay.text))+1 bugLog.write "delay " + str(r) ft.waitTicks r if me.notDone and (rnd>.50) Then bugLog.write "Left Head to center" r = (rnd*30)+1 for i = 25 to 90 step r ft.servoMove(0,neck,i) 'ft.waitTicks 1 next end if if me.notDone and (rnd>.60) Then bugLog.write "Talk" r = (rnd*5)+1 for i = 1 to r r2 = (rnd*20)+20 ft.waitTicks (r2/3) ft.servoMove(0,jaw,r2) ft.waitTicks (r2/3) ft.servoMove(0,jaw,0) 'ft.waitTicks 30 'ft.servoMove(0,jaw,r2) 'ft.waitTicks (r2/3) 'ft.servoMove(0,jaw,0) next end if if me.notDone and (rnd>.50) Then bugLog.write "Center Head to right" r = (rnd*30)+1 for i = 90 to 170 step r ft.servoMove(0,neck,i) 'ft.waitTicks 1 next end if if me.notDone and (rnd>.50) Then bugLog.write "Right Head to Left" r = (rnd*30)+1 for i = 170 downto 25 step r ft.servoMove(0,neck,i) 'ft.waitTicks 1 next end if wend ft.servoMove(0,neck,75) ft.servoMove(0,jaw,1) End Sub |
Skel1RightArmClass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | Skel1RightArmClass.Run: Sub Run() dim i,r,r2 as integer dim armP,narm,armstep as integer dim b as string me.notDone = true b = " " for i = 1 to 8 b = b+b next ft.servoinit(1) armP = 75 ft.servoMove(0,arm,armP) while me.notDone r = (rnd*val(main.MaxDelay.text))+1 ft.waitTicks r if me.notDone and (rnd>.10) Then 'bugLog.write "Arm" r = (rnd*20)+40 r2 = (rnd*4)+1.1 r2 = r2 - 2.5 if rnd>.9 then narm = 90 else narm = armP + (r2*r) end if if narm > 200 then narm = 200 end if if narm < 0 then narm = 0 end if armstep = rnd*5 +1 While armP > narm armP = armP-armstep ft.servoMove(0,arm,armP) bugLog.write "Arm " +str(armP) + " " + str(r2) + Right(b +"*",armP/5) wend While armP < narm armP = armP+armstep ft.servoMove(0,arm,armP) bugLog.write "Arm " +str(armP) + " " + str(r2) + Right(b +"*",armP/5) wend end if wend ft.servoMove(0,arm,75) End Sub |
Preferences Subroutines
Many thanks to D. Zouras for this module. Unfortunately, I have lost the link to his page. If anyone knows where it is, let me know.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | prefFileItem.writeItem: Sub writeItem(sectionName as string, itemName as string, itemValue as string) 'this sub will either update the value of itemName with itemValue if it exists 'or it will create itemName and assign itemValue to it if it doesn't exist 'if the sectionName does not exist, that will be created also dim temp, itemText as string dim sectionHeading,itemLabel as String dim sectionPos,nextSectionPos,itemPos,itemEndPos as integer dim headingLen,itemsLen,labelLen as integer dim beforeItem, afterItem as string temp=me.fileText sectionHeading="["+sectionName+"]" headingLen=len(sectionHeading)+1 'add 1 for return at end of line itemLabel=itemName+"=" labelLen=len(itemLabel) sectionPos=instr(temp,sectionHeading) if sectionPos>0 then nextSectionPos=instr(sectionPos+headingLen,temp,"[") if nextSectionPos<>0 then itemsLen=nextSectionPos-(sectionPos+headingLen) itemText=mid(temp,sectionPos+headingLen,itemsLen) itemPos=instr(itemText,itemLabel) itemEndPos=instr(itemPos,itemText,CHR(13)) else 'no next section itemText=mid(temp,sectionPos+headingLen) itemPos=instr(itemText,itemLabel) 'itemEndPos=len(itemText)+1 itemEndPos=instr(itemPos,itemText,CHR(13)) end if if itemPos>0 then 'exists 'breaking item string apart to insert itemValue beforeItem=mid(itemText,1,itemPos+labelLen-1) afterItem=mid(itemText,itemEndPos) itemText=beforeItem+itemValue+afterItem else 'item does not exist itemText=itemText+itemName+"="+itemValue+CHR(13) end if 'breaking entire prefs string apart to reinsert the updated itemText beforeItem=mid(temp,1,sectionPos+headingLen-1) if nextSectionPos=0 then afterItem="" else afterItem=mid(temp,nextSectionPos) end if temp=beforeItem+itemText+afterItem me.fileText=temp else 'section not found me.fileText=me.fileText+CHR(13)+sectionHeading+CHR(13)+itemName+"="+itemValue+CHR(13) 'add section & item end if me.saved=false End Sub prefFileItem.readItem: Function readItem(sectionName as string, itemName as string) As String 'returns value for itemName if found, else returns null dim temp, itemText as string dim itemValue As String dim sectionHeading,itemLabel as String dim sectionPos,nextSectionPos,itemPos,itemEndPos as integer dim headingLen,itemsLen,labelLen as integer temp=me.fileText sectionHeading="["+sectionName+"]" headingLen=len(sectionHeading)+1 'add 1 for return at end of line itemLabel=itemName+"=" labelLen=len(itemLabel) sectionPos=instr(temp,sectionHeading) if sectionPos>0 then nextSectionPos=instr(sectionPos+headingLen,temp,"[") if nextSectionPos<>0 then itemsLen=nextSectionPos-(sectionPos+headingLen) itemText=mid(temp,sectionPos+headingLen,itemsLen) itemPos=instr(itemText,itemLabel) itemEndPos=instr(itemPos,itemText,CHR(13)) else 'no next section itemText=mid(temp,sectionPos+headingLen) itemPos=instr(itemText,itemLabel) 'itemEndPos=len(itemText)+1 itemEndPos=instr(itemPos,itemText,CHR(13)) end if if itemPos>0 then 'exists ItemValue=mid(itemText,itemPos+labelLen,itemEndPos-(itemPos+labelLen)) else 'no item to read itemValue="" end if else 'section not found itemValue="" end if return itemValue End Function prefFileItem.deleteItem: Sub deleteItem(sectionName as string, itemName as string) 'deletes itemName and its itemValue if it exists dim temp, itemText as string dim sectionHeading,itemLabel as String dim sectionPos,nextSectionPos,itemPos,itemEndPos as integer dim headingLen,itemsLen,labelLen as integer dim beforeItem, afterItem as string temp=me.fileText sectionHeading="["+sectionName+"]" headingLen=len(sectionHeading)+1 'add 1 for return at end of line itemLabel=itemName+"=" labelLen=len(itemLabel) sectionPos=instr(temp,sectionHeading) if sectionPos>0 then nextSectionPos=instr(sectionPos+headingLen,temp,"[") if nextSectionPos<>0 then itemsLen=nextSectionPos-(sectionPos+headingLen) itemText=mid(temp,sectionPos+headingLen,itemsLen) itemPos=instr(itemText,itemLabel) itemEndPos=instr(itemPos,itemText,CHR(13)) else 'no next section itemText=mid(temp,sectionPos+headingLen) itemPos=instr(itemText,itemLabel) 'itemEndPos=len(itemText)+1 itemEndPos=instr(itemPos,itemText,CHR(13)) end if if itemPos>0 then 'exists 'breaking item string apart to delete item beforeItem=mid(itemText,1,itemPos-1) afterItem=mid(itemText,itemEndPos+1) itemText=beforeItem+afterItem else 'item does not exist 'do nothing end if 'breaking entire prefs string apart to reinsert the updated itemText beforeItem=mid(temp,1,sectionPos+headingLen-1) if nextSectionPos=0 then afterItem="" else afterItem=mid(temp,nextSectionPos) end if temp=beforeItem+itemText+afterItem me.fileText=temp else 'section not found 'do nothing, can't find item in nonexistent section end if me.saved=false End Sub prefFileItem.deleteSection: Sub deleteSection(sectionName as string) 'deletes the entire section and related items under sectionName dim temp, itemText as string dim sectionHeading,itemLabel as String dim sectionPos,nextSectionPos as integer dim headingLen,itemsLen as integer dim beforeItem, afterItem as string temp=me.fileText sectionHeading="["+sectionName+"]" headingLen=len(sectionHeading)+1 'add 1 for return at end of line sectionPos=instr(temp,sectionHeading) if sectionPos>0 then nextSectionPos=instr(sectionPos+headingLen,temp,"[") if nextSectionPos<>0 then itemsLen=nextSectionPos-(sectionPos+headingLen) itemText=mid(temp,sectionPos+headingLen,itemsLen) else 'no next section itemText=mid(temp,sectionPos+headingLen) end if 'breaking entire prefs string apart to delete the itemText if nextSectionPos=0 then beforeItem=mid(temp,1,sectionPos-2) afterItem="" msgBox itemText else beforeItem=mid(temp,1,sectionPos-1) afterItem=mid(temp,nextSectionPos) end if temp=beforeItem+afterItem me.fileText=temp else 'section not found 'nothing to delete end if me.saved=false End Sub prefFileItem.clear: Sub clear() 'reset the fileText property 'still need to putText if you want to clear the file on disk me.fileText="This file created with Pref Maker class. ©D. Zouras 1998"+CHR(13) me.saved=false End Sub prefFileItem.getText: Function getText(prefFile as string) As integer 'reads the folderItem with name prefFile in the systemFolder:PreferencesFolder '0=success 1=file did not exist, created blank dim inStream As TextInputStream dim outStream as textoutputstream dim prefFolder as folderitem dim rc as integer prefFolder=preferencesFolder //assign the path me.fileInfo= getfolderItem(prefFolder.absolutepath+prefFile) //see if we need to create a new prefs file or not if me.fileInfo.exists then inStream=me.fileInfo.OpenAsTextFile me.fileText=inStream.readAll me.fileText=mid(me.fileText,1,len(me.fileText)-1) inStream.close rc=0 else 'create new pref file me.fileText="This file created with Pref Maker class. ©D. Zouras 1998"+CHR(13) outStream=me.fileInfo.CreateTextFile outStream.WriteLine me.fileText outStream.Close rc=1 end me.saved=true return rc End Function prefFileItem.putText: Sub putText() 'writes the text in the fileText property to the folderItem of this object dim outStream As TextOutputStream dim type,creator as string creator=me.fileInfo.MacCreator type=me.fileInfo.MacType outStream=me.fileInfo.CreateTextFile outStream.WriteLine me.fileText outStream.Close setCreatorType creator,type me.saved=true 'just wrote to disk End Sub prefFileItem.setCreatorType: Sub setCreatorType(creator as string,type as string) 'set the creator and type for the prefFile object 'if a parameter is not 4 chars long then no change will be made 'to it, but the other is independently tested if len(creator)=4 then me.fileInfo.MacCreator=creator end if if len(type)=4 then me.fileInfo.MacType=type end if End Sub |
Original author: Chuck Rice
Original URL: http://www.wildrice.com/Halloween/Construction/Skeleton/