microsoft / jacdac

Device and service catalogs for Jacdac.
https://aka.ms/jacdac
Creative Commons Attribution 4.0 International
66 stars 24 forks source link

Role manager (servo?) assignment behaviour is different when Makecode is/isn't connected #1335

Closed ross-inksmith closed 8 months ago

ross-inksmith commented 9 months ago

In the attached video (https://github.com/microsoft/jacdac/assets/88154489/bf2d7dc8-3e97-45f6-be6d-22576faf6d69), I've already downloaded the code (https://makecode.microbit.org/_JKyP30b9TY8a) to the microbit. With the computer disconnected I turn the breakout board on. Only the left servo turns (in firmware they're created in order 0:left 1:middle 2:right). Once I connect the computer/Makecode, the left and middle servos start turning. They will keep doing this even if I disconnect the computer again. If I start with the microbit connected to Makecode, then both servos will work on startup.

Additional detail

In the above build, using our wrapper extension I've included code to wait for roleManagerServer.isConnected() in the extension's main.ts before querying (in order) left-, middle-, and rightServo.getAngle() in an attempt to bias the roleManager's assignments. This seems to work in Makecode, but a disconnected microbit will assign "leftServo" to the first service, while the other two roles can be assigned in either order with no obvious pattern.

Our issue has a lot in common with #1293; we can control the servos using the dashboard controls and they move within their full range without delay, but only the first service will respond to the first block (e.g. servo1.run(x) will always work). Other services on the board only start repsonding after the second block (e.g. servo2.run(x) has no effect the first time, but subseuqent calls to servo2.anything work as normal)

There may be something in the physical init process that influences this; when the board is powered on any servo on the left pin (first one in firmware) moves to 0° while the others do not move. I can turn the servos easily so they're unpowered. Our board doesn't do any detection of servos, so sends signals based on pin regardless of what is plugged in.

Another demonstration is here (https://makecode.microbit.org/_e4UJXP23ER3j) using the MS jacdac extension. If I use the Add Simulators button, it will create three simulators and assign them like this: servo-assignment-sims Note that the simulators have a 0-180° range but alternate between servo1:0/45° and servo3:45/113° instead of servo1:90/135° and servo3:45/90° Using the same code and plugging in our breakout board (which has 270° servos), it will now lay itself like this: servo-assignment-fwd The same code now causes the servos to alternate between 0/90° and 90/180° instead of 67.5/135° and 135/202.5°

The above might be related to #1327? I've also found during testing that the starting ranges for our servos initially default to 0-180° before getting updated later.

tballmsft commented 9 months ago

Trying to understand. I made a simple example two jacdac buttons - the assignments stay the same when connected and disconnect: https://makecode.microbit.org/_hf6CaPE1Jf3r

pelikhan commented 9 months ago

try 3 buttons

Sent from Outlookhttp://aka.ms/weboutlook


From: Tom Ball @.> Sent: Wednesday, October 18, 2023 9:16 AM To: microsoft/jacdac @.> Cc: Assign @.>; Subscribed @.> Subject: Re: [microsoft/jacdac] Role manager (servo?) assignment behaviour is different when Makecode is/isn't connected (Issue #1335)

Trying to understand. I made a simple example two jacdac buttons - the assignments stay the same when connected and disconnect: https://makecode.microbit.org/_hf6CaPE1Jf3r

— Reply to this email directly, view it on GitHubhttps://github.com/microsoft/jacdac/issues/1335#issuecomment-1768881698 or unsubscribehttps://github.com/notifications/unsubscribe-auth/AA73QKJKND57QMYEO5CM2PDX776GJBFKMF2HI4TJMJ2XIZLTSSBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDUOJ2WLJDOMFWWLLTXMF2GG2C7MFRXI2LWNF2HTAVFOZQWY5LFUVUXG43VMWSG4YLNMWVXI2DSMVQWIX3UPFYGLAVFOZQWY5LFVIZDCMBXG4YDMNJWGOSG4YLNMWUWQYLTL5WGCYTFNSWHG5LCNJSWG5C7OR4XAZNMJFZXG5LFINXW23LFNZ2KM5DPOBUWG44TQKSHI6LQMWVHEZLQN5ZWS5DPOJ42K5TBNR2WLKJSGY4TCMJQGMYTJAVEOR4XAZNFNFZXG5LFUV3GC3DVMWVDCOJUGU3TONJXGE2IFJDUPFYGLJLMMFRGK3FFOZQWY5LFVIZDCMBXG4YDMNJWGOTXI4TJM5TWK4VGMNZGKYLUMU. You are receiving this email because you were assigned.

Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

tballmsft commented 9 months ago

There seems to be another issue addressed above:

Another demonstration is here (https://makecode.microbit.org/_e4UJXP23ER3j) using the MS jacdac extension. If I use the Add Simulators button, it will create three simulators and assign them like this: The same code now causes the servos to alternate between 0/90° and 90/180° instead of 67.5/135° and 135/202.5°

The above might be related to https://github.com/microsoft/jacdac/issues/1327? I've also found during testing that the starting ranges for our servos initially default to 0-180° before getting updated later.

tballmsft commented 9 months ago

Three buttons seems to work as well: https://makecode.microbit.org/_DYD4RA6rpCK0

ross-inksmith commented 9 months ago

The assignment issue does seem to be unique to the servos. I haven't seen it so far with our reflected light/line follower board which also has 3 otherwise identical services on them.

Attached is a packet trace demonstrating the issue similar to #1293, where only one servo responds at first; only one packet is actually sent.

trace

tballmsft commented 9 months ago

Yes, I am looking now into program you gave above: https://makecode.microbit.org/_e4UJXP23ER3j

tballmsft commented 9 months ago

@ross-inksmith, you said:

There may be something in the physical init process that influences this; when the board is powered on any servo on the left pin (first one in firmware) moves to 0° while the others do not move. I can turn the servos easily so they're unpowered. Our board doesn't do any detection of servos, so sends signals based on pin regardless of what is plugged in.

Right. I forgot that the servos are connected via jacdac cables which PWM is being sent over. Where is the code that manages initialization? This must be special-purpose for your board, correct?

pelikhan commented 9 months ago

so the difference is that you have 3 servos on the same devices; rather than 3 individual devices with 1 servo service.

ross-inksmith commented 9 months ago

@ross-inksmith, you said:

There may be something in the physical init process that influences this; when the board is powered on any servo on the left pin (first one in firmware) moves to 0° while the others do not move. I can turn the servos easily so they're unpowered. Our board doesn't do any detection of servos, so sends signals based on pin regardless of what is plugged in.

Right. I forgot that the servos are connected via jacdac cables which PWM is being sent over. Where is the code that manages initialization? This must be special-purpose for your board, correct?

Not quite. Similar to the kittenbot device in #1293, we have one jacdac connection to a device with multiple servo services on it. Instead of having it as a separate board, it's on the same board as the edge connector/microbit. If you were to swap the connector to a standard 3 pin connector, it would work identically

pelikhan commented 9 months ago

can you share a packet trace? (link in the jacdac-docs footer)

ross-inksmith commented 9 months ago

trace

it's the same code as here (https://makecode.microbit.org/_e4UJXP23ER3j), except that I moved the code from forever to input.onButtonPressed so I could record the trace

pelikhan commented 9 months ago

looks like makecode wants to have 0-180 at start

image

tballmsft commented 9 months ago

@ross-inksmith, you said:

Not quite. Similar to the kittenbot device in https://github.com/microsoft/jacdac/issues/1293, we have one jacdac connection to a device with multiple servo services on it.

I understand. Where is the firmware for that device?

But just to be clear, your hypothesis is that this is something in the Jacdac stack above the firmware, due to the similar problem Kittenbot has?

tballmsft commented 9 months ago

@pelikhan - so you think that the makecode defaults for the servo could be leading to the problem?

ross-inksmith commented 9 months ago

@pelikhan - so you think that the makecode defaults for the servo could be leading to the problem?

https://github.com/ross-inksmith/pxt-jacdac/commit/cde16a82eac6182e1e2c45471d0e7ecebf613bc6 https://makecode.microbit.org/_1i0EJDXobWj2 Doesn't seem to have changed it

{
    "name": "remove defaults",
    "description": "",
    "dependencies": {
        "core": "*",
        "radio": "*",
        "microphone": "*",
        "jacdac": "github:microsoft/pxt-jacdac",
        "jacdac-servo": "github:ross-inksmith/pxt-jacdac/servo#cde16a82eac6182e1e2c45471d0e7ecebf613bc6"
    },
    "files": [
        "main.blocks",
        "main.ts",
        "README.md"
    ],
    "preferredEditor": "tsprj"
}
ross-inksmith commented 9 months ago

@ross-inksmith, you said:

Not quite. Similar to the kittenbot device in https://github.com/microsoft/jacdac/issues/1293, we have one jacdac connection to a device with multiple servo services on it.

I understand. Where is the firmware for that device?

https://github.com/Forward-Education/firmware/tree/main/BreakoutBoard270

tballmsft commented 9 months ago

Ok. in jacdac-c servo.c, init() is

SRV_DEF(servo, JD_SERVICE_CLASS_SERVO);
void servo_init(const servo_params_t *params) {
    SRV_ALLOC(servo);
    state->params = *params;
    state->params0 = params;
}

So nothing happens on init to set the servo to an initial position/state?

tballmsft commented 9 months ago

@ross-inksmith - I see that servo_0 has a different power pin than the other two servos. Correct?

const servo_params_t servo_0 = {
    .pin = PA_6,
    .fixed = 0,
    .min_angle = 0 << 16,
    .min_pulse = 600,
    .max_angle = 270 << 16,
    .max_pulse = 2500,
    .power_pin = PB_7
};

const servo_params_t servo_1 = {
    .pin = PA_7,
    .fixed = 0,
    .min_angle = 0 << 16,
    .min_pulse = 600,
    .max_angle = 270 << 16,
    .max_pulse = 2500,
    .power_pin = PC_15
};

const servo_params_t servo_2 = {
    .pin = PA_4,
    .fixed = 0,
    .min_angle = 0 << 16,
    .min_pulse = 600,
    .max_angle = 270 << 16,
    .max_pulse = 2500,
    .power_pin = PC_15
    //NO_PIN
};  
ross-inksmith commented 9 months ago

@brian-inksmith is double checking the schematics, but the pins are fed from the same rail. (I asked a similar question)

tballmsft commented 9 months ago

OK. So buttons and light sensors are input modules that generate events, so let me try with something that generates output instead.

tballmsft commented 9 months ago

OK. I think I have a program with 3 dot matrixes (for which I have modules too): https://makecode.microbit.org/_a2vhjoLqxbEW

ross-inksmith commented 9 months ago

https://github.com/microsoft/pxt-jacdac/blob/master/servo-server/server.microbit.ts#L13 For the min/max issues, it's also defined here for the servos. It doesn't explain how the math in servo.run() comes up with 0/90 and 90/180 though

tballmsft commented 9 months ago

Oops spoke too soon... it's working when plugged in, and when I unplug and put on battery power. So this seems to be specific to servos.

pelikhan commented 9 months ago

The issue is that the servo clients has partially received the ranges from the servo services; and then applies the computation for converting the speed into an angle. Since the current default in the client is -90, 90, you could end up with a combination of [-90,0] x [90, 180]. image

https://github.com/microsoft/pxt-jacdac/blob/d8afba90caba7f5f0c5c0306a3ee1849083de814/servo/client.ts#L119

pelikhan commented 9 months ago

and in restrospect, .... 0 || 90 -> 90 so that explains it.

pelikhan commented 9 months ago

https://github.com/microsoft/pxt-jacdac/pull/101

ramseyball commented 9 months ago

So the problem is initialization between service and client!

ross-inksmith commented 9 months ago

and in restrospect, .... 0 || 90 -> 90 so that explains it.

Oh that's funny. For the majority of development we were using -90/90 PXL_20231018_191956597

pelikhan commented 9 months ago

silly silly me.

pelikhan commented 9 months ago

Servo range fix deployed. Please test.

ramseyball commented 9 months ago

Thanks, Peli!

ross-inksmith commented 9 months ago

Servo range fix deployed. Please test.

neutral swing

Also works if I detach the board and add simulators instead :+1:

pelikhan commented 9 months ago

I don't think this solves the role manager issue. @ross-inksmith ?

ross-inksmith commented 9 months ago

While the angle now reports as accurate, still having issues getting multiple servos to respond. Attached is the video of the exact same code above running without makecode connected. Only servo1 responds. On the first click it goes to it's end range. On the second and subsequent clicks it moves in its normal range. servo3 does not move

https://github.com/microsoft/jacdac/assets/88154489/1475a350-2507-4c9b-9930-77cb273c3a00

ross-inksmith commented 9 months ago

Longer video now, behaviour with makecode attached is different. tl;dw: With makecode attached, servo3 will eventually start responding

https://github.com/microsoft/jacdac/assets/88154489/8f018c26-109f-41d7-8bb2-9d4c4d4a3b3a

ross-inksmith commented 9 months ago

without-sims.jd.txt

I recorded this trace without going to the dashboard, so there were no simulated devices. It behaved as the first video with makecode disconnected. When I opened the dashboard to record a second trace it worked as with makecode connected but only recorded 18 packets :thinking:

tballmsft commented 9 months ago

OK. This also seems specific to servo.

tballmsft commented 9 months ago

In the past, I have seen this sort of behavior where the hardware works differently when the Jacdac device is connected through WebUSB to the dashboard....

tballmsft commented 9 months ago

@ross-inksmith you said:

When I opened the dashboard to record a second trace it worked as with makecode connected but only recorded 18 packets 🤔

Did the program work correctly or not when connected to the dashboard? I'm not sure how to interpret the above comment.

tballmsft commented 9 months ago

In the last trace you gave, all the servo messages are tagged with "(usb)":

9222.700   b75b1803dc445b97ac759af1133e00e800000000000000000391fc1200736572766f31ff
[ack:0x5bb7] to SB67/PIPE: port:464 cnt:0; sz=19; CMD 0xe800 {     _:
00000000000000000391fc1200736572766f31 | .............servo1 } (usb)
ross-inksmith commented 9 months ago

Yeah I realized that would be a bit hard to follow so I did it again here's the trace.jd.txt

and here's a full video https://github.com/microsoft/jacdac/assets/88154489/5beceef8-bd41-44c3-be64-8a5aa91a2cf6

tballmsft commented 9 months ago

@pelikhan - Is it possible to see the log messages that pxt-jacdac sends to the console? That might help more than the Jacdac trace.

pelikhan commented 9 months ago

You can turn on the "passive" mode in the jacdac-docs so that the browser does not emit any packets; and you should have the same behavior as without being connected.

image

tballmsft commented 9 months ago

Ah, very good

tballmsft commented 9 months ago

I'm not sure this is a role manager problem - seems like the three servos get recognized

device: 
  id: TQ01 (0x54cf1386c74a3cdd)
  product: TQ01 (0x3412171b)
  firmware_version: v0.20.3-16-g7e9e119-20230726-1434
  uptime: 72652.17000000224
  stats: announce 103, drop 0, restart 0
  services:
    servo (0x12fc9103)
        const instance_name: "Left" (4c656674) 
            last data: 33726, last get: 33726, last set: , last gets attempts: 0,
        rw angle: 135° (00008700) 
            last data: 80616, last get: 80616, last set: , last gets attempts: 0,
        rw enabled: true (01) 
            last data: 84317, last get: 84317, last set: , last gets attempts: 0,
        rw offset: 0° (00000000) 
            last data: 84322, last get: 84322, last set: , last gets attempts: 0,
        const min_angle: 0° (00000000) 
            last data: 40191, last get: 40191, last set: , last gets attempts: 0,
        const max_angle: 270° (00000e01) 
            last data: 40195, last get: 40195, last set: , last gets attempts: 0,
    servo (0x12fc9103)
        const instance_name: "Middle" (4d6964646c65) 
            last data: 33729, last get: 33729, last set: , last gets attempts: 0,
        rw angle: 0° (00000000) 
            last data: 84571, last get: 84571, last set: , last gets attempts: 0,
        rw enabled: false (00) 
            last data: 84365, last get: 84365, last set: , last gets attempts: 0,
        rw offset: 0° (00000000) 
            last data: 84370, last get: 84370, last set: , last gets attempts: 0,
        const min_angle: 0° (00000000) 
            last data: 34061, last get: 34061, last set: , last gets attempts: 0,
        const max_angle: 270° (00000e01) 
            last data: 34067, last get: 34067, last set: , last gets attempts: 0,
    servo (0x12fc9103)
        const instance_name: "Right" (5269676874) 
            last data: 33740, last get: 33740, last set: , last gets attempts: 0,
        rw angle: 135° (00008700) 
            last data: 80622, last get: 80622, last set: , last gets attempts: 0,
        rw enabled: true (01) 
            last data: 82413, last get: 82413, last set: , last gets attempts: 0,
        rw offset: 0° (00000000) 
            last data: 84414, last get: 84414, last set: , last gets attempts: 0,
        const min_angle: 0° (00000000) 
            last data: 40204, last get: 40204, last set: , last gets attempts: 0,
        const max_angle: 270° (00000e01) 
            last data: 40212, last get: 40212, last set: , last gets attempts: 0,
    relay (0x183fe656)
        const instance_name: "Pump" (50756d70) 
            last data: 33751, last get: 33751, last set: , last gets attempts: 0,
        rw active: false (00) 
            last data: 84264, last get: 84264, last set: , last gets attempts: 0,
tballmsft commented 9 months ago

My current hypothesis is that we are seeing packet loss. I see something similar here: https://github.com/microsoft/jacdac/issues/1336

tballmsft commented 9 months ago

@ross-inksmith - what chip is driving the servos? Is that an STM?

brian-forwardedu commented 9 months ago

@tballmsft Yes, specifically it's STM32G030F6P6TR

tballmsft commented 9 months ago

Right, just figured that out:

MCU = STM32g030x6 include $(PLATFORM)/mk/stm32g0.mk

tballmsft commented 9 months ago

From what I see in the trace, the packets GET/SET of angle for both servos1 and servo3 always happen together

See TQ01(1) and TQ01/(3) below

12442.900  0896040154cf1386c74a3cdd00011011                               to TQ01/(1): GET[minvalue]; sz=0; GET 0x110 (usb)
12447.100  39a5040154cf1386c74a3cdd00011111                               to TQ01/(1): GET[maxvalue]; sz=0; GET 0x111 (usb)
12450.400  ff53080154cf1386c74a3cdd0101012001ffffff                       to TQ01/(1): SET[intensity]; sz=1; SET 0x1: 01 | . (usb)
12454.900  bcb3080154cf1386c74a3cdd040102200080ca00                       to TQ01/(1): SET[value]; sz=4; SET 0x2: 0080ca00 | .... (usb)
12457.800  87e50c0154cf1386c74a3cdd06010920636f6e743d31ffff               to TQ01/(1): SET[clientvariant]; sz=6; SET 0x9: 636f6e743d31 | cont=1 (usb)
12460.600  68f8040154cf1386c74a3cdd00031011                               to TQ01/(3): GET[minvalue]; sz=0; GET 0x110 (usb)
12464.800  59cb040154cf1386c74a3cdd00031111                               to TQ01/(3): GET[maxvalue]; sz=0; GET 0x111 (usb)
12468.300  1c33080154cf1386c74a3cdd0103012001ffffff                       to TQ01/(3): SET[intensity]; sz=1; SET 0x1: 01 | . (usb)
12472.600  5f72080154cf1386c74a3cdd0403022000804300                       to TQ01/(3): SET[value]; sz=4; SET 0x2: 00804300 | ..C. (usb)
12475.600  34450c0154cf1386c74a3cdd06030920636f6e743d31ffff               to TQ01/(3): SET[clientvariant]; sz=6; SET 0x9: 636f6e743d31 | cont=1 (usb)