Boe-Bot Troubles and Questions
I currently have a project for my class that requires me to build the boe-bot, it has navigate through a course using a predetermined path. I insereted the exact code below which is straight out of the handbook (Chapter 4 EEPROM Navigation). When I try to run the code onto my bot it sends an error message stating that the constant exceeds 16 bits, while highlighting the 01234567 in the EEPROM data. Does anyone know how to fix this? Im using the BS2 model and version 2.5.
' Robotics with the Boe-Bot - EepromNavigation.bs2q
' Navigate using charachters stored in EEPROM.
' {$STAMP BS2}
' {$PBASIC 2.5}
' {$PORT COM3}
DEBUG "Program Running!"
pulseCount VAR Word
address VAR Byte
instruction VAR Byte
Address: 0123456789
||||||||||
DATA "FLFFRBLBBQ"
FREQOUT 4, 2000, 3000
DO UNTIL (instruction = "Q")
READ address, instruction
address = address + 1
SELECT instruction
CASE "F": GOSUB Forward
CASE "B": GOSUB Backward
CASE "L": GOSUB Left_Turn
CASE "R": GOSUB Right_Turn
ENDSELECT
LOOP
END
Forward:
FOR pulseCount = 1 TO 64
PULSOUT 13, 850
PULSOUT 12, 650
PAUSE 20
NEXT
RETURN
Backward:
FOR pulseCount = 1 TO 64
PULSOUT 13, 650
PULSOUT 12, 850
PAUSE 20
NEXT
RETURN
Left_Turn:
FOR pulseCount = 1 TO 24
PULSOUT 13, 650
PULSOUT 12, 650
PAUSE 20
NEXT
RETURN
Right_Turn:
FOR pulseCount = 1 TO 24
PULSOUT 13, 850
PULSOUT 12, 850
PAUSE 20
NEXT
RETURN
Comments
Evan_Petersen,
You code is Chapter 4, Activity #6 except for the comments.
The line with Address and the Vertical Pipes (|) are comments so there should be an apostrophe (') in front of them, just like the first few lines of the program.
Comments are ignored but since the apostrophes are missing, the editor thinks that it should be using that huge number so you get an error.
You can copy and paste the programs from the PDF.
https://www.parallax.com/package/robotics-with-the-boe-bot-kit-downloads/
Thank you very much, I had no clue there were pdf files for them.
I have another problem if anyone could help...
So I have finsihed the eeprom navigation code to the specifications needed for my maze (listed below). My next objective is to add the whiskers to it. When the whiskers make contact i want the bot to pause and then turn slowly the opposite way until the whisker istn making contact anymore. So in otherwords if the Right whisker is triggered then the right wheel will go forward and the left wheel will go backwards and the opposite if the left whisker is triggered. When no whiskers are triggered i want it to continue on with program ive created. Ive been trying to use the roaming with whiskers file but i cant figure out how to have it return to the eeprom code. Roaming with whiskers is also provided below under the maze code.
______MAZE CODE_______ ' {$PORT COM3} ' {$PBASIC 2.5} ' Navigate using characters stored in EEPROM. ' {$STAMP BS2} ' Stamp directive. DEBUG "Program Running!" ' -----[ Variables ]---------------------------------------------------------- pulseCount VAR Word ' Stores number of pulses. address VAR Byte ' Stores EEPROM address. instruction VAR Byte ' Stores EEPROM instruction. ' -----[ EEPROM Data ]-------------------------------------------------------- ' Address: 0123456789 ' These two comm ented lines show ' |||||||||| ' EEPROM address of each datum. DATA "FRGRJLDLKLPLUQ" ' Navigation instructions. ' -----[ Initialization ]----------------------------------------------------- ' -----[ Main Routine ]------------------------------------------------------- DO UNTIL (instruction = "Q") READ address, instruction ' Data at address in instruction. address = address + 1 ' Add 1 to address for next read. SELECT instruction ' Call a different subroutine CASE "F": GOSUB Forward ' for each possible character 'CASE "B": GOSUB Backward ' that can be fetched from CASE "L": GOSUB Left_Turn ' EEPROM. CASE "R": GOSUB Right_Turn CASE "G": GOSUB Forwards CASE "J": GOSUB Forwardss CASE "D": GOSUB Forwardsss CASE "K": GOSUB Forwardssss CASE "P": GOSUB Forwardsssss CASE "U": GOSUB Forwardssssss ENDSELECT LOOP END ' Stop executing until reset. ' -----[ Subroutine - All Forwards ]----------------------------------------------- Forward: ' Forward subroutine. FOR pulseCount = 1 TO 270 ' Send 64 forward pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. Forwards: ' Forward subroutine. FOR pulseCount = 1 TO 130 ' Send 64 forward pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. Forwardss: ' Forward subroutine FOR pulseCount = 1 TO 258 ' Send 64 forward pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. Forwardsss: ' Forward subroutine. FOR pulseCount = 1 TO 103 ' Send 64 forward pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. Forwardssss: ' Forward subroutine. FOR pulseCount = 1 TO 390 ' Send 64 forward pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. Forwardsssss: ' Forward subroutine. FOR pulseCount = 1 TO 240 ' Send 64 forward pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. Forwardssssss: ' Forward subroutine. FOR pulseCount = 1 TO 384 ' Send 64 forward pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. ' -----[ Subroutine - Backward ]---------------------------------------------- Backward: ' Backward subroutine. FOR pulseCount = 1 TO 64 ' Send 64 backward pulses. PULSOUT 13, 650 ' 1.3 ms pulse to left servo. PULSOUT 12, 850 ' 1.7 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. ' -----[ Subroutine - Left_Turn ]--------------------------------------------- Left_Turn: ' Left turn subroutine. FOR pulseCount = 1 TO 29 ' Send 24 left rotate pulses. PULSOUT 13, 650 ' 1.3 ms pulse to left servo. PULSOUT 12, 680 ' 1.3 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine loop. ' -----[ Subroutine – Right_Turn ]-------------------------------------------- Right_Turn: ' right turn subroutine. FOR pulseCount = 1 TO 26 ' Send 24 right rotate pulses. PULSOUT 13, 850 ' 1.7 ms pulse to left servo. PULSOUT 12, 820 ' 1.7 ms pulse to right servo. PAUSE 20 ' Pause for 20 ms. NEXT RETURN ' Return to Main Routine section. _________Romaing With Whisker________________ ' {$STAMP BS2} ' {$PBASIC 2.5} ' {$PORT COM3} DEBUG "Program Running!" pulseCount VAR Byte FREQOUT 4, 2000, 3000 DO IF (IN5 = 0) AND (IN7 = 0) THEN GOSUB Back_UP GOSUB Turn_Left GOSUB Turn_Left ELSEIF (IN5 = 0) THEN GOSUB Back_Up GOSUB Turn_Right ELSEIF (IN7 = 0) THEN GOSUB Back_Up GOSUB Turn_Left ELSE GOSUB Forward_Pulse ENDIF LOOP Forward_Pulse: PULSOUT 13, 850 PULSOUT 12, 650 PAUSE 20 RETURN Turn_Left: FOR pulseCount = 0 TO 20 PULSOUT 13, 650 PULSOUT 12, 650 PAUSE 20 NEXT RETURN Turn_Right: FOR pulseCount = 0 TO 20 PULSOUT 13, 850 PULSOUT 12, 850 PAUSE 20 NEXT RETURN Back_Up: FOR pulseCount = 0 TO 40 PULSOUT 13, 650 PULSOUT 12, 850 PAUSE 20 NEXT RETURN
That's somewhat challenging with a BS2, which has neither hardware or software interrupts. Otherwise you would "simply" run your maze program until a whisker triggered an interrupt, when you would jump to the whiskers subroutine, which could return to your maze code when its done.
One possible method is to send enough servo pulses to move an inch or so at a time, then check the whiskers and repeat. No need to stop really, the whisker check is likely so fast that you won't even see the bot slow down, it will coast for a fraction of a second during the check then keep going.
One problem I foresee with your plan is that the whiskers subroutine will move your robot in random ways to get away from a wall, so when you return to your maze map you are likely headed in a different direction than before you hit the wall. After just one whisker trigger & routine, your robot is off course and it gets worse with each subsequent whisker trigger.
Have you considered modifying your whiskers to let you follow a wall?
HI, this is the same person i just got locked out of my account and I took what you said I have changed the idea. Thank you very much for the advice!!
I'm now working on a code that a professor has given me, using this code 5 IR sensors are used to detect the front, Front left and right, and sides left and right. I have the design down but I do have some questions on the code that my professor was unable to clear up with me. There are a few lines like this ( IF irDetectCenter = 0 THEN cent ) i get the that ir is detecting something causing a 0 but what on earth does cent mean? it says its not defined when i try to run the code but i dont know how to define it. Again, thank you for any help that you could provide:)
irDetectLeft VAR Bit 'Variable for left irDetectCenter VAR Bit 'Variable for center irDetectRight VAR Bit 'Variable for right irDetectLSide VAR Bit 'Variable for left side irDetectRSide VAR Bit 'Variable for right side irDetectLSideFar VAR Bit 'Variable for left side low resistance irDetectRSideFar VAR Bit 'Variable for right side low resistance mLoop VAR Word Lmotor PIN 15 'The left motor is connected to pin 14, pulses go through here Rmotor PIN 14 'right = 15 'speeds are -> 650-750-850 LFast CON 850 'Conastant for left motor at full speed RFast CON 650 'Conastant for right motor at full speed LStop CON 750 'Conastant for left motor at full speed RStop CON 650 'Conastant for right motor at full speed LMid CON 830 'Conastant for left motor at medium speed RMid CON 700 'Conastant for right motor at medium speed LSlow CON 770 'Conastant for left motor at minimum speed RSlow CON 730 'Conastant for right motor at minimum speed LRev CON 650 'Conastant for left motor at full speed in reverse RRev CON 850 'Conastant for left motor at full speed in reverse FREQOUT 7, 1, 38500 'left side irDetectLeft = IN8 FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 FREQOUT 3, 1, 38500 'right side irDetectRight = IN2 FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 1, 1, 38500 'right Close irDetectRSide = IN0 FREQOUT 9, 1, 38500 'left side far irDetectLSideFar = IN11 FREQOUT 4, 1, 38500 'right side far irDetectRSideFar = IN0 IF irDetectLSide = 0 AND irDetectRSide = 0 THEN main 'START COMMAND wave your hands past the two side detectors to start program Main: PAUSE 1000 DO PULSOUT Lmotor, LFast 'left motor runs on full speed PULSOUT Rmotor, RFast 'Right motor runs on full speed FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 1, 1, 38500 'right side irDetectRSide = IN0 IF irDetectLSide = 0 AND irDetectRSide = 1 THEN DO PULSOUT Lmotor, LFast FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 IF irDetectCenter = 0 THEN cent FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 3, 1, 38500 'right side irDetectRight = IN2 LOOP UNTIL irDetectLSide = 1 OR irDetectRSide = 0 ELSEIF irDetectLSide = 1 AND irDetectRSide = 0 THEN DO PULSOUT Rmotor, RFast FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 IF irDetectCenter = 0 THEN cent FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 3, 1, 38500 'right side irDetectRight = IN2 LOOP UNTIL irDetectLSide = 0 OR irDetectRSide = 1 ' ENDIF IF irDetectCenter = 0 THEN 'START FREQOUT 7, 1, 38500 'left side irDetectLeft = IN8 FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 FREQOUT 3, 1, 38500 irDetectRight = IN2 PAUSE 1000 'pause to show signal detected IF (irDetectLeft = 1 AND irDetectRight = 0) THEN ' evaluate duration GOSUB turnLeft ELSEIF (irDetectLeft = 0 AND irDetectRight = 1) THEN GOSUB turnRight ELSEIF (irDetectLeft = 1 AND irDetectRight = 1) THEN GOSUB turnDecide ELSE GOSUB turnReverse ENDIF ENDIF LOOP 'END END turnLeft: DO PULSOUT Lmotor, LRev FREQOUT 8, 1, 38500 irDetectLeft = IN9 FREQOUT 5, 1, 38500 irDetectCenter = IN4 FREQOUT 2, 1, 38500 irDetectRight = IN0 LOOP UNTIL IN0 = 1 RETURN turnRight: DO PULSOUT Rmotor, RRev FREQOUT 8, 1, 38500 irDetectLeft = IN9 FREQOUT 5, 1, 38500 irDetectCenter = IN4 FREQOUT 2, 1, 38500 irDetectRight = IN0 LOOP UNTIL IN9 = 1 RETURN turnReverse: FOR mLoop = 0 TO 50 PULSOUT Rmotor, RRev PULSOUT Lmotor, LRev PAUSE 20 PULSOUT Lmotor, LRev PAUSE 20 NEXT DO PULSOUT Rmotor, RRev FREQOUT 8, 1, 38500 irDetectLeft = IN9 FREQOUT 5, 1, 38500 irDetectCenter = IN4 FREQOUT 2, 1, 38500 irDetectRight = IN0 LOOP UNTIL IN9 = 1 RETURN turnDecide: 'uses lower resistance to see further FREQOUT 9, 1, 38500 irDetectLSideFar = IN11 FREQOUT 4, 1, 38500 'right side irDetectRSideFar = IN0 IF (irDetectLSideFar = 1 AND irDetectRSideFar = 0) THEN ' evaluate duration GOSUB turnLeft ELSEIF (irDetectLSideFar = 0 AND irDetectRSideFar = 1) THEN GOSUB turnRight ELSEIF (irDetectLSideFar = 1 AND irDetectRSideFar = 1) THEN GOSUB turnLeft ELSE GOSUB turnReverse ENDIF RETURN
ModEdit: code tags added
BTW what causes the cent to be a problem is when I take the apostrophe away from the endif statement in the middle of the Main code. As seen in the code above it has an apostrophe, i meant to take that out. This ENDIF statement is needed for the LOOP
If you can post yor complte code using the code tag...
CR
Here is my file on the basic stamp editor, im having problems copying the code with code tag.
BS2 file even better.
Peter167,
These are useful references.
https://www.parallax.com/go/PBASICHelp/Content/LanguageTopics/Reference/ElementsStyle.htm
https://www.parallax.com/package/basic-stamp-manual/
Your code is cluttered and hard to read.
' {$STAMP BS2} ' {$PBASIC 2.5} ' {$PORT COM3} irDetectLeft VAR Bit 'Variable for left irDetectCenter VAR Bit 'Variable for center irDetectRight VAR Bit 'Variable for right irDetectLSide VAR Bit 'Variable for left side irDetectRSide VAR Bit 'Variable for right side irDetectLSideFar VAR Bit 'Variable for left side low resistance irDetectRSideFar VAR Bit 'Variable for right side low resistance mLoop VAR Word Lmotor PIN 15 'The left motor is connected to pin 14, pulses go through here Rmotor PIN 14 'right = 15 'speeds are -> 650-750-850 LFast CON 850 'Conastant for left motor at full speed RFast CON 650 'Conastant for right motor at full speed LStop CON 750 'Conastant for left motor at full speed RStop CON 650 'Conastant for right motor at full speed LMid CON 830 'Conastant for left motor at medium speed RMid CON 700 'Conastant for right motor at medium speed LSlow CON 770 'Conastant for left motor at minimum speed RSlow CON 730 'Conastant for right motor at minimum speed LRev CON 650 'Conastant for left motor at full speed in reverse RRev CON 850 'Conastant for left motor at full speed in reverse FREQOUT 7, 1, 38500 'left side irDetectLeft = IN8 FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 FREQOUT 3, 1, 38500 'right side irDetectRight = IN2 FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 1, 1, 38500 'right Close irDetectRSide = IN0 FREQOUT 9, 1, 38500 'left side far irDetectLSideFar = IN11 FREQOUT 4, 1, 38500 'right side far irDetectRSideFar = IN0 IF (irDetectLSide = 0 AND irDetectRSide = 0) THEN main 'START COMMAND wave your hands past the two side detectors to start program Main: PAUSE 1000 DO PULSOUT Lmotor, LFast 'left motor runs on full speed PULSOUT Rmotor, RFast 'Right motor runs on full speed FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 1, 1, 38500 'right side irDetectRSide = IN0 IF (irDetectLSide = 0 AND irDetectRSide = 1) THEN DO PULSOUT Lmotor, LFast FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 IF (irDetectCenter = 0) THEN cent ' <--- ??? FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 3, 1, 38500 'right side irDetectRight = IN2 LOOP UNTIL (irDetectLSide = 1 OR irDetectRSide = 0) ELSEIF (irDetectLSide = 1 AND irDetectRSide = 0) THEN DO PULSOUT Rmotor, RFast FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 IF (irDetectCenter = 0) THEN cent ' <--- ??? FREQOUT 10, 1, 38500 'Left Close irDetectLSide = IN11 FREQOUT 3, 1, 38500 'right side irDetectRight = IN2 LOOP UNTIL (irDetectLSide = 0 OR irDetectRSide = 1) ' ENDIF ' <--- Why? IF irDetectCenter = 0 THEN 'START FREQOUT 7, 1, 38500 'left side irDetectLeft = IN8 FREQOUT 6, 1, 38500 'center irDetectCenter = IN5 FREQOUT 3, 1, 38500 irDetectRight = IN2 PAUSE 1000 'pause to show signal detected IF (irDetectLeft = 1 AND irDetectRight = 0) THEN ' evaluate duration GOSUB turnLeft ELSEIF (irDetectLeft = 0 AND irDetectRight = 1) THEN GOSUB turnRight ELSEIF (irDetectLeft = 1 AND irDetectRight = 1) THEN GOSUB turnDecide ELSE GOSUB turnReverse ENDIF ENDIF LOOP 'END END turnLeft: DO PULSOUT Lmotor, LRev FREQOUT 8, 1, 38500 irDetectLeft = IN9 FREQOUT 5, 1, 38500 irDetectCenter = IN4 FREQOUT 2, 1, 38500 irDetectRight = IN0 LOOP UNTIL IN0 = 1 RETURN turnRight: DO PULSOUT Rmotor, RRev FREQOUT 8, 1, 38500 irDetectLeft = IN9 FREQOUT 5, 1, 38500 irDetectCenter = IN4 FREQOUT 2, 1, 38500 irDetectRight = IN0 LOOP UNTIL IN9 = 1 RETURN turnReverse: FOR mLoop = 0 TO 50 PULSOUT Rmotor, RRev PULSOUT Lmotor, LRev PAUSE 20 PULSOUT Lmotor, LRev PAUSE 20 NEXT DO PULSOUT Rmotor, RRev FREQOUT 8, 1, 38500 irDetectLeft = IN9 FREQOUT 5, 1, 38500 irDetectCenter = IN4 FREQOUT 2, 1, 38500 irDetectRight = IN0 LOOP UNTIL IN9 = 1 RETURN turnDecide: 'uses lower resistance to see further FREQOUT 9, 1, 38500 irDetectLSideFar = IN11 FREQOUT 4, 1, 38500 'right side irDetectRSideFar = IN0 IF (irDetectLSideFar = 1 AND irDetectRSideFar = 0) THEN ' evaluate duration GOSUB turnLeft ELSEIF (irDetectLSideFar = 0 AND irDetectRSideFar = 1) THEN GOSUB turnRight ELSEIF (irDetectLSideFar = 1 AND irDetectRSideFar = 1) THEN GOSUB turnLeft ELSE GOSUB turnReverse ENDIF RETURN
Chapter 7 of Robotics with the BOE-Bot is on Infrared Object Detection.
A LOW or 0 means that an object IS detected, and a HIGH or 1 means that NO object was detected.
Your mystery line means that when the Center IR detector sees something it should... we don't know.
Is this all you were given?
Yes, this was all that I was given to me. Im trying to get it so it can guide its way through a maze using the infrared detectors for a little show for incoming students.
for reference here is the circuit design,
Peter167,
The program and the diagram have some differences.
The diagram has P4 as the Front Right transmitter, and P2 as the Far Right Side transmitter.
Front Right should be P4 and P3, but the program uses P3 and P2.
Far Right side uses P2 but is P4 in the program.
The 1st IF...THEN...ELSEIF looks for irDetectRSide, but uses the Front Right for detection.
Which IR directions are TurnLeft, TurnRight, and TurnReverse supposed to use?
I once again have changed to project a bit to combine some of an old code that I had using specific distances with the addition of using two IR sensors on the left and right side to slow down the wheels when it comes to close to a wall to keep it from running into any sidewalls. I'm currently just trying to figure out how I can have the frequency scanning while the Boebot is traveling on its specific. As shown in the BS2 file I'm trying to make X = 1 to that it can run while looping so when X = 1 the frequency sweep is active so it would be running the entire time, although I'm trying this currently it's not working how I want it to.
I Think I figured out my previous problem but i am now stuck with it saying that my Data occupies the same location as my program..... any help here?
does this basically mean that I have too much for it to hold? I can try to shorten/combine some of the subroutines if so.
I guess I could buy the bs2p microcontroller but I want to ask if I'm correct before I spend $200 on it for next-day shipping
Peter167,
The BS2 has only 2K of EEPROM and you repeat the same code segments over and over again.
https://www.parallax.com/package/basic-stamp-manual/
Notice how the wheel pulse rates are treated as variables in the IR roaming programs starting on page 250 of Robotics with the BOE-Bot.
In AvoidTableEdge on page 245, the number of servo pulses is also a variable.
Look at the code segment at the bottom of page 133 to see as a perfect example.
The more often that you can use the same segment of code and the same variables, the more compact your program will be.
I see that you are using some of the code from Chapter 8, Activity 1 but your starting frequency values don't match.
What's a Microcontroller is a good reference for basic BS2 programming.
https://www.parallax.com/package/whats-a-microcontroller-and-linked-downloads/
StampWorks deals with more advanced BS2 programming.
https://www.parallax.com/package/stampworks-experiment-kit-manual-and-code/
Very helpful, thank you!