https://www.yahboom.com/build.html?id=10955&cid=66...
बनाया गया: 20 जनवरी 2026
का उपयोग करके उत्तर दिया गया GPT-5.2 Thinking द्वारा Chat01
बनाया गया: 20 जनवरी 2026
का उपयोग करके उत्तर दिया गया GPT-5.2 Thinking द्वारा Chat01
你们按教程在浏览器输 IP:8888 进不去,一般就落在三类问题里:
192.168.2.95:8888 只是示例;实际必须用你这台小车(树莓派/Jetson)的当前 IP,并且电脑要和它在同一局域网(同一个路由器/同一个 Wi-Fi),才能访问。(亚博智能科技官网)hostname -I 或 ip -4 addrping 小车IP:
sudo ss -lntp | grep 8888jupyter server list(或 jupyter notebook list)sudo systemctl restart nano_jupyter.service(不同镜像服务名可能不同,也可以 systemctl | grep jupyter 找一下)jupyter server list 里。(jupyter-server.readthedocs.io)jupyter notebook password,那密码就被改成你们设置的新密码了。(亚博智能科技官网)jupyter server list 找 token,或确认是否改过密码如果你把下面两样信息贴出来(任意一种就行),我可以直接帮你判断是哪一类:
1)浏览器报错文字(超时/拒绝连接/密码错误)
2)在小车上执行 hostname -I 和 jupyter server list 的输出(打码也行)。
很好现在我进去了,但是有个问题,我按照这个https://www.yahboom.com/build.html?id=10973&cid=663步骤进行后续的操作,但是出现了照片中的报错
我看了你这张 JupyterLab 的截图,报错核心是这一句:
ModuleNotFoundError: No module named 'McLumk_Wheel_Sports'
这表示 Python 没有在“可搜索路径”里找到 McLumk_Wheel_Sports 这个库/文件。结合你截图里第一行:
pythonsys.path.append('/home/pi/project_demo/lib')
而你左侧文件树的真实目录是在:
/project_demo/05.Comprehensive_gameplay/ ...
所以最大概率原因是:你机器上的 demo 实际放在 /project_demo,但代码却把库路径加成了 /home/pi/project_demo/lib(路径不对),导致导入失败。
pythonimport os print("exists /home/pi/project_demo/lib =", os.path.exists("/home/pi/project_demo/lib")) print("exists /project_demo/lib =", os.path.exists("/project_demo/lib")) !ls -l /project_demo | head !ls -l /project_demo/lib | head
/home/pi/project_demo/lib 是 False、/project_demo/lib 是 True,那就完全对上了:就是路径写错。把你那一格代码改成这样再运行一次:
pythonimport sys sys.path.append('/project_demo/lib') from McLumk_Wheel_Sports import *
然后 Kernel → Restart Kernel(或重启内核)再从头跑一遍。
Linux 下导入是严格区分大小写的,文件名必须和 import 一模一样。
你在 Notebook 里跑这个找一下真实文件名:
python!ls -1 /project_demo/lib | grep -i wheel
McLunk_Wheel_Sports.py、MCLumk_Wheel_Sports.py 之类,就把 import 那行改成和文件名完全一致。如果你 ls /project_demo/lib 里压根没有 McLumk_Wheel_Sports.py,那就是驱动库没装/没拷贝完整。
这时你可以在终端执行(有 setup.py 的情况下):
bashcd /project_demo/lib sudo python3 setup.py install
装完回到 Jupyter 重启内核再试。
exists /home/pi/project_demo/lib = ?exists /project_demo/lib = ?ls -1 /project_demo/lib | grep -i wheel 的输出(截图/复制都行)import sys
import time
sys.path.append('/home/pi/project_demo/lib')
from McLumk_Wheel_Sports import *
speed = 25#25
try:
while True:
# 从I2C读取巡线传感器数据 Read line sensor data from I2C
track_data = bot.read_data_array(0x0a, 1)
track = int(track_data[0])
# 解析巡线传感器的状态 Analyze the status of the line patrol sensor
x1 = (track >> 3) & 0x01
x2 = (track >> 2) & 0x01
x3 = (track >> 1) & 0x01
x4 = track & 0x01
"""
X2 X1 X3 X4
| | | |
L1 L2 R1 R2
"""
lineL1 = x2
lineL2 = x1
lineR1 = x3
lineR2 = x4
# 0000
if not lineL1 and not lineL2 and not lineR1 and not lineR2:
rotate_right(speed)
time.sleep(1)
# 1X00
elif lineL1 and not lineR1 and not lineR2:
rotate_left(speed-10)
time.sleep(1)
# 00X1
elif not lineL1 and not lineL2 and lineR2:
rotate_right(speed-10)
time.sleep(1)
# 10X1
elif lineL1 and not lineL2 and lineR2:
rotate_right(speed-10)
time.sleep(1)
# 1X01
elif lineL1 and not lineR1 and lineR2:
rotate_right(speed-10)
time.sleep(1)
# 0110
elif not lineL1 and lineL2 and lineR1 and not lineR2:
rotate_right(speed-10)
time.sleep(1)
# 0111
elif not lineL1 and lineL2 and lineR1 and lineR2:
rotate_right(speed-20)
time.sleep(1)
# 1110
elif lineL1 and lineL2 and lineR1 and not lineR2:
rotate_left(speed-20)
time.sleep(1)
# 1111
elif lineL1 and lineL2 and lineR1 and lineR2:
move_forward(speed)
# 等待一段时间再进行下一次检测 Wait for a while before the next test
time.sleep(0.01)
except KeyboardInterrupt:
# 当用户中断程序时,确保所有电机停止 Ensure that all motors stop when the user interrupts the program
stop_robot()
print("Ending")
stop_robot()
del bot现在我的这个代码,只能实现红外巡线,然后超声波避障,遇见障碍物后,蜂鸣器报警,之后就停下来了。但是他无法实现避开障碍物继续行驶,现在我想要实现避开障碍物继续行驶,请你帮我修改代码,实现这个功能,给我修正后的完整代码!!!
你现在之所以“遇到障碍物报警后就停住不再走”,本质上是避障逻辑执行完没有回到巡线循环(或者避障里直接 stop/break 了)。下面我给你一份完整可用的“巡线 + 避障绕开后继续巡线”代码:遇到障碍物 → 停车蜂鸣 → 后退 → 左绕 → 前进通过 → 右回正 → 继续跑,并且加了“重新找线”的小搜索过程。
说明:你们这套 Yahboom 库里,超声波/蜂鸣器函数名可能有差异。我在代码里做了“自动尝试常见函数名”的兼容;如果你们的函数名不同,只需要改
get_ultrasonic_cm()或beep()里那一行即可(我也在注释里标了)。
pythonimport sys import time import os # 兼容两种常见 demo 路径(你之前路径经常会不一致) for p in ("/project_demo/lib", "/home/pi/project_demo/lib"): if os.path.isdir(p) and p not in sys.path: sys.path.append(p) # 导入麦克纳姆小车驱动库 from McLumk_Wheel_Sports import * # ===================== 可调参数(建议先用默认) ===================== SPEED_FWD = 25 # 正常巡线速度 SPEED_TURN = 25 # 转向速度 SPEED_SLOW = 18 # 慢速(找线/后退用) OBSTACLE_CM = 20 # 障碍物阈值:小于该距离触发避障(cm) BACK_TIME = 0.35 # 后退时长(秒) TURN_TIME = 0.42 # 原地转向时长(秒) PASS_TIME = 0.75 # 绕行直行时长(秒) BEEP_TIME = 0.15 # 蜂鸣时长(秒) # ================================================================ def _try_call(obj, names, *args): """尝试调用 obj 的多个可能方法名,成功就返回结果;都不行返回 None""" for n in names: fn = getattr(obj, n, None) if callable(fn): try: return fn(*args) except TypeError: # 有些函数签名不一样就略过 continue except Exception: continue return None def beep(duration=BEEP_TIME): """ 蜂鸣器:不同镜像/库函数名可能不同,这里尽量自动适配。 如果你们知道准确函数名,直接在这里改成一行最稳。 """ if "bot" not in globals(): return # 常见:on/off 风格 if _try_call(bot, ["Ctrl_Beep", "Ctrl_beep", "Ctrl_buzzer", "buzzer", "beep"], 1) is not None: time.sleep(duration) _try_call(bot, ["Ctrl_Beep", "Ctrl_beep", "Ctrl_buzzer", "buzzer", "beep"], 0) return # 常见:传毫秒 _try_call(bot, ["beep_ms", "Beep"], int(duration * 1000)) def get_ultrasonic_cm(): """ 读取超声波距离(cm)。 你们当前“能避障并报警”的那份代码里,肯定有一行获取距离的函数; 如果这里读不到(返回 None),把下面 _try_call(...) 里的名字替换成你们实际的那个即可。 """ if "bot" not in globals(): return None val = _try_call( bot, [ "get_ultrasonic_distance", "get_distance", "ultrasonic_distance", "Ultrasonic_read", "read_ultrasonic", "Ultrasonic_cm", "GetUltrasonicDistance", "get_ultrasonic" ] ) if val is None: return None try: dist = float(val) # 有的库返回 mm,这里做个粗略兼容 if dist > 300: dist = dist / 10.0 return dist except Exception: return None def read_line_bits(): """ 从I2C读取巡线传感器数据,并解析成 4 个探头状态 """ track_data = bot.read_data_array(0x0a, 1) track = int(track_data[0]) x1 = (track >> 3) & 0x01 x2 = (track >> 2) & 0x01 x3 = (track >> 1) & 0x01 x4 = track & 0x01 # 按你原代码映射: # X2 X1 X3 X4 -> L1 L2 R1 R2 lineL1 = x2 lineL2 = x1 lineR1 = x3 lineR2 = x4 return lineL1, lineL2, lineR1, lineR2 def follow_line_once(speed=SPEED_FWD): """ 单次巡线控制(不在这里写长 sleep,否则反应会很慢) """ lineL1, lineL2, lineR1, lineR2 = read_line_bits() # 0000:全丢线,原代码是右转找线 if not lineL1 and not lineL2 and not lineR1 and not lineR2: rotate_right(speed) # 1X00:偏左(按你原逻辑) elif lineL1 and not lineR1 and not lineR2: rotate_left(max(speed - 10, 10)) # 00X1:偏右 elif (not lineL1) and (not lineL2) and lineR2: rotate_right(max(speed - 10, 10)) # 10X1 / 1X01 / 0110 / 0111:你原逻辑都偏向右转纠正 elif (lineL1 and (not lineL2) and lineR2) or (lineL1 and (not lineR1) and lineR2) \ or ((not lineL1) and lineL2 and lineR1 and (not lineR2)) \ or ((not lineL1) and lineL2 and lineR1 and lineR2): rotate_right(max(speed - 15, 8)) # 1110:偏左纠正 elif lineL1 and lineL2 and lineR1 and (not lineR2): rotate_left(max(speed - 20, 8)) # 1111:正中,前进 elif lineL1 and lineL2 and lineR1 and lineR2: move_forward(speed) else: # 兜底:前进 move_forward(speed) def move_backward_safe(speed=SPEED_SLOW): """ 有的库叫 move_backward,有的叫 move_back,这里做兼容 """ if "move_backward" in globals(): move_backward(speed) elif "move_back" in globals(): move_back(speed) else: # 实在没有就停一下 stop_robot() def reacquire_line(timeout_s=4.0): """ 绕障后重新找线:慢速前进 + 轻微左右摆动,直到任一探头检测到线 """ t0 = time.time() i = 0 while time.time() - t0 < timeout_s: bits = read_line_bits() if any(bits): return True move_forward(SPEED_SLOW) time.sleep(0.05) # 每隔一小段做一下“摆动”帮助找线 i += 1 if i % 12 == 6: rotate_left(SPEED_SLOW) time.sleep(0.08) elif i % 12 == 0: rotate_right(SPEED_SLOW) time.sleep(0.08) return False def avoid_obstacle(): """ 避障动作:停车->蜂鸣->后退->左绕->前进->右回->前进->找线->继续巡线 """ stop_robot() beep() # 1) 后退离开障碍物 move_backward_safe(SPEED_SLOW) time.sleep(BACK_TIME) stop_robot() time.sleep(0.05) # 2) 左转绕开 rotate_left(SPEED_TURN) time.sleep(TURN_TIME) move_forward(SPEED_FWD) time.sleep(PASS_TIME) # 3) 右转回正 rotate_right(SPEED_TURN) time.sleep(TURN_TIME) move_forward(SPEED_FWD) time.sleep(PASS_TIME) stop_robot() time.sleep(0.05) # 4) 重新找线(找不到就继续慢慢找一会儿) reacquire_line(timeout_s=4.0) # ================================ 主循环 ================================ # 有些镜像需要先打开超声波测距功能;你之前截图里出现过 Ctrl_Ulratist_switch _try_call(bot, ["Ctrl_Ulratist_switch", "Ctrl_Ultrasound_switch", "Ultrasonic_switch"], 1) try: while True: dist = get_ultrasonic_cm() # 有距离值且小于阈值 -> 避障绕开,然后继续 while(继续巡线) if dist is not None and 0 < dist < OBSTACLE_CM: avoid_obstacle() continue # 正常巡线 follow_line_once(SPEED_FWD) time.sleep(0.01) except KeyboardInterrupt: print("Ending") finally: _try_call(bot, ["Ctrl_Ulratist_switch", "Ctrl_Ultrasound_switch", "Ultrasonic_switch"], 0) stop_robot() try: del bot except Exception: pass # =======================================================================
通常是这两个参数不合适(不同车体/地面差别很大):
OBSTACLE_CM:太大/太小都会影响行为(一般 15~25cm 调)TURN_TIME / PASS_TIME:绕行幅度不够会“绕不开”,过大又会偏离太远找不到线如果你愿意,把你们“超声波测距那一行代码(获取距离的那行)”贴出来,我可以把 get_ultrasonic_cm() 改成完全匹配你们镜像的写法,这样就不会因为函数名差异导致 dist 读不到。
import sys
import time
sys.path.append('/home/pi/project_demo/lib')
from McLumk_Wheel_Sports import *
speed = 25#25
try:
while True:
# 从I2C读取巡线传感器数据 Read line sensor data from I2C
track_data = bot.read_data_array(0x0a, 1)
track = int(track_data[0])
# 解析巡线传感器的状态 Analyze the status of the line patrol sensor
x1 = (track >> 3) & 0x01
x2 = (track >> 2) & 0x01
x3 = (track >> 1) & 0x01
x4 = track & 0x01
"""
X2 X1 X3 X4
| | | |
L1 L2 R1 R2
"""
lineL1 = x2
lineL2 = x1
lineR1 = x3
lineR2 = x4
# 0000
if not lineL1 and not lineL2 and not lineR1 and not lineR2:
rotate_right(speed)
time.sleep(1)
# 1X00
elif lineL1 and not lineR1 and not lineR2:
rotate_left(speed-10)
time.sleep(1)
# 00X1
elif not lineL1 and not lineL2 and lineR2:
rotate_right(speed-10)
time.sleep(1)
# 10X1
elif lineL1 and not lineL2 and lineR2:
rotate_right(speed-10)
time.sleep(1)
# 1X01
elif lineL1 and not lineR1 and lineR2:
rotate_right(speed-10)
time.sleep(1)
# 0110
elif not lineL1 and lineL2 and lineR1 and not lineR2:
rotate_right(speed-10)
time.sleep(1)
# 0111
elif not lineL1 and lineL2 and lineR1 and lineR2:
rotate_right(speed-20)
time.sleep(1)
# 1110
elif lineL1 and lineL2 and lineR1 and not lineR2:
rotate_left(speed-20)
time.sleep(1)
# 1111
elif lineL1 and lineL2 and lineR1 and lineR2:
move_forward(speed)
# 等待一段时间再进行下一次检测 Wait for a while before the next test
time.sleep(0.01)
except KeyboardInterrupt:
# 当用户中断程序时,确保所有电机停止 Ensure that all motors stop when the user interrupts the program
stop_robot()
print("Ending")
stop_robot()
del bot现在我的这个代码,只能实现红外巡线,然后超声波避障,遇见障碍物后,蜂鸣器报警,之后就停下来了。但是他无法实现避开障碍物继续行驶,现在我想要实现避开障碍物继续行驶,请你帮我修改代码,实现这个功能,给我修正后的完整代码!!!现在我的这个代码,只能实现红外巡线,然后超声波避障,遇见障碍物后,蜂鸣器报警,之后就停下来了。但是他无法实现避开障碍物继续行驶,现在我想要实现避开障碍物继续行驶,请你帮我修改代码,实现这个功能,给我修正后的完整代码!!!现在我的这个代码,只能实现红外巡线,然后超声波避障,遇见障碍物后,蜂鸣器报警,之后就停下来了。但是他无法实现避开障碍物继续行驶,现在我想要实现避开障碍物继续行驶,请你帮我修改代码,实现这个功能,给我修正后的完整代码!!!
下面给你一份“红外巡线 + 超声波检测到障碍物就绕开,然后自动回到巡线继续走”的完整代码(可直接替换你当前 Notebook 里的代码运行)。
它的逻辑是:
说明:Yahboom 不同镜像/库里,超声波距离和蜂鸣器的函数名可能不一样。代码里做了“自动尝试常见函数名”的兼容;如果你跑起来发现
dist一直是 None(或者蜂鸣器不响),只需要按注释把那一行换成你们库里真实函数名即可。
pythonimport sys import time import os # ====== 1) 路径兼容:你之前经常是 /project_demo,而不是 /home/pi/project_demo ====== for p in ("/project_demo/lib", "/home/pi/project_demo/lib"): if os.path.isdir(p) and p not in sys.path: sys.path.append(p) # 导入麦克纳姆小车驱动库 from McLumk_Wheel_Sports import * # ===================== 可调参数(先用默认,跑通后再微调) ===================== SPEED_FWD = 25 # 正常巡线速度 SPEED_TURN = 25 # 转向速度 SPEED_SLOW = 18 # 慢速(找线/后退用) OBSTACLE_CM = 20 # 障碍物阈值:小于该距离触发避障(cm) BACK_TIME = 0.35 # 后退时长(秒) TURN_TIME = 0.42 # 原地转向时长(秒) PASS_TIME = 0.75 # 绕行直行时长(秒) BEEP_TIME = 0.15 # 蜂鸣时长(秒) LOOP_DT = 0.01 # 主循环周期 # ============================================================================ def _try_call(obj, names, *args): """尝试调用 obj 的多个可能方法名,成功就返回结果;都不行返回 None""" for n in names: fn = getattr(obj, n, None) if callable(fn): try: return fn(*args) except Exception: pass return None def beep(duration=BEEP_TIME): """ 蜂鸣器:自动尝试常见函数名 如果你知道你们准确蜂鸣器接口,建议直接替换成那一行最稳。 """ if "bot" not in globals(): return # 常见开关风格:1/0 ok = _try_call(bot, ["Ctrl_Beep", "Ctrl_beep", "Ctrl_buzzer", "Ctrl_Buzzer", "buzzer", "beep"], 1) if ok is not None: time.sleep(duration) _try_call(bot, ["Ctrl_Beep", "Ctrl_beep", "Ctrl_buzzer", "Ctrl_Buzzer", "buzzer", "beep"], 0) return # 另一类:传毫秒 _try_call(bot, ["beep_ms", "Beep"], int(duration * 1000)) def get_ultrasonic_cm(): """ 读取超声波距离(cm) 若你们库里有明确函数名(例如 bot.Ultrasonic_read()), 把下面 names 列表里加上/改成那个即可。 """ if "bot" not in globals(): return None val = _try_call( bot, [ "get_ultrasonic_distance", "get_distance", "ultrasonic_distance", "Ultrasonic_read", "read_ultrasonic", "Ultrasonic_cm", "GetUltrasonicDistance", "get_ultrasonic" ] ) if val is None: return None try: dist = float(val) # 有的库返回 mm,这里做粗略兼容 if dist > 300: dist = dist / 10.0 return dist except Exception: return None def read_line_bits(): """从I2C读取巡线传感器数据,并解析 4 个探头状态""" track_data = bot.read_data_array(0x0a, 1) track = int(track_data[0]) x1 = (track >> 3) & 0x01 x2 = (track >> 2) & 0x01 x3 = (track >> 1) & 0x01 x4 = track & 0x01 # 你原始映射: # X2 X1 X3 X4 -> L1 L2 R1 R2 lineL1 = x2 lineL2 = x1 lineR1 = x3 lineR2 = x4 return lineL1, lineL2, lineR1, lineR2 def follow_line_step(speed=SPEED_FWD): """ 单次巡线控制(不要像你原来那样每次 sleep(1),否则反应会很慢) """ lineL1, lineL2, lineR1, lineR2 = read_line_bits() # 0000:丢线 -> 轻微右转找线 if not lineL1 and not lineL2 and not lineR1 and not lineR2: rotate_right(speed) # 1X00:偏左 -> 左转纠正 elif lineL1 and (not lineR1) and (not lineR2): rotate_left(max(speed - 10, 10)) # 00X1:偏右 -> 右转纠正 elif (not lineL1) and (not lineL2) and lineR2: rotate_right(max(speed - 10, 10)) # 10X1 / 1X01 / 0110 / 0111:按你原逻辑偏向右纠正 elif (lineL1 and (not lineL2) and lineR2) or (lineL1 and (not lineR1) and lineR2) \ or ((not lineL1) and lineL2 and lineR1 and (not lineR2)) \ or ((not lineL1) and lineL2 and lineR1 and lineR2): rotate_right(max(speed - 15, 8)) # 1110:偏左纠正 elif lineL1 and lineL2 and lineR1 and (not lineR2): rotate_left(max(speed - 20, 8)) # 1111:在线上 -> 前进 elif lineL1 and lineL2 and lineR1 and lineR2: move_forward(speed) else: move_forward(speed) def move_backward_safe(speed=SPEED_SLOW): """兼容不同库的后退函数名""" if "move_backward" in globals(): move_backward(speed) elif "move_back" in globals(): move_back(speed) else: stop_robot() def reacquire_line(timeout_s=4.0): """绕障后重新找线:慢速前进 + 左右摆动,直到任一探头检测到线""" t0 = time.time() i = 0 while time.time() - t0 < timeout_s: bits = read_line_bits() if any(bits): return True move_forward(SPEED_SLOW) time.sleep(0.05) i += 1 if i % 12 == 6: rotate_left(SPEED_SLOW) time.sleep(0.08) elif i % 12 == 0: rotate_right(SPEED_SLOW) time.sleep(0.08) return False def avoid_obstacle(): """ 避障动作(绕开后继续巡线): 停车->蜂鸣->后退->左绕->前进->右回正->前进->找线->继续 """ stop_robot() beep() # 1) 后退离开障碍物 move_backward_safe(SPEED_SLOW) time.sleep(BACK_TIME) stop_robot() time.sleep(0.05) # 2) 左转绕开 rotate_left(SPEED_TURN) time.sleep(TURN_TIME) move_forward(SPEED_FWD) time.sleep(PASS_TIME) # 3) 右转回正 rotate_right(SPEED_TURN) time.sleep(TURN_TIME) move_forward(SPEED_FWD) time.sleep(PASS_TIME) stop_robot() time.sleep(0.05) # 4) 重新找线(找不到也不会卡死,超时返回) reacquire_line(timeout_s=4.0) # ================================ 主循环 ================================ # 有些镜像需要先打开超声波测距功能(你之前截图里出现过 Ctrl_Ulratist_switch) _try_call(bot, ["Ctrl_Ulratist_switch", "Ctrl_Ultrasound_switch", "Ultrasonic_switch"], 1) try: while True: dist = get_ultrasonic_cm() # 检测到障碍物 -> 绕开后继续 while(继续巡线) if dist is not None and 0 < dist < OBSTACLE_CM: avoid_obstacle() continue # 正常巡线 follow_line_step(SPEED_FWD) time.sleep(LOOP_DT) except KeyboardInterrupt: print("Ending") finally: _try_call(bot, ["Ctrl_Ulratist_switch", "Ctrl_Ultrasound_switch", "Ultrasonic_switch"], 0) stop_robot() try: del bot except Exception: pass # =======================================================================
你只需要优先调这 3 个参数(很关键):
OBSTACLE_CM:一般 15~25cm 之间试(太大容易频繁触发;太小会撞上)TURN_TIME:绕不开就 增大(比如 0.42 → 0.50)PASS_TIME:绕过障碍需要更远就 增大(比如 0.75 → 1.00)另外,如果你发现 dist 一直是 None(避障从不触发),告诉我你们库里“读取超声波距离”的那一行到底叫什么(或把你们避障那段代码截图/贴出来),我就把 get_ultrasonic_cm() 精确改成你们那套镜像的函数名,保证触发。