Abstract Our overall goal for this project was to create an interactive system that provided a variety of types of play for children. We hoped our design would engage a child’s senses and encourage them to play and share with others. As an extension, we wanted to conceal parts of our system so that marbles would “disappear” into holes and “reappear” in other places. We feel these goals were met through our project design and sparked interesting outcomes.
Objectives Our goal for this project was to create an interactive system that provided a variety of types of play for children. One type of play we wanted to explore was sensory experiences integrated into the overall system. To do this we included a tactile inflatable that could be pressed on and bounced, reactive, colorful lights surrounding the turntable, and a bit of airflow beneath the geometric ramp. Another aspect of play we looked at was concealing the marble’s routes so that a marble would disappear as it fell into a hole and reappear when it re-emerged out of a separate part of the system. We wanted the “hidden” parts of our design to excite the children and engage them in figuring out how the system worked on a low level. To achieve this, we created a double ramp system that sent marbles from the turntable to the top of the ramp or a ball launcher, depending on what hole the ball fell into.
Implementation To implement our design, we had four “play” pieces interlocked with a center turntable who’s holes lead to either an Archimedes’ screw and a ramp back to the turntable, or a ball launcher pointed at the turntable. Two separate internal ramps led to each outcome, depending on the hole of entrance, and we saw that the children were initially surprised to see marbles pop out of one location or another. Both the Archimedes’ screw and ball launcher systems were included to provide a self contained system that would keep the marbles moving even in the absence of a child playing with them.
We created an interlocking system between the turntable and its surrounding sections in order to make our system more resilient to play. Our prototype test showed us that our system wasn’t resilient enough to withstand play. If the ramps and other play pieces were simply placed next to the turntable, as they were in the first iteration of our design, they very quickly ended up in new places that hindered continuous use for the kids. As a result, the bottom portion of each piece connected to the center turntable using a puzzle piece-like connection that held up very well during our final test.
A brief summary the construction/purpose of each piece within our design:
For all the systems described above, our project used 3 continuously running motors, an infrared sensor, and a NeoPixel LED light strip. Below is the code and wiring diagrams used for the 2 Pico boards used.
# Below is a section of code used to control the LED light strip #--------------------------------------------------------- # The NeoPixel strand uses one GPIO output. Note that in general it will need # separate 5V power, only the smallest arrays can use USB power. pixels = digitalio.DigitalInOut(board.GP13) pixels.direction = digitalio.Direction.OUTPUT # The number of NeoPixels must be specified, as they cannot be detected. num_pixels = 12 # Create a buffer for storing a complete linear image. The color order and # depth depends upon the specific devices, but are typically 3 bytes (24 bits) # per pixel in BGR order. The first pixel data will apply to the first device # in the chain, the second to the next, etc. Excess data will have no effect. # If less than a full frame is sent, the last pixels will not change. frame_buffer = bytearray(3*num_pixels) #--------------------------------------------------------- # Run the main loop to generate a sequence of frames as fast as possible if a marble is detected. print("Starting main script.") while True: # Read the sensor once per cycle. sensor_level = sensor.value # send color sequence iff the sensor detects a marble if (sensor_level> 4): for i in range(20): # generate the next frame based on the real-time clock value now = time.monotonic_ns() / 1000 # generate a temporal color sequence with each component out of phase red = int((now//11000) % 256) grn = int((now//33000) % 256) blu = int((now//55000) % 256) # update the entire frame buffer including an additional position-dependent term # to create spatial variation for p in range(num_pixels): frame_buffer[3*p] = (grn + 12*p) % 256 frame_buffer[3*p+1] = (red + 12*p) % 256 frame_buffer[3*p+2] = (blu + 12*p) % 256 # transfer the new frame to the NeoPixel LED strand neopixel_write.neopixel_write(pixels, frame_buffer) # generate white red = int(256) grn = int(256) blu = int(256) # clear the entire frame buffer when a marble isn't detected for p in range(num_pixels): frame_buffer[3*p] = (grn + 12*p) % 256 frame_buffer[3*p+1] = (red + 12*p) % 256 frame_buffer[3*p+2] = (blu + 12*p) % 256 # send the "blank" frame to the NeoPixel LED strand neopixel_write.neopixel_write(pixels, frame_buffer)
# Below is a section of code used to control the motors #--------------------------------------------------------- # The main processing loop is set to continously drive both motors. print("Starting main script.") while True: # run both motors at full speed driver.write(0, 1.0) driver.write(1, 1.0) time.sleep(2.0)
Outcomes The children played with our project in similar capacities as our first iteration, with a bit more focus on getting marbles to go through the center hole of the turntable to make the LEDs light up and see the cat (ball launcher) “spit out” the marble.
Marbles disappearing into holes and reappearing in other places created curiosity and exploration for some of the children. There were a handful of kids who attempted to test every hole on the turntable to see where the marbles would reappear depending on their input.
With the addition of a ball launcher that projected balls in the direction of the inflatable, we noticed a couple children try to “aim” with the launcher and express “success” when the marbles would bounce on the inflatable and go into the center turntable. While the launcher wasn’t really controlled by the users, that didn’t stop kids from repeatedly putting marbles into the center hole to see how it would be launched (it seemed marbles would be launched at different angles depending on how the rolling marble came into contact with the launcher).
We noticed that children were excited to play with the catapults and played with the increased number of catapults (from 1 to 2) with their peers or by themselves. If a child saw something interesting happen with a catapult, they could immediately try it for themselves without any interruption or waiting for the other child to finish playing. We also saw kids try to use both catapults simultaneously and experiment with their fine motor skills.
Future Work If we were to make another iteration of this project, we would focus on fine tuning the range the marbles could be launched and put more focus on the finished look of the project rather than just its functionality. We believe that a cleaner look would make play more straightforward so the kids exclusively focus on the features we intend to be played with.
Contribution To divide project work, Waleed was much more familiar with using SolidWorks to design physical systems, so he designed many of the interacting laser cut pieces and archimedes’ screw. Sandra had more electrical circuit and sewing experience so she was responsible for those aspects of the project alongside a couple laser cut pieces (specifically the catapult design and second center ramp) to distribute the work more evenly.
Abstract: The overall goal of the project was to create a marble track game that could be configured in many different ways. We wanted to emphasize modularity through design choices so the pieces could be used for many play modes and to allow multiple kids to play at once. The older kids were much more receptive to the idea of creating different piece configurations while the younger kids needed a lot of suggestions. Overall, we believe the kids enjoyed playing with our marble toy.
Objectives: The primary goal was to create a collection of tile pieces that could be arranged in many permutations to form long tracks for the marbles to roll down. We wanted there to be enough pieces that multiple kids could interact with the toy at the same time and possibly even make multiple tracks. We planned on designing pieces that varied in complexity to allow for many modes of interaction with the pieces.
Implementation: We created three categories of pieces for the marble to roll through: complex pieces, medium pieces, and simple pieces. Complex pieces would be motorized and mostly used to lift up marbles, medium pieces that usually include user interaction, and simple pieces that have tracks for the ball to roll through and to connect other pieces. We wanted to make the complex lifting pieces interesting to look at so the kids could watch their marbles get lifted up. During the first children’s school visit the gear spinning pieces wasn’t working exactly how we intended; the gear would only spin if you moved it with your hands. But, we learned from watching the kids that they enjoyed the interaction with the piece, and we designed a second medium piece with this goal in mind. We also later decided to paint some of the pieces in different patterns and colors to make the whole collection less mundane and to entice the kids to want to play with our toy. The idea behind the moveable bounce pad on the Archimedes screw piece was to allow children to aim a jumping ball into another piece and to redirect the ball in new directions to promote piece configurations that weren’t just straight lines.
Outcomes: The first two outcomes had to do with the children’s’ responses, while the latter two had to do with problems we encountered throughout the process. The first outcome was that younger kids didn’t make as much of an active effort to rearrange pieces. They didn’t understand the concept of building a continuous track, they focused more on playing with individual pieces and on observing the current system state. The second outcome was that older kids were more interested in arranging the pieces to create custom tracks. They actively moved pieces and understood the idea that pieces needed to be lined up to create a continuous path. The third outcome was that controlling the output location of marble from the piece was harder than expected. Various characteristics of user interaction such as force applied and exit location influences where the marble lands when exiting from the pieces. The fourth outcome was that creating perfectly aligned tracks was harder than expected. Since we didn’t standardize the input and output heights, it took a lot of effort to get pieces to align.
Future Work: The main goal moving forward would be to create a plan to allow for easier alignment of pieces by creating a standardized guide that allow for more permutations of tracks. We could do this by widening the track width, controlling the output path, standardizing the heights of pieces, and creating more vertical lifting pieces.
Contribution: Diederik designed, fabricated, and coded the two complex pieces and the spinning gear medium piece, and Saloni designed and fabricated the other medium pieces, all of the simple pieces, and all the height blocks and ideated the concept for all the pieces.
Technical Documentation:
DC Motor Circuit (from course website)
Code for Both Motors (from course website)
# dual_spin.py # # Raspberry Pi Pico - DC motor motion demo # # Demonstrates operating two DC motors driven by a DRV8833. # # This assumes a Pololu DRV8833 dual motor driver has been wired up to the Pico as follows: # Pico pin 24, GPIO18 -> AIN1 # Pico pin 25, GPIO19 -> AIN2 # Pico pin 26, GPIO20 -> BIN2 # Pico pin 27, GPIO21 -> BIN1 # any Pico GND -> GND # DRV8833 carrier board: https://www.pololu.com/product/2130 ################################################################ # CircuitPython module documentation: # time https://circuitpython.readthedocs.io/en/latest/shared-bindings/time/index.html # math https://circuitpython.readthedocs.io/en/latest/shared-bindings/math/index.html # board https://circuitpython.readthedocs.io/en/latest/shared-bindings/board/index.html # pwmio https://circuitpython.readthedocs.io/en/latest/shared-bindings/pwmio/index.html ################################################################################ # print a banner as reminder of what code is loaded print("Starting dual_spin script.") # load standard Python modules import math, time # load the CircuitPython hardware definition module for pin definitions import board # load the CircuitPython pulse-width-modulation module for driving hardware import pwmio #-------------------------------------------------------------------------------- # Class to represent a single dual H-bridge driver. class DRV8833(): def __init__(self, AIN1=board.GP18, AIN2=board.GP19, BIN2=board.GP20, BIN1=board.GP21, pwm_rate=20000): # Create a pair of PWMOut objects for each motor channel. self.ain1 = pwmio.PWMOut(AIN1, duty_cycle=0, frequency=pwm_rate) self.ain2 = pwmio.PWMOut(AIN2, duty_cycle=0, frequency=pwm_rate) self.bin1 = pwmio.PWMOut(BIN1, duty_cycle=0, frequency=pwm_rate) self.bin2 = pwmio.PWMOut(BIN2, duty_cycle=0, frequency=pwm_rate) def write(self, channel, rate): """Set the speed and direction on a single motor channel. :param channel: 0 for motor A, 1 for motor B :param rate: modulation value between -1.0 and 1.0, full reverse to full forward.""" # convert the rate into a 16-bit fixed point integer pwm = min(max(int(2**16 * abs(rate)), 0), 65535) if channel == 0: if rate < 0: self.ain1.duty_cycle = pwm self.ain2.duty_cycle = 0 else: self.ain1.duty_cycle = 0 self.ain2.duty_cycle = pwm else: if rate < 0: self.bin1.duty_cycle = pwm self.bin2.duty_cycle = 0 else: self.bin1.duty_cycle = 0 self.bin2.duty_cycle = pwm #-------------------------------------------------------------------------------- # Create an object to represent a dual motor driver. print("Creating driver object.") driver = DRV8833() #-------------------------------------------------------------------------------- # Begin the main processing loop. This is structured as a looping script, since # each movement primitive 'blocks', i.e. doesn't return until the action is # finished. print("Starting main script.") while True: driver.write(0, 1.0)
Objectives Our overall goals for this project were to create an interactive system that provided a variety of types of play for children. In this project, we wanted to conceal parts of the system so that marbles would “disappear” into holes and “reappear” in other places.
Implementation To implement our design, we had four pieces connecting to a center turntable with holes that lead to either an Archimedes’ screw and a ramp, or a ball launcher, depending on the entrance hole. two separate internal rams led to each outcome and we saw the children were initially surprised to see marbles pop out of one location or another.
Outcomes The children played with our project in similar capacities as the last iteration, with a bit more focus on putting marbles through the center hole to make the LEDs light up and see the cat “spit out” the marble. Additionally, we received positive feedback from a handful of kids who remembered our project and were very excited to play with it again.
Future Work If we were to make another iteration of this project, we would focus on fine tuning the range the marbles could be launched and work on the system being more resistant to play. Additionally, we would put more focus on the finished look of the project rather than just its functionality. We believe tha a cleaner look would make play more straightforward so the kids exclusively focus on the features we intend to be played with.
Our main goal was to develop a large interactive marble run that would capture and maintain the attention of young children at the local school for a long period of time. This particular project was designed with the intention of being large in scale, composed of multiple modular paths, and various kinetic elements that helped guide or capture the marbles in the slide. Our hope was that the children would greet our Megaslide with enthusiasm, excitement, and leave with a newfound opportunity to explore and interact with the kinetic and structural mechanisms while strengthening their estimation and prediction skills. The Megaslide experienced several ideation revisions and structural reconstructions through initial testing at the Children’s school and in class critiques.
The overall goal was to design a slide that could maintain the children’s attention for a longer period of time than an average game/slide iteration. After the first interaction with the children’s school, our team had realized that our initial Megaslide design was too bulky for transport, unintuitive, lacked movement, and had ramps that were too steep. For the slide’s redesign, our team wanted to emphasize the parts that the children loved: simplicity, intuitive interaction, mass marbles, speed, large scale, running after the marbles, and movement.
Regarding kinetic aspects, our team had gone through multiple iterations of the basketball hoop for the Childen’s school, and we ended up putting it next to the slide as it didn’t work as intended. Our team’s goal for kinetic aspects was to get them working well and integrate them more into the slide as a way to transport the marbles through the tunnels.
Throughout the entire project, our designs drastically changed and went through multiple revisions. Each of our kinetic pieces went through an incredible amount of design iterations and revisions ranging from multiple problems, and in the end, never quite worked how we intended.
Initially, we intended to create a self-playing basketball game, with the potential for interaction with children. This particular machine aimed to implement a motorized slingshot that would shoot the marble towards the hoop. Our slingshot never worked, so to involve some sort of movement for the children’s school, our team altered the motor into a revolving spinning motion. The children positively interacted with the motor for a short period of time and were happy to run after their marbles until they got bored and realized the piece didn’t give them their desired results. The visual interaction seen between the children and the piece strongly indicated that our team needed to rethink our kinetic pieces.
Our final design iteration had included all our initial observations and positive aspects that the children truly gravitated towards: simplicity, intuitive interaction, mass marbles, speed, large scale, running after the marbles, and movement. Our team also added the special element of prediction and estimation through surprise tunnels and holes causing marbles to unexpectedly switch paths.
Since our team overhauled our design so close to the final demo, we felt that we had to be realistic in the pieces we would be able to create, which ultimately limited the pieces we created and how we created them because we needed them to work whether mechanical or motorized. The final kinetic pieces we constructed were a spinning ball collector, a vertical wheel, and a bouncy platform.
On our initial slide design, the ramps were too steep causing the marbles to accelerate off the ramp towards the other end of the room. This not only created a safety hazard of children/teachers tripping or falling down due to the rampant marbles, it makes it difficult to find the lost marbles. The teachers at the Children’s School ended up helping us create a barrier that would stop the marbles from going too far. The children loved running after and collecting the marbles, and our team wanted to maintain a bit of this simple joy the children experienced. Our team aimed to develop a kinetic marble collector that would help us maintain the marbles and keep track of them all, but kept it towards the bottom of the slide, so the children would have to continue transporting them back to the starting point.
This particular marble platform went through multiple iterations and none of them quite worked as we hoped. Our team had planned for this marble platform to act as a transportation path between tunnels, but had accidentally scaled it just slightly too big for the area it had intended to be located. Our team decided to stick this particular platform in the beginning of the slide instead.
Our team developed the elevator/wheel as a way to transport marbles from one tunnel path to another. We had been working to including a motor, but this piece became mechanical as the motor had not working as we hoped.
The slide garnered the most enthusiastic response from children with many jumping or screaming with excitement, even with some students needing to be dragged away from the slide so other children could have more time at the slide. The students loved the hole and tunnel aspect with some children specifically placing marbles in each hole to find where they exited. Our team had expected more students to want to use the slide as a mode of competition between all the marbles. Since there were many “dead” areas where the marbles got stuck, our team observed that the children were more focused on getting the marbles to reach the “finish line” and which path could get them there the fastest.
The favorite kinetic piece amongst the children was the collector. Most students enjoyed seeing the balls spin around and enjoyed grabbing marbles from their place on the collector. There were many students who were only fascinated by the collector and chose to spend their time placing every marble in each hole on the collector.
For the vertical elevator, the kids did initially seem to be interested in this piece, however they struggled to understand how it worked. The piece ended up being broken early on during the showcase, which made it difficult to see how other students interacted with the kinetic mode.
As for the bouncing platform, the children didn’t really know what to do with this piece. They tried dropping the marbles into the piece, but didn’t catch on to the fact that they were meant to move the pieces with the strings. In the end, they ended up ignoring this piece.
In the future, our team believes that our kinetic pieces needed to be simplified. We always created a piece by developing a goal or a specific form of interaction we hoped to develop, and sometimes the ideas were slightly too ambitious, never quite working out how we hoped even after multiple iterations. Our team also would hope to create even more interaction between the kinetic pieces and slide where they were more integrated with one another.
During final critique, someone had mentioned implementing kinetic pieces that worked as a stopper or slows down other marbles on various paths to make it more of a competition. This is a really interesting idea for a more competitive slide, and our team would love to explore this aspect further.
In regards to the slide, the main revision for a future work would be to better design the slide and ramps so that there weren’t as many dead areas where the marbles would get stuck. Our original plywood print out was scaled too large and we had to heavily revise the base outline with the pieces we had. The pieces worked well together, but caused some difficulties in terms of the overall smoothness of our slide causing dead areas and uneven entrances/exits for the marble. In addition, the slide had to developed in pieces for easy transportation and if we could create one full slide that wasn’t in pieces, that would be fantastic.
1-2 Minute Video Demonstration (Kinetic Videos Shown Above)
Solidworks and Python Files
import math, time import board import pwmio def servo_write(servo, angle, pulse_rate=50, debug=False): pulse_width = 0.001 + angle * (0.001 / 180.0) cycle_period = 1.0 / pulse_rate duty_cycle = pulse_width / cycle_period duty_fixed = int(2**16 * duty_cycle) servo.duty_cycle = min(max(duty_fixed, 0), 65535) # print some diagnostics to the console if debug: print(f"Driving servo to angle {angle}") print(f" Pulse width {pulse_width} seconds") print(f" Duty cycle {duty_cycle}") print(f" Command value {servo.duty_cycle}\n") #-------------------------------------------------------------------------------- def constantSpin(servo): servo_write(servo, 0) #-------------------------------------------------------------------------------- # constant spin servo servo1 = pwmio.PWMOut(board.GP0, duty_cycle = 0, frequency = 50) while True: constantSpin(servo1) time.sleep(.25)
Additional Images of Design/Production from Original Slideshow
https://docs.google.com/presentation/d/1ofk8OZU2hKioLtVvLoL_oHv8QUR8j9NiwZwvWWuMTXc/edit?usp=sharing
]]>Abstract:
One of the core goals of our project was to explore how children would respond to the ‘indirect’ method of control we were presenting them with and also design our project to make it easier for the children to adapt to the idea of interacting with the box purely through marbles. Overall our box ended up highlighting ‘indirect’ experiences – the magnet mechanism, movable ramps, and toggling spinner all created an extra step between the children’s actions and the marble’s movement which we discovered was both a source of frustration and satisfaction for the children.
We observed that the children were either very receptive to our project, or got frustrated quickly. The older children tended to be more on the receptive side and seemed to enjoy the challenge of isolating their marble, going down difficult ramps, discovering each of the elements, and building their own structures.
How our project evolved:
Ideation:
Reflections:
One major thing we did not consider during the ideation phase was how the marble’s movement up and into structures would be limited. For example, going up even extremely shallow ramps and being ‘scooped’ up were much more difficult to accomplish than we had anticipated. Thus, we ended up adjusting the contents of our box to take advantage of the wall space to move the marbles around.
First Prototype:
Final Prototype:
User-focused Goals of our Magnetic Marble Box Components:
Technical-focused Goals of our Magnetic Marble Box Components:
Implementation:
Outcomes:
Future Works:
Contibutions:
Jiatong: Ramp systems (both in-plane and perpendicular), movable ramp structures
Thanh: Box frame, magnet handles, maze
Melinda: Motorized wheel lift, gear train w/photosensor and base-embedded spinner
All: Overall ideation, research, and project assembly
Citations:
All references for code, technical documentation, and material concerns came from the CKS and Ideate websites
Similar artifacts include things like magnetically controlled tabletop games like the one linked below:
Supplementary Files:
# Source Code: # Driver Object driver = DRV8833() # Wall wheel spins continously driver.write(1,-0.65) # Sensor Object sensor = analogio.AnalogIn(board.A0) def getAmbientLighting(): pool = 0 for i in range(10): pool += sensor.value time.sleep(0.5) return (pool/10) ambient = getAmbientLighting() while True: sensor_level = sensor.value if sensor_level > ambient + 500: driver.write(0, 0.8) else: driver.write(0,0)]]>
The main part of our project consisted of 4 motors moving in crank motion, which would ultimately lift and lower the canvas in certain points. This allowed us to create a table tilt motion as well as have full control of the x and y axis tilt motions. To add additional support in the center, we supported the canvas on a universal joint which was connected to the canvas and the support beam. This prevented the spining of the canvas allowing it to be balanced while moving.
The children were able to actively interact with our project. There are some steps that are required to build up towards the moment of discovery for the children. We had to tell them the steps to get our project set up for them. Once they started to play with the marbles, the children found different ways to interact with the paint as well. We observed some children wanting to mix multiple colors of paint to color the canvas where some kids wanted to push the marble with their hands while it was on the canvas.
The pieces that the children created were really amazing but there was some difference between the preschoolers (3~4 year olds) and the kindergarten group. The older children were able to interact with the marble more in different ways causing the paintings to be more dynamic and have more lines and streaks.
Originally, we expected to have marble runs where the children would pour the paint and marbles onto the canvas. However, having the children pour their own paint and directly interact with the marbles allowed us to have more unique pieces. So we decided that we would keep the marble runs only to help the children drop the marbles onto the canvas. The children would ultimately pour the paint themselves and would drop the marbles using their hand or the marble runs.
The 4-year-old children and kindergarteners were excited to see different strokes and color mixing whereas 3-year-old children enjoyed adding a lot of paint and marbles on the canvas.
Major additions to our project
Pipets: A first, the kindergarteners were not as excited to use pipets to put paint on canvas because they had to wait for us to fill them with paint. When they got tired of waiting, they would grab pipets filled with water and put water on canvas. As a result, one of the groups created a puddle of mixed paint on canvas. Thus, we sped up the process of filling and washing pipets and handing them the marbles. We allowed them to keep adding color of their choice so they don’t get bored, which worked out. Over time, they started using pipets to put paint on different areas.
Barrier: We added a barrier so that the marbles stay on the canvas for a longer period of time. This worked but the kids’ level of patience would drop over time. They would eventually grab marbles from the canvas. Adding exit holes on the corners would have improved our project because that’s where marbles get stuck the most.
Water Containers: Most of the kids enjoyed watching the marbles fall into the water containers and grabbing marbles from the them. One of the kids didn’t like getting their hands wet, so we handed them the washed marbles.
Marble Track: We also introduced them to a track that they can use to create a different stroke of paint. They liked dropping and moving the marbles with their hands more than using this track. This could have been different if we had multiple tracks.
# drv8833.py # # Raspberry Pi Pico - dual H-bridge motor driver support # # This module provides a class for controlling a DRV8833 dual H-bridge DC motor driver. # This device can drive two low-power DC motor bidirectionally with variable speed. # # A typical usage requires four digital outputs. The defaults assumes a Pololu # DRV8833 dual motor driver has been wired up to the Pico as follows: # Pico pin 24, GPIO18 -> AIN1 # Pico pin 25, GPIO19 -> AIN2 # Pico pin 26, GPIO20 -> BIN2 # Pico pin 27, GPIO21 -> BIN1 # any Pico GND -> GND # DRV8833 carrier board: https://www.pololu.com/product/2130 ################################################################ # CircuitPython module documentation: # time https://circuitpython.readthedocs.io/en/latest/shared-bindings/time/index.html # math https://circuitpython.readthedocs.io/en/latest/shared-bindings/math/index.html # board https://circuitpython.readthedocs.io/en/latest/shared-bindings/board/index.html # pwmio https://circuitpython.readthedocs.io/en/latest/shared-bindings/pwmio/index.html # # Driver lifecycle documentation: # https://circuitpython.readthedocs.io/en/latest/docs/design_guide.html#lifetime-and-contextmanagers # ################################################################################ # load standard Python modules import math, time # load the CircuitPython hardware definition module for pin definitions import board # load the CircuitPython pulse-width-modulation module for driving hardware import pwmio #-------------------------------------------------------------------------------- class DRV8833: def __init__(self, AIN1=board.GP18, AIN2=board.GP19, # control pins for motors 1,2 BIN2=board.GP20, BIN1=board.GP21, # control pins for motors 3,4 pwm_rate=20000): """This class represents a single dual H-bridge driver. It configures four pins for PWM output and can be used to control two DC motors bidirectionally at variable speed. N.B. this does not implement any other timing process, it simply sets motor PWM levels but does not apply feedback, duration, or trajectory. """ self.ain1 = pwmio.PWMOut(AIN1, duty_cycle=0, frequency=pwm_rate) self.ain2 = pwmio.PWMOut(AIN2, duty_cycle=0, frequency=pwm_rate) self.bin1 = pwmio.PWMOut(BIN1, duty_cycle=0, frequency=pwm_rate) self.bin2 = pwmio.PWMOut(BIN2, duty_cycle=0, frequency=pwm_rate) def tilt_table(self, channel, rate): """Set the speed and direction on a single motor channel. :param int channel: 0 for motor A, 1 for motor B :param float rate: modulation value between -1.0 and 1.0, full reverse to full forward.""" # convert the rate into a 16-bit fixed point integer pwm1 = min(max(int(2**16 * abs(rate)), 0), 52000) pwm2 = min(max(int(2**16 * abs(rate)), 0), 52000) if channel == 0: self.ain1.duty_cycle = 0 self.ain2.duty_cycle = pwm1 self.bin1.duty_cycle = 0 self.bin2.duty_cycle = pwm2 def roll_x(self, channel, rate): """Set the speed and direction on a single motor channel. :param int channel: 0 for motor A, 1 for motor B :param float rate: modulation value between -1.0 and 1.0, full reverse to full forward.""" # convert the rate into a 16-bit fixed point integer pwm = min(max(int(2**16 * abs(rate)), 0), 52000) if channel == 0: self.ain1.duty_cycle = 0 self.ain2.duty_cycle = pwm self.bin1.duty_cycle = 0 self.bin2.duty_cycle = 0 def roll_y(self, channel, rate): """Set the speed and direction on a single motor channel. :param int channel: 0 for motor A, 1 for motor B :param float rate: modulation value between -1.0 and 1.0, full reverse to full forward.""" # convert the rate into a 16-bit fixed point integer pwm = min(max(int(2**16 * abs(rate)), 0), 52000) if channel == 0: self.ain1.duty_cycle = 0 self.ain2.duty_cycle = 0 self.bin1.duty_cycle = 0 self.bin2.duty_cycle = pwm def deinit(self): """Manage resource release as part of object lifecycle.""" self.ain1.deinit() self.ain2.deinit() self.bin1.deinit() self.bin2.deinit() self.ain1 = None self.ain2 = None self.bin1 = None self.bin2 = None def __enter__(self): return self def __exit__(self): # Automatically deinitializes the hardware when exiting a context. self.deinit()
# photomotor.py # # Raspberry Pi Pico - photointerrupter and DC motordemo # # Demonstrates operating a DC motors driven by a DRV8833 based # on a photointerrupter signal. # # This assumes a photointerrupter circuit is wired to analog input 0. # # This assumes a Pololu DRV8833 dual motor driver has been wired up to the Pico as follows: # Pico pin 24, GPIO18 -> AIN1 # Pico pin 25, GPIO19 -> AIN2 # Pico pin 26, GPIO20 -> BIN2 # Pico pin 27, GPIO21 -> BIN1 # any Pico GND -> GND # DRV8833 carrier board: https://www.pololu.com/product/2130 ################################################################ # CircuitPython module documentation: # time https://circuitpython.readthedocs.io/en/latest/shared-bindings/time/index.html # math https://circuitpython.readthedocs.io/en/latest/shared-bindings/math/index.html # board https://circuitpython.readthedocs.io/en/latest/shared-bindings/board/index.html # pwmio https://circuitpython.readthedocs.io/en/latest/shared-bindings/pwmio/index.html ################################################################################ # print a banner as reminder of what code is loaded print("Starting photomotor script.") # load standard Python modules import math, time # load the CircuitPython hardware definition module for pin definitions import board # load the CircuitPython interface to the analog-to-digital converter import analogio # load the CircuitPython pulse-width-modulation module for driving hardware import pwmio # load the drv8833.py module, which should be copied to the top-level of CIRCUITPY from drv8833 import DRV8833 #-------------------------------------------------------------------------------- # Create an object to represent a dual motor driver. print("Creating driver object.") driver = DRV8833() # Create an object to represent the ADC0 input, which is physically pin 31. # E.g., this may be attached to photocell or photointerrupter with associated pullup resistor. sensor = analogio.AnalogIn(board.A0) #-------------------------------------------------------------------------------- # Begin the main processing loop. This is structured as a looping script, since # each movement primitive 'blocks', i.e. doesn't return until the action is # finished. print("Starting main script.") while True: # Set the motor speed. driver.tilt_table(0, 1) time.sleep(4.3) driver.roll_x(0, 1) time.sleep(3.0) driver.tilt_table(0, 1) time.sleep(4.7) driver.roll_y(0, 1) time.sleep(3.0)
The children were able to actively interact with our project. There are some steps that are required to build up towards the moment of discovery for the children. We had to tell them the steps to get our project set up for them. Once they started to play with the marbles, the children found different ways to interact with the paint as well. We observed some children wanting to mix multiple colors of paint to color the canvas where some kids wanted to push the marble with their hands while it was on the canvas.
The pieces that the children created were really amazing but there was some difference between the preschoolers (3~4 year olds) and the kindergarten group. The older children were able to interact with the marble more in different ways causing the paintings to be more dynamic and have more lines and streaks.
Originally, we expected to have marble runs where the children would pour the paint and marbles onto the canvas. However, having the children pour their own paint and directly interact with the marbles allowed us to have more unique pieces. So we decided that we would keep the marble runs only to help the children drop the marbles onto the canvas. The children would ultimately pour the paint themselves and would drop the marbles using their hand or the marble runs.
Our project ended up working right before the visit so there were some parts that were unaccounted for. We had to make sure that the electronics in the middle were covered so paint could not get on them as well as making sure the motors kept on moving even with child interaction. The children were naturally curious about the cranks and moving joints so they were touching the parts. This led to the pistons attached to the crank falling out sometimes. During the first couples of groups, the cranks held up just fine, but towards the end of the visit, the pistons fell out more often.
Another technical limitation we observed was the movement of the canvas. This was somewhat expected since the canvas is not balanced and tuned percisely, but the tilt motion would not create a perfect spiral motion for the marble. This also led to the marble not staying on the canvas long enough and the children had to use many marbles to satisfied.
We would say that our prototype was a success and there definitely were points where the children were captivated and engaging with the project actively. However, for the second iteration we want to refine these points of captivation. Specifically with the canvas motion and tuning the parts and code so that the spiral motion is more consistent. Refining this motion will also allow for the pistons to become more stable and fall out less often. There are some limitation since we know we can produce every single part precisely and it hard to balance the canvas perfectly but these limitations can be somewhat accounted for through software calibration.
As you can see in the first video of Preschoolers dropping marbles on to the canvas, they grab the canvas and try to make the marble stay on the canvas. In order to let them watch the marble move around more, we are thinking of creating a low barrier (clear acrylic) around the canvas that has an exit on each side. By making a barrier, the marble can make more diverse strokes of paint that kids can enjoy watching.
We also need to create the marble run that the children will drop their marbles into. These will most likely be made out of wood and produce motions that can create additional different strokes on the canvas.
We are still planning on putting containers filled with water where marbles can fall into. They will be located right under the barrier marble exits. This way, the kids can wash the marbles themselves. In order to prevent water and paint from splashing on the electronics, we can make a clear acrylic shield behind the cranks so that kids can still see what’s moving the canvas.
]]>The only part that failed was the spinning wheel piece because I dropped it on the way to the children’s school. None of the other parts failed, somewhat surprisingly. Occasionally the ferris wheel motor would stall if a child jammed their hand or a different piece in it.
We need to design a lot more simple pieces, more medium level pieces, and at least a second complex piece that the children can use because they really enjoyed the moving parts. We realized that due to the varying heights/speeds of the medium/complex pieces the simple pieces couldn’t be lined up perfectly even with the height blocks. Given this we will make height blocks of varying heights and also will try to standardize the exit height of the marble for medium/complex pieces in order to make sure the pieces can be aligned.
As the spinning gear didn’t quite work, the children had to use their hands to spin the gear manually and we learned that they really enjoyed the aspect of touching the pieces. With this in mind, we can design more pieces that require interaction from the kids because that will keep them more engaged. We will add more mechanically moving pieces and stick to just a few automated pieces as children can quickly get bored of those if they don’t have anything else to do.
We can also play around with the idea of removing plugs for the moving pieces and using battery packs instead so that all the pieces can be moved around on the floor. We will also focus on creating covers for our automatic pieces to hide the wires and circuits to ensure nothing gets ruined.
]]>We also saw that children were most interested in the parts of the box that had clearly defined goals/structure for play (i.e. almost every child attempted at some point to get to the middle of the maze, and many of them wanted to try to get their marble into the wheel system). Even when performing seemingly unstructured tasks like trying to move the marbles up the walls, many of the children were aiming for the an end goal of either dropping the marble or getting it as high as possible. Thus, it may be helpful for us to include many modules that easily provide some sort of sensory feedback so that the children can define a wider array of goals for themselves.
In terms of technical limitations, we noticed that the biggest one was how kids were having trouble seeing where their magnets are in order to move the marble that they want. Their arms are also too short to reach all the way across the box. The power of the magnets are sometimes also too weak because of the thickness of the wood between the magnets and the marbles.
Moving forward, we’ve decided that for the overall box:
For our wall with wire and tabs
Possible improvements we are currently considering: